本文是Spark知識總結帖,講述Spark Partition相關內容。
1 什麼是Partition
Spark RDD 是一種分佈式的數據集,由於數據量很大,因此要它被切分並存儲在各個結點的分區當中。從而當我們對RDD進行操作時,實際上是對每個分區中的數據並行操作。
圖一:數據如何被分區並存儲到各個結點
圖二:RDD、Partition以及task的關係
參考: https://blog.csdn.net/zhangzeyuan56/article/details/80935034
2 Partition定義和初始化
查看spark源碼,trait Partition的定義很簡單,序列號index和hashCode方法。Partition和RDD是伴生的,即每一種RDD都有其對應的Partition實現,所以,分析Partition主要是分析其子類。我們關注兩個常用的子類,JdbcPartition和HadoopPartition。此外,RDD源碼中有5個方法,代表其組成,如下:
第二個方法,getPartitions是數據源如何被切分的邏輯,返回值正是Partition,第一個方法compute是消費切割後的Partition的方法,所以學習Partition,要結合getPartitions和compute方法。
JdbcPartition例子
下面是Spark JdbcRDDSuite中一個例子
val sc = new SparkContext("local[1]", "test")
val rdd = new JdbcRDD(
sc,
() => { DriverManager.getConnection("jdbc:derby:target/JdbcRDDSuiteDb") },
// DATA類型爲INTEGER
"SELECT DATA FROM FOO WHERE ? <= ID AND ID <= ?",
1, 100, 3,
(r: ResultSet) => { r.getInt(1) } ).count()
查看JdbcPartition實現,相比Partition,主要多了lower和upper這兩個字段。
查看JdbcRDD的getPartitions,按照如上圖所示算法將1到100分爲3份(partition數量),結果爲(1,33)、(34,66)、(67,100),封裝爲JdbcPartition並返回,這樣數據切分的部分就完成了。
查看JdbcRDD的compute方法,邏輯清晰,將Partition強轉爲JdbcPartition,獲取連接並預處理sql,將
例子中的”SELECT DATA FROM FOO WHERE ? <= ID AND ID <= ?”問號分別用Partition的lower和upper替換(即getPartitions切分好的(1,33)、(34,66)、(67,100))並執行查詢。至此,JdbcPartition如何發揮作用就分析完了。
參考:https://blog.csdn.net/u011564172/article/details/53611109
3 Partitioner 定義和用途
HashPartitioner簡介
HashPartitioner採用哈希的方式對<Key,Value>鍵值對數據進行分區。其數據分區規則爲 partitionId = Key.hashCode % numPartitions,其中partitionId代表該Key對應的鍵值對數據應當分配到的Partition標識,Key.hashCode表示該Key的哈希值,numPartitions表示包含的Partition個數。圖3簡單描述了HashPartitioner的數據分區過程。
RangePartitioner簡介
Spark引入RangePartitioner的目的是爲了解決HashPartitioner所帶來的分區傾斜問題,也即分區中包含的數據量不均衡問題。HashPartitioner採用哈希的方式將同一類型的Key分配到同一個Partition中,因此當某一或某幾種類型數據量較多時,就會造成若干Partition中包含的數據過大問題,而在Job執行過程中,一個Partition對應一個Task,此時就會使得某幾個Task運行過慢。RangePartitioner基於抽樣的思想來對數據進行分區。圖4簡單描述了RangePartitioner的數據分區過程。
Partitioner 用途
主要用在groupByKey, reduceByKey, repartition(n)這些需要shuffle操作的過程中。
參考: https://www.cnblogs.com/tongxupeng/p/10435976.html
https://www.jianshu.com/p/391d42665a30
4 Partition 參數設置
Partition數量的影響
Partition數量太少
太少的影響顯而易見,就是資源不能充分利用,例如local模式下,有16core,但是Partition數量僅爲8的話,有一半的core沒利用到。
Partition數量太多
太多,資源利用沒什麼問題,但是導致task過多,task的序列化和傳輸的時間開銷增大。
那麼多少的partition數是合適的呢,這裏我們參考spark doc給出的建議,Typically you want 2-4 partitions for each CPU in your cluster。
爲什麼不是partition數目不是和core 數量 1:1?
個人認爲,是partition對於的task直接有先後銜接關係,map -> transfer -> reduce 這樣兩到三個task可以同時在一個core上運行。
參考:https://spark.apache.org/docs/latest/tuning.html#level-of-parallelism