目录:
6、Spark编程进阶
6.1、累加器
通常在向Spark传递函数时,比如使用map()函数或者用filter()传条件时,可以使用驱动器程序定义的变量,但是集群中运行的每个任务都会得到这些变量的一位新的副本。更新这些副本的值不会影响驱动器中的对应变量。spark的两个共享变量:累加器和广播变量,分别为结果与广播这两种常见的通信模式突破了这一限制。
第一种共享变量,即累加器,提供了将工作节点中的值聚合到驱动器程序中的简单语法。累加器的一个常见用途是在调试时对作业执行过程中的事件进行计数。例如,假设我们在从文件中读取呼号列表对应的日志,同时也想知道输入文件中有多少空行
1、Spark内置的提供了Long和Double类型的累加器。
LongAccumulator longAccumulator = jsc.sc().longAccumulator();
DoubleAccumulator doubleAccumulator = jsc.sc().doubleAccumulator();
2、主要方法介绍
add方法:赋值操作
value方法:获取累加器中的值
merge方法:该方法特别重要,一定要写对,这个方法是各个task的累加器进行合并的方法。
iszero方法:判断是否为初始值
reset方法:重置累加器中的值
copy方法:拷贝累加器
3、使用累加器需要注意的点
a、只有在行动操作中才会触发累加器,也就是说如:flatMap()转换操作因为Spark惰性特征所以只用当执行行动操作(如:count等)时累加器才会被触发;累加器只有在驱动程序中才可访问,worker节点中的任务不可访问累加器中的值.
b、使用Accumulator时,为了保证准确性,只使用一次action操作。如果需要使用多次则使用cache或persist操作切断依赖
简单实用demo
LongAccumulator accum = jsc.sc().longAccumulator();
sc.parallelize(Arrays.asList(1, 2, 3, 4)).foreach(x -> accum.add(x));
accum.value();// returns 10
6.2、广播变量
Spark提供的广播变量可以解决闭包函数引用外部大变量引起的性能问题;广播变量将只读变量缓存在每个worker节点中,Spark使用了高效广播算法分发变量从而提高通信性能;如直接在闭包函数中使用外部 变量该变量会缓存在每个任务(jobTask)中如果多个任务同时使用了一个大变量势必会影响到程序性能;广播变量:每个worker节点中缓存一个副本,通过高效广播算法提高传输效率,广播变量是只读的;Spark Scala Api与Java Api默认使用了Jdk自带序列化库,通过使用第三方或使用自定义的序列化库还可以进一步提高广播变量的性能。看个demo
广播变量的优势:是因为不是每个task一份变量副本,而是变成每个节点的executor才一份副本。这样的话,就可以让变量产生的副本大大减少。
简单解释就是:上面demo定义了一个sexMapBC的广播变量,这个变量每台work上只存一份,然后该work上的所有task共享这个变量。
左边没有采用广播变量,右边采用了广播变量。 左每个task都有一个副本,右边只有worker上一个副本。
网上的一个例子:
50个Executor 1000个task。
默认情况下,1000个task 1000个副本
1000 * 10M = 10 000M = 10 G
10G的数据,网络传输,在集群中,耗费10G的内存资源。
如果使用 广播变量:
50个Executor ,50个副本,10M*50 = 500M的数据。
网络传输,而且不一定是从Dirver传输到各个节点,还可能是从就近的节点 的Executor的BlockManager上获取变量副本,网络传输速度大大增加。之前 10000M 现在 500M。20倍网络传输性能的消耗。20倍内存消耗的减少。
虽然说,不一定会对性能产生决定向性的作用。比如运行30分钟的spark作业,可能做了广播变量以后,速度快了2分钟。变成28分钟。
注意一点:广播变量创建后,它可以运行在集群中的任何Executor上,而不需要多次传递给集群节点。另外需要记住,不应该修改广播变量,这样才能确保每个节点获取到的值都是一致的。
6.3、基于分区进行操作
后续。
6.4、与外部程序间的管道
后续。
6.5、数值RDD的操作
后续。