我說Java基礎重要,你不信?來試試這幾個問題

點擊上方藍色字體,選擇“設爲星標”

回覆”面試“獲取更多驚喜

什麼是字節碼?Java採用字節碼的好處是什麼?

那我在問問SparkSQL的字節碼生成是怎麼做的不過分吧?

代碼生成技術廣泛應用於現代的數據庫系統中。代碼生成是將用戶輸入的表達式、查詢、存儲過程等現場編譯成二進制代碼再執行,相比解釋執行的方式,運行效率要高很多。尤其是對於計算密集型查詢、或頻繁重複使用的計算過程,運用代碼生成技術能達到數十倍的性能提升。

Spark SQL在其catalyst模塊的expressions中增加了codegen模塊,對於SQL語句中的計算表達式,比如select num + num from t這種的sql,就可以使用動態字節碼生成技術來優化其性能。

spark1.x就已經有代碼生成技術,2.0進一步優化。

spark1.4,使用代碼生成技術加速表達式計算。表達式代碼生成(expression codegen)表達式代碼生成主要是想解決大量虛函數調用(Virtual Function Calls),泛化的代價等。需要注意的是,上面通過表達式生成完整的類代碼只有在將 spark.sql.codegen.wholeStage 設置爲 false 纔會進行的,否則只會生成一部分代碼,並且和其他代碼組成 Whole-stage Code。

spark2.0支持同一個stage的多個算子組合編譯成一段二進制。主要就是將一串的算子,轉換成一段代碼(Spark sql轉換成java代碼),從而提高性能。一串的算子操作,可以轉換成一個java方法,這樣一來性能會有一定的提升。通過引入全階段代碼生成,大大減少了虛函數的調用,減少了 CPU 的調用,使得 SQL 的執行速度有很大提升。

代碼編譯:通過janino實現的。

Janino 是一個超級小但又超級快的 Java™ 編譯器. 它不僅能像 javac 工具那樣將一組源文件編譯成字節碼文件,還可以對一些 Java 表達式,代碼塊,類中的文本(class body)或者內存中源文件進行編譯,並把編譯後的字節碼直接加載到同一個 JVM 中運行。Janino 不是一個開發工具, 而是作爲運行時的嵌入式編譯器,比如作爲表達式求值的翻譯器或類似於 JSP 的服務端頁面引擎。通過引入了 Janino 來編譯生成的代碼,結果顯示 SQL 表達式的編譯時間減少到 5ms。在 Spark 中使用了 ClassBodyEvaluator 來編譯生成之後的代碼,參見 org.apache.spark.sql.catalyst.expressions.codegen.CodeGenerator。

Java的IO熟悉吧?

那我問個HDFS上傳和MapReduce讀取文件有什麼區別不過分吧?

MapReduce的InputFormat常見子類包括:

  • TextInputFormat (普通文本文件,MR框架默認的讀取實現類型

  • KeyValueTextInputFormat(讀取一行文本數據按照指定分隔符,把數據封裝爲kv類型)

  • NLineInputFormat(讀取數據按照行數進行劃分分片)

  • CombineTextInputFormat(合併小文件,避免啓動過多MapTask任務)

HDFS讀取文件:

public static void copyBytes(InputStream in, OutputStream out, int buffSize) throws IOException {
PrintStream ps = out instanceof PrintStream ? (PrintStream)out : null;
byte[] buf = new byte[buffSize];

for(int bytesRead = in.read(buf); bytesRead >= 0; bytesRead = in.read(buf)) {
out.write(buf, 0, bytesRead);
if (ps != null && ps.checkError()) {
throw new IOException("Unable to write to output stream.");
}
}
}

Java中的Serializable熟悉吧?

那我問問你知道的任何一個框架的序列化是怎麼做的?爲什麼這些框架不用Java原生的序列化不過分吧?

Flink爲什麼要自己實現序列化框架?

目前,絕大多數的大數據計算框架都是基於JVM實現的,爲了快速地計算數據,需要將數據加載到內存中進行處理。當大量數據需要加載到內存中時,如果使用Java序列化方式來存儲對象,佔用的空間會較大降低存儲傳輸效率。

例如:一個只包含布爾類型的對象需要佔用16個字節的內存:對象頭要佔8個字節、boolean屬性佔用1個字節、對齊填充還要佔用7個字節。

Java序列化方式存儲對象存儲密度是很低的。也是基於此,Flink框架實現了自己的內存管理系統,在Flink自定義內存池分配和回收內存,然後將自己實現的序列化對象存儲在內存塊中。

Java生態系統中有挺多的序列化框架,例如:Kryo、Avro、ProtoBuf等。Flink自己實現了一套序列化系統可以讓我們編寫程序的時候,儘快地發現問題,更加節省內存空間,並直接進行二進制數據的處理。

例如:POJO類型對應的是PojoTypeInfo、基礎數據類型數組對應的是BasicArrayTypeInfo、Map類型對應的是MapTypeInfo、值類型對應的是ValueTypeInfo。

除了對類型地描述之外,TypeInformation還提供了序列化的支撐。在TypeInformation中有一個方法:createSerializer方法,它用來創建序列化器,序列化器中定義了一系列的方法。其中,通過serialize和deserialize方法,可以將指定類型進行序列化。並且,Flink的這些序列化器會以稠密的方式來將對象寫入到內存中。

Spark的目標是在便利與性能中取得平衡,所以提供2種序列化的選擇。

  • Java serialization

在默認情況下,Spark會使用Java的ObjectOutputStream框架對對象進行序列化,並且可以與任何實現java.io.Serializable的類一起工作。您還可以通過擴展java.io.Externalizable來更緊密地控制序列化的性能。Java序列化是靈活的,但通常相當慢,並且會導致許多類的大型序列化格式。

  • Kryo serialization

Spark還可以使用Kryo庫(版本2)來更快地序列化對象。Kryo比Java串行化(通常多達10倍)要快得多,也更緊湊,但是不支持所有可串行化類型,並且要求您提前註冊您將在程序中使用的類,以獲得最佳性能

Kryo serialization 性能和序列化大小都比默認提供的 Java serialization 要好,但是使用Kryo需要將自定義的類先註冊進去,使用起來比Java serialization麻煩。自從Spark 2.0.0以來,我們在使用簡單類型、簡單類型數組或字符串類型的簡單類型來調整RDDs時,在內部使用Kryo序列化器。

Java中的反射了解吧?

那我問問Spark SQL將RDD轉換爲DataFrame如何實現的不過分吧?

Spark SQL支持將現有RDDS轉換爲DataFrame的兩種不同方法,其實也就是隱式推斷或者顯式指定DataFrame對象的Schema。

  • 1.使用反射機制( Reflection )推理出schema (結構信息)

第一種將RDDS轉化爲DataFrame的方法是使用Spark SQL內部反射機制來自動推斷包含特定類型對象的RDD的schema

(RDD的結構信息)進行隱式轉化。採用這種方式轉化爲DataFrame對象,往往是因爲被轉化的RDD[T]所包含的T對象本身就是具有典型-一維表嚴格的字段結構的對象,因此Spark SQL很容易就可以自動推斷出合理的Schema這種基於反射機制隱式地創建DataFrame的方法往往僅需更簡潔的代碼即可完成轉化,並且運行效果良好。

Spark SQL的Scala接口支持自動將包含樣例類( case class對象的RDD轉換爲DataFrame對象。在樣例類的聲明中 已預先定義了表的結構信息,內部通過反射機制即可讀取樣例類的參數的名稱、類型,轉化爲DataFrame對象的Schema.樣例類不僅可以包含Int、Double、String這樣的簡單數據類型,也可以嵌套或包含複雜類型,例如Seq或Arrays。

  • 2.由開發者指定Schema

RDD轉化DataFrame的第二種方法是通過編程接口,允許先構建個schema,然後將其應用到現有的RDD(Row),較前一種方法由樣例類或基本數據類型 (Int、String) 對象組成的RDD加過toDF ()直接隱式轉化爲DataFrame不同,不僅需要根據需求、以及數據結構構建Schema,而且需要將RDD[T]轉化爲Row對象組成的RDD (RDD[Row]),這種方法雖然代碼量一些,但也提供了更高的自由度,更加靈活。

LinkedHashMap知道吧?

那我問問Spark做內存管理有一種叫"存儲內存",用了什麼數據結構?淘汰策略是什麼不過分吧?

由於同一個 Executor 的所有的計算任務共享有限的存儲內存空間,當有新的 Block 需要緩存但是剩餘空間不足且無法動態佔用時,就要對 LinkedHashMap 中的舊 Block 進行淘汰(Eviction),而被淘汰的 Block 如果其存儲級別中同時包含存儲到磁盤的要求,則要對其進行落盤(Drop),否則直接刪除該 Block

遍歷 LinkedHashMap 中 Block,按照最近最少使用(LRU)的順序淘汰,直到滿足新 Block 所需的空間。其中LRU 是 LinkedHashMap 的特性。

快速失敗(fail-fast)和安全失敗(fail-safe)聽過吧?

Flink哪裏的設計用到了fail-fast理念?

In case of a program failure (due to machine-, network-, or software failure), Flink stops the distributed streaming dataflow. The system then restarts the operators and resets them to the latest successful checkpoint. The input streams are reset to the point of the state snapshot. Any records that are processed as part of the restarted parallel dataflow are guaranteed to not have been part of the previously checkpointed state.

你很懂ConcurrentHashMap?

### 那我問問Spark/Flink中哪裏用到了ConcurrentHashMap?

友情提示:Spark中的所有Settings,Flink中的ParameterUtil,太多了。




八千里路雲和月 | 從零到大數據專家學習路徑指南

我們在學習Flink的時候,到底在學習什麼?

193篇文章暴揍Flink,這個合集你需要關注一下

Flink生產環境TOP難題與優化,阿里巴巴藏經閣YYDS

Flink CDC我喫定了耶穌也留不住他!| Flink CDC線上問題小盤點

我們在學習Spark的時候,到底在學習什麼?

在所有Spark模塊中,我願稱SparkSQL爲最強!

硬剛Hive | 4萬字基礎調優面試小總結

數據治理方法論和實踐小百科全書

標籤體系下的用戶畫像建設小指南

4萬字長文 | ClickHouse基礎&實踐&調優全視角解析

【面試&個人成長】2021年過半,社招和校招的經驗之談

大數據方向另一個十年開啓 |《硬剛系列》第一版完結

我寫過的關於成長/面試/職場進階的文章

當我們在學習Hive的時候在學習什麼?「硬剛Hive續集」


你好,我是王知無,一個大數據領域的硬核原創作者。

做過後端架構、數據中間件、數據平臺&架構、算法工程化。

專注大數據領域實時動態&技術提升&個人成長&職場進階,歡迎關注。

本文分享自微信公衆號 - 大數據技術與架構(import_bigdata)。
如有侵權,請聯繫 [email protected] 刪除。
本文參與“OSC源創計劃”,歡迎正在閱讀的你也加入,一起分享。

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