Spark Streaming: 保存上一个批次数据的计算结果

在Spark Streaming计算模型下,有时候我们对当前 batch 数据的计算需要依赖上一个 batch 的计算结果,如广告系统中检索日志和曝光时间的join拼接。这时可以使用JavaStreamingContext#remember()方法完成。该方法需要一个时间参数,用来指定要”记住”多久时间内的 RDD 数据。但是悲剧的是,文档对被”记住”的数据在哪里、如何引用这些数据却没有任何说明,这就导致了使用上的困难。

首先,时间参数的设置是由数据批次的时间间隔决定的。比如,batch interval 为10s, 那么如果你想在这次计算中引用到上次计算中的RDD, 那就必须至少将时间参数设置为 > 10s, 否则还没到下次处理时RDD就过期被GC了。其次,你要自己缓存RDD, spark并没有提供任何访问前批次RDD的方法。缓存的方法,定义一个本地RDD变量lastRdd,用来保存上个批次你想要保存的计算结果。 但这时候要注意,你的似于 new SparkConf(), new JavaStreamingContext()这样的代码是在 driver 节点中执行的,而实际数据处理逻辑是在 executor 所在节点执行的,并不在同一个进程中。所以如果直接定义一个本地RDD变量来引用你的批次数据结果时,那么只有你的 driver 节点中的 executor 进程才有这个引用,数据处理逻代码里中获取不到的。其实,我们可以在transform()方法中安全的引用到本地缓存RDD的引用变量,因为transform()永远在 driver 节点执行。因此,只要在该方法中,将当前正在处理的RDD引用直接赋值给lastRdd,这样在执行下一个批次的任务时,lastRdd就指向了上一个批次中你想保存的RDD结果了。代码大致如下:

JavaStreamingContext ctx = new JavaStreamingContext(conf, Durations.seconds(10));

 // 记住20s
ctx.remember(Durations.seconds(20));
// 用于保存上次RDD对象的引用
final JavaPairRDD[] lastRdd = new JavaPairRDD[1];


JavaXXXDStream exposePairStream = exposeStream
                .map( ... ... )
                .filter( ... ... )
                .mapToPair(... ...)
                .reduceByKey(... ...)
                .transformToPair(new Function, JavaPairRDD>() {
                    @Override
                    public JavaPairRDD call(JavaPairRDD stringExposeLogJavaPairRDD) throws Exception {
                        if (null == lastRdd[0]) { // 表示当前是第一个批次的数据, 还没有上个批次
                            lastRdd[0] = stringExposeLogJavaPairRDD; // 将当前批次的rdd保存到引用变量中
                            return stringExposeLogJavaPairRDD;
                        }

                        // 做一些业务逻辑上的处理
                        stringExposeLogJavaPairRDD = stringExposeLogJavaPairRDD.subtractByKey(lastRdd[0]);
                        // 将当前批次的rdd保存到引用变量中
                        lastRdd[0] = stringExposeLogJavaPairRDD;

                        return stringExposeLogJavaPairRDD;
                    }
                });

你可能感兴趣的:(spark)