Spark 1.5.1 + Java 1.8
我们正在使用spark将可靠的记录上传到数据库。
Action代码如下所示:
rdd.foreachPartition(new VoidFunction<Iterator<T>>() {
@Override
public void call(Iterator<T> iter) {
//while there are more records perform the following every 1000 records
//int[] recoords = statement.executeBatch();
//accumulator.add(recoords.length);
}
// ...
}
在驱动程序节点上有一个监视累加器值的线程。但是值不会更新。在应用程序结束时,它只会更新一次。即使累加器使用了惰性值设置,也应该正确更新,因为我在驱动程序节点线程中定期读取值。
我是否错误地使用了累加器?无论如何,我可以更持续地监控工人的进步吗?
答案 0 :(得分:3)
您可以监控累加器值但不能连续完成,即在任务完成后更新发生。
虽然累加器被称为共享变量,但实际上并没有共享。每个任务都有自己的累加器,在任务完成后合并。这意味着在任务运行时无法更新全局值。
为了能够看到更新,执行程序的数量必须小于已处理分区的数量(对应于任务的数量)。这样做的原因是当累加器更新发送给驱动程序时引入“障碍”。
例如:
import org.apache.spark.{SparkConf, SparkContext}
object App {
def main(args: Array[String]) {
val conf = new SparkConf().setMaster("local[4]")
val sc = new SparkContext(conf)
val accum = sc.accumulator(0, "An Accumulator")
val rdd = sc.parallelize(1 to 1000, 20)
import scala.concurrent.duration._
import scala.language.postfixOps
import rx.lang.scala._
val o = Observable.interval(1000 millis).take(1000)
val s = o.subscribe(_ => println(accum.value))
rdd.foreach(x => {
Thread.sleep(x + 200)
accum += 1
})
s.unsubscribe
sc.stop
}
}
正如您所看到的,每个任务仅更新一次全局值。
如果您按照提供的示例创建命名累加器,您也可以使用Spark UI监视它的状态。只需打开Stages选项卡,导航到特定阶段并检查累加器部分。
无论如何,我可以更持续地监察员工的进度吗?
最可靠的方法是通过添加更多分区来增加粒度,但它并不便宜。