spark中非常难以理解的概念,就是在集群分布式并行运行时操作算子外部的变量生命周期
所谓RDD算子中,操作作用域外部的变量,指的是,类似下面的语句:val a = 0 ; rdd.foreach(i -> a +=1)
此时,对rdd执行foreach算子的作用阈,其实仅仅是它内部代码,但是这里却操作了作用阈外部的变量a,这种现象就是闭包
闭包简单来说,就是i操作一个不属于一个作用域范围的变量
如果使用local模式运行spark作业,那么实际只有一个jvm进程在执行这个作业
此时,你所有的RDD算子的代码执行以及它们操作的外部变量,都是在一个进程内存中,这个进程就是driver进程,此时是没有任何问题的
但是在作业提交到集群执行前,spark会在driver端处理闭包
spark中的闭包,特指哪些,不在算子的作用域nebula,但是在作用阈外部却被算子处理和操作的这些变量
而算子代码的执行也需要这些变量才能顺利执行
此时,这些闭包变量会被序列化成多个副本,然后每个副本都发送到各个executor进程中,供那个executor进程运行的task执行代码时使用
闭包变量发送到executor进程中之后,就变成了一个一个独立的变量副本了,这就是最关键的一点
此时在executor进程中,也有一个变量副本,但是缺完全跟各个executor进程照顾你的变量副本不是一个东西
此时,各个executor进程对于自己内存中的变量副本进行操作,即使改变了变量副本的值,但是对于driver端的程序,是完全感知不到的,driver端的变量没有被进行任何操作
因此,在使用集群模式运行作业的时候,切记不要在算子内部,对作用域外部的闭包变量进行改变值操作,因为那没有任何意义,算子仅仅在executor进程中改变副本的值
这里我们需要用到我们的Accumulator累加变量来对外部变量做操作