
先只做一個(gè)靜態(tài)的分析,即上圖最左面部份,動(dòng)態(tài)調(diào)度執(zhí)行稍后分析
概念理解
做為新手,RDD看的我頭痛,Resilient Distributed Dataset, ?彈性分布式數(shù)據(jù)集,有哪些特點(diǎn)呢?
1. 首先他是 Dataset, 俗稱數(shù)據(jù)集??梢灶惐?Redis 里的 ZSET, HSET, SET, 保存數(shù)據(jù)的一種組織結(jié)構(gòu)而已。區(qū)別就在于 RDD 是分布式,粗粒度
2. 關(guān)于分布式,大家所熟知的就是將數(shù)據(jù)分片。類比 MySQL 分庫(kù)分表,可以有按 ID 做 Range 分怎,也可以按 Hash。RDD 也同樣,具體取決于 partitioner 如何實(shí)現(xiàn)。
3. 具有 fault tolerance 特性,做個(gè)對(duì)比,關(guān)系數(shù)據(jù)庫(kù)一般都是對(duì)分區(qū) partition 做多副本來做到容災(zāi)和高可用。但是RDD 完全另外一個(gè)思路,他有一個(gè) lineage(血統(tǒng)??) 的概念,每一個(gè) partition 都可以回溯來重建。
4. 由于 RDD 只讀,每一個(gè) RDD 都由父 RDD 和做用之上的操作生成,父子 partition 涉及一一對(duì)應(yīng)(窄依賴)和一對(duì)多(寬依賴),而這種依賴關(guān)系就是構(gòu)成 fault tolerance 回溯的基礎(chǔ)。
上面只是對(duì)于 RDD 靜態(tài)的分析,至于動(dòng)態(tài)的調(diào)度執(zhí)行和 stage 劃分下次再分享。
RDD 五要素
1. A list of partitions ? 數(shù)據(jù)分區(qū)
2. A function for computing each split 每個(gè)片的處理函數(shù)
3. A list of dependencies on other RDDs 依賴
4. Optionally, a Partitioner for key-value RDDs (e.g. to say that the RDD is hash-partitioned) 分區(qū)函數(shù)很重要,對(duì)于join group 優(yōu)化
5. Optionally, a list of preferred locations to compute each split on (e.g. block locations for?an HDFS file)
例子: 行數(shù)統(tǒng)計(jì)
來看一個(gè)官網(wǎng) quick start 例子,打開 spark-shell
scala> val textFile = sc.textFile("README.md")
textFile: org.apache.spark.rdd.RDD[String] = README.md MapPartitionsRDD[1] at textFile at:27
textFile 是一個(gè) MapPartitionsRDD, 他沒有 Dependency, 并且也不會(huì)讀取數(shù)據(jù),不做任何操作
scala> val linesWithSpark = textFile.filter(line => line.contains("Spark"))
linesWithSpark: org.apache.spark.rdd.RDD[String] = MapPartitionsRDD[2] at filter at:29
linesWithSpark 同樣也是一個(gè) MapPartitionsRDD, 他有 Dependency, 就是上文的 textFile, 并且附加一個(gè) filter 操作,返回包含 “Spark” 的記錄
scala> linesWithSpark.count
res0: Long = 17
最后執(zhí)行 count 函數(shù),得到記錄 17?
transformation 和 action
RDD 只讀,所以每次 filter, map, flatMap 等操作都是生成一個(gè)新的 RDD, 多個(gè) RDD 為鏈?zhǔn)疥P(guān)系,由 Denpendency 和 compute 聯(lián)系在一起。下圖是主要的兩類函數(shù)。

transformation: 惰性的操作,只生成新的 RDD, 描述執(zhí)行邏輯
action: 會(huì)提交 job, 交給 worker 去執(zhí)行,流式依次計(jì)算所有 transformation 操作,流式的精髓在于 Iterator
對(duì)應(yīng)文中例子,textFile和filter 都是 transformation 操作,只負(fù)責(zé)生成 RDD, 只有最后一個(gè) count 才發(fā)起 job 執(zhí)行。

filter 函數(shù)簡(jiǎn)單明了,直接生成一個(gè)新的 MapPartitionsRDD, 重點(diǎn)在于兩個(gè)參數(shù) this 和 iter 操作的閉包

MapPartitionsRDD 要重寫幾個(gè)關(guān)鍵成員函數(shù),partitioner 決定如何做分區(qū),getPartitions 決定如何從父 RDD 中獲取自已使用的 partition,這塊是簡(jiǎn)單的 one to one依賴,即窄依賴,后續(xù)會(huì)涉及到 shuffle 寬依賴再分析。compute 封裝傳弟的 f 閉包,直接作用于 partition, 這里都是針對(duì) Iterator, 不到最后觸發(fā)是不會(huì)執(zhí)行。

count不具有代表現(xiàn),貼一個(gè) reduce 源碼, 最常見的就是 reduce(_+_),如果大家了解單機(jī)的,肯定知道原理,對(duì)于分布式的RDD也一樣。 jobResult 是一個(gè) Option[T] 結(jié)果,mergeResult 決定如何對(duì)各個(gè)分區(qū)的結(jié)果進(jìn)行操作,就是調(diào)用 reduce(f: (T,T) => T): T 里面的閉包f,對(duì)于各分區(qū)也執(zhí)行 f。
RDD 的初探,DAGSchdule 后文分析,如有理解有誤的請(qǐng)大家指證