最近使用sparkstreaming是有个场景需要统计入mysql的数据量,因此考虑使用累加器;按照官网使用
如下方式:
JavaStreamingContext jssc = new JavaStreamingContext (conf, Durations.seconds(3));
LongAccumulator BroadbandArrearsAll = jssc.sparkContext().sc().longAccumulator("BroadbandArrearsAll");
然后在处理逻辑中调用累加器
directStream.foreachRDD(rdd-> {
//处理逻辑...
//其他逻辑
phoneData.foreachPartition(partitions->{
if(满足条件统计){
处理逻辑
broadbandArrears.add(1L);
}
})
})
把任务提交到集群发现broadbandArrears.add(1L);报空指针错误。累加器实例在task中没实例化;官网例子就是最外面实例的累加器???
之后使用下面方式实例化累加器
directStream.foreachRDD(rdd-> {
LongAccumulator broadbandArrears = rdd.context().longAccumulator("BroadbandArrears");
//获取kafka的 offset
OffsetRange[] offsetRanges = ((HasOffsetRanges) rdd.rdd()).offsetRanges();
//处理逻辑....
phoneData.foreachPartition(partitions->{
if(满足条件){
处理逻辑
broadbandArrears .add(1L);
}
});
});
提交任务后发现没有问题,但是累加器累加的是一个task的计数,也就是流计算定义的一个Dstream中的数据
查阅资料后发现,应该使用单例模式,就是整个流任务定义一个累加器实例;代码如下
class BroadbandArrears {
private volatile static LongAccumulator instance = null;
public static LongAccumulator getInstance(SparkContext sc) {
if (instance == null) { //如果累加器不存在则创建
synchronized(BroadbandArrears.class) {
if (instance == null) {
instance = sc.longAccumulator("BroadbandArrears"); //用以记录被删除的词
}
}
}
return instance;
}
}
directStream.foreachRDD(rdd-> {
LongAccumulator instance = BroadbandArrears.getInstance(rdd.context());
//获取kafka的 offset
OffsetRange[] offsetRanges = ((HasOffsetRanges) rdd.rdd()).offsetRanges();
//处理逻辑....
phoneData.foreachPartition(partitions->{
if(满足条件){
处理逻辑
instance.add(1L);
}
});
});
你会发现达到了自己的目的;