本节我们会介绍一种在tasks之间共享可读写变量的方式,就是累加器变量。
累加器变量
累加器变量是在tasks之间可以进行读写的变量,所有tasks可共享。累加器变量有以下两个特点:
- 写操作:只允许进行增加,比如var += delta,或者是用户自定义的满足交换律和结合律的其他函数。这样可以简化Spark累加器变量的同步实现成本,使得同步过程更加高效。
- 读操作:只允许在Driver中读取,不能在task中读取到累加器变量。
实现原理
每个Executor各自可以在累加器变量中增加delta值,Executor把delta值发送给Driver,Driver将所有的delta值加在一起。以下图为例,定义了一个累加器变量VALID,初始值为0。Executor1增加42,Driver接收到之后,VALID的值为42。Executor2增加8,VALID的值为50。Executor3增加10,VALID的值为60。在Driver中读取该变量时,得到的结果为60。
准确性保证
累加器变量对于Action类型的算子,和Transformations类型的算子,准确性的保证是不同的。
- Action:由于Action只会在执行成功后,Spark保证不会重复执行,因此在Action中修改累加器变量,可以保证只执行一次。
- Transformation:Spark不会保证已经成功执行的Transformation过程不会重复执行,可能会出现执行失败、内存不足或者等情况,因此累加器变量的修改可能会发生多次。
应用场景
下面我们列举一些累加器变量的应用场景:
- 性能统计:统计处理过的日志总数,执行总时间,错误数等等;
- 控制计算流:
- 条件判断:统计错误日志数,超过设定的阈值后停止计算;
- 循环判断:统计一些迭代算法的指标,判断是否需要停止迭代。
- 系统监控:输出监控Spark运行状态的一些指标;
- 性能评估和调试。
要尽可能的控制使用累加器变量的场景,对于一些统计类数据,比如UV,是不适合使用累加器变量来计算的。
小结
本节我们介绍了累加器变量的概念,特性和应用场景。它是可读写的变量,在executors中进行修改,在driver中读取。对于一些需要进行全局简单统计的场景可以使用。