为什么工作节点没有在其他工作节点上看到累加器的更新?

时间:2017-05-04 09:48:14

标签: java apache-spark

我在地图操作中使用LongAccumulator作为共享计数器。但似乎我没有正确使用它,因为工作节点上的计数器状态未更新。这是我的计数器类的样子:

public class Counter implements Serializable {

   private LongAccumulator counter;

   public Long increment() {
      log.info("Incrementing counter with id: " + counter.id() + " on thread: " + Thread.currentThread().getName());
      counter.add(1);
      Long value = counter.value();
      log.info("Counter's value with id: " + counter.id() + " is: " + value + " on thread: " + Thread.currentThread().getName());
      return value;
   }

   public Counter(JavaSparkContext javaSparkContext) {
      counter = javaSparkContext.sc().longAccumulator();
   }
}

据我所知,当应用程序在多个工作节点中运行时,这应该可以正常工作:

  

累加器是仅通过关联和可交换操作“添加”的变量,因此可以并行有效地支持。它们可用于实现计数器(如MapReduce)或总和。 Spark本身支持数值类型的累加器,程序员可以添加对新类型的支持。

但是,当计数器在2个不同的工作程序上递增并且看起来节点之间没有共享状态时,这是结果:

  

INFO计数器:在线程上使用id:866递增计数器:执行程序任务启动worker-6   INFO计数器:ID为866的计数器值为:线程为1:执行任务启动worker-6
  INFO计数器:在线程上使用id:866递增计数器:执行程序任务启动worker-0   INFO计数器:计数器的值id:866是:1线程:执行任务启动worker-0

我是否理解累加器概念错误或者是否有必须开始执行任务的设置?

2 个答案:

答案 0 :(得分:3)

shouldn't work

  

然后,使用add方法可以在群集上运行任务。但是,他们无法读懂它的价值。只有驱动程序可以使用其值方法读取累加器的值。

每个任务都有自己的累加器,在本地更新,并与"共享"在任务完成并报告结果后复制驱动程序。

旧的Accumulator API(现在包装AccumulatorV2)在任务中使用value时实际上抛出了异常,但由于某种原因,它在AccumulatorV2中被省略了

您所体验的内容实际上类似于此处所述的旧行为How to print accumulator variable from within task (seem to "work" without calling value method)?

答案 1 :(得分:0)

来自the answer from @user6910411(强调我的):

  

每个任务都有自己的累加器,在本地更新,并且在驱动程序上与“共享”副本合并,一旦任务完成并且报告结果

粗体答案的那部分并非100%正确。

内部和外部累加器的当前值将被发送给驱动程序,每个执行程序心跳必须定期发生,或者驱动程序假定执行程序丢失。

常规间隔由spark.executor.heartbeatInterval属性控制,默认为10s

  

每个执行者的心跳与驾驶员之间的间隔。 Heartbeats让驱动程序知道执行程序仍处于活动状态,并使用正在进行的任务的指标对其进行更新。 spark.executor.heartbeatInterval应显着低于spark.network.timeout

如上所述,心跳是“传输层”,用于将累加器(在执行程序上)的部分更新传递给驱动程序。

有两种累加器 - 内部和非内部(因为缺少更合适的名称,我将称之为非内部的非内部累加器)。

内部累加器用于Spark使用的任务指标,让管理员/操作员知道幕后发生的事情。

Spark使用相同的机制向非内部累加器发送部分更新,因此对每个执行程序心跳的驱动程序都可以看到累加器的本地更新(在执行任务的执行程序上)。

我不确定,但驱动程序可能不会将它们提供给代码(=外部世界),但重点是要知道驱动程序知道累加器的当前值(由执行程序延迟)心跳)。

BTW,问题是工作节点是累加器更新的边界,但实际上这只是一个任务,它为累加器更新创建了可见性边界。如果您有一个或两个工作节点(带有一个或多个执行程序)并不重要,因为您也不会在单个执行程序的任务中看到累加器更新。

累加器更新是任务的本地更新,它由驱动程序自行决定,并且可以通知任何有关累加器更新的任务。