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

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