最近使用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);
}
});
});
你會發現達到了自己的目的;