spark累加器Accumulator

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章