1 使用累加器的背景
spark在调度任务时,master会挑选一个worker成为driver。
在使用spark的action算子时,会触发job任务,开始计算。
此时,开始切分,driver分发Task给相应的executor,每个executor是相对独立的。
对应在action算子范围内的变量会各自独立。如果在action算子代码内使用driver算子代码范围的变量,
会形成在每个executor中有一个变量副本。
计算得到返回的变量值可能不是你想要的结果。
此时就需要累加器变量的概念,建立一个全局同步的变量。
1.1 不使用累加器变量
package spark.rdd
import org.apache.spark.rdd.RDD
import util.RddUtils
object WordCountRdd {
def main(args: Array[String]): Unit = {
//mycluster是namservice
val path = "hdfs://mycluster/input.txt"
val sc = RddUtils.initRdd("wordcount","local[*]")
val lines: RDD[String] = sc.textFile(path)
val result: RDD[(String, Int)] = lines
.filter(f => f.size > 0)
.flatMap(line => line.split(" ")).map(word => (word,1)).reduceByKey((v1, v2) => v1+v2)
var counter = 0
//foreach是action算子,内部是executor范围计算的变量和值,
//外部是drive代码范围,此时counter在里面executor被用到,
//也就是在driver有一个变量counter,每个executor中有一个副本变量counter。
//计算的结果不是我们想要的----计算单词的个数。而是0
result.foreach(f => counter += f._2)
println(counter)
}
}
package util
import org.apache.spark.{SparkConf, SparkContext}
object RddUtils {
def initRdd(appname:String,master:String):SparkContext = {
// val appname:String = "sparkname"
// val master:String = "local[*]"
/**
* master有几种方式:
* local
* spark://host:7077
* yarn
*/
//用户权限问题
System.setProperty("HADOOP_USER_NAME", "root")
System.setProperty("user.name", "root")
val conf: SparkConf = new SparkConf().setAppName(appname).setMaster(master)
// conf.set("spark.executor.memory", "1000m")
val sc = new SparkContext(conf)
//hadoop高可用时添加配置文件才能链接hdfs
sc.hadoopConfiguration.addResource("core-site.xml")
sc.hadoopConfiguration.addResource("hdfs-site.xml")
sc
}
}
预期结果应该是
(worldworld,6)
(jason,294)
(peng,588)
(sheng,588)
(hello,882)
(zhang,588)
(world,870)
相加为3816
实际计算的结果是 0
1.2 使用累加器变量
package spark.rdd
import org.apache.spark.rdd.RDD
import util.RddUtils
object AccumlatorTest {
def main(args: Array[String]): Unit = {
val path = "hdfs://mycluster/input.txt"
val sc = RddUtils.initRdd("accumlator","local[*]")
val lines = sc.textFile(path)
val result: RDD[(String, Int)] = lines
.filter(_.size > 0)
.flatMap(_.split(" "))
.map((_,1))
.reduceByKey(_+_)
val accum = sc.longAccumulator("My Accumulator")
result.foreach(f => accum.add(f._2))
println(accum.value)
}
}
计算的结果是3816