1. 程式人生 > >52.效能調優之Kryo序列化

52.效能調優之Kryo序列化

本文為《Spark大型電商專案實戰》 系列文章之一,主要介紹在實際專案中使用Kryo序列化的方式進行效能優化。

Kryo 序列化原因

在廣播大變數進行優化後,還可以進一步優化,即優化這個序列化格式。
預設情況下,Spark內部是使用Java的序列化機制ObjectOutputStream / ObjectInputStream這種物件輸入輸出流機制來進行序列化。
這種預設序列化機制的好處在於:處理起來比較方便,也不需要我們手動去做什麼事情,只是在運算元裡面使用的變數必須是實現Serializable介面的,可序列化即可。
但是缺點在於:預設的序列化機制的效率不高,序列化的速度比較慢;序列化以後的資料,佔用的記憶體空間相對還是比較大。

可以手動進行序列化格式的優化,Spark支援使用Kryo序列化機制。Kryo序列化機制比預設的Java序列化機制速度要快,序列化後的資料要更小,大概是Java序列化機制的1/10。所以Kryo序列化優化以後,可以讓網路傳輸的資料變少,在叢集中耗費的記憶體資源大大減少。

Kryo序列化生效位置

Kryo序列化機制一旦啟用以後,會在以下幾個地方生效:
1. 運算元函式中使用到的外部變數,會序列化,這時可以是用Kryo序列化機制;
2. 持久化 RDD 時進行序列化,比如StorageLevel.MEMORY_ONLY_SER,可以使用 Kryo 進一步優化序列化的效率和效能;
3、進行shuffle時,比如在進行stage間的task的shuffle操作時,節點與節點之間的task會互相大量通過網路拉取和傳輸檔案,此時,這些資料既然通過網路傳輸,也是可能要序列化的,就會使用Kryo。

Kryo序列化優點

其實之前在“Kryo序列化生效位置”處已經提到了Kryo序列化的優點,這裡總結一下,大致為:
1. 運算元函式中使用到的外部變數,使用Kryo以後:優化網路傳輸的效能,可以優化叢集中記憶體的佔用和消耗;
2. 持久化RDD,優化記憶體的佔用和消耗,持久化RDD佔用的記憶體越少,task執行的時候,建立的物件,就不至於頻繁的佔滿記憶體,頻繁發生GC;
3、shuffle:可以優化網路傳輸的效能。

實現Kryo序列化步驟

第一步,在 SparkConf中設定一個屬性spark.serializer,使用org.apache.spark.serializer.KryoSerializer

類。
Kryo 之所以沒有被作為預設的序列化類庫的原因,主要是因為 Kryo 要求,如果要達到它的最佳效能的話,那麼就一定要註冊你自定義的類(比如,你的運算元函式中使用到了外部自定義型別的物件變數,這時就要求必須註冊你的類,否則 Kryo 達不到最佳效能)。
第二步,註冊你使用到的需要通過 Kryo 序列化的一些自定義類。

程式碼實現

在專案中,以CategorySortKey這個方法為例,在獲取top10熱門品類功能中,在進行二次排序時自定義了一個key,這個key是需要在進行 shuffle 的時候進行網路傳輸的,因此也是要求實現序列化的,啟用 Kryo 序列化機制後就會用 Kryo 去序列化和反序列化 CategorySortKey,按上面講的序列化步驟具體實現程式碼為:

        SparkConf conf = new SparkConf()
                .setAppName(Constants.SPARK_APP_NAME_SESSION)
                .setMaster("local")
                .set("spark.serializer", "org.apache.spark.serializer.KryoSerializer")
                .registerKryoClasses(new Class[]{
                        CategorySortKey.class});