Flink面試八股文(上萬字面試必備寶典)
Flink是一個面向流處理和批處理的分布式數(shù)據(jù)計算引擎,能夠基于同一個Flink運行,可以提供流處理和批處理兩種類型的功能。?在 Flink 的世界觀中,一切都是由流組成的,離線數(shù)據(jù)是有界的流;實時數(shù)據(jù)是一個沒有界限的流:這就是所謂的有界流和無界流。
2. Flink的運行必須依賴Hadoop組件嗎
Flink可以完全獨立于Hadoop,在不依賴Hadoop組件下運行。但是做為大數(shù)據(jù)的基礎設施,Hadoop體系是任何大數(shù)據(jù)框架都繞不過去的。Flink可以集成眾多 Hadooop 組件,例如Yarn、Hbase、HDFS等等。例如,F(xiàn)link可以和Yarn集成做資源調(diào)度,也可以讀寫HDFS,或者利用HDFS做檢查點。
3. Flink集群運行時角色
Flink 運行時由兩種類型的進程組成:一個 JobManager 和一個或者多個 TaskManager。

Client 不是運行時和程序執(zhí)行的一部分,而是用于準備數(shù)據(jù)流并將其發(fā)送給 JobManager。之后,客戶端可以斷開連接(分離模式),或保持連接來接收進程報告(附加模式)??蛻舳丝梢宰鳛橛|發(fā)執(zhí)行 Java/Scala 程序的一部分運行,也可以在命令行進程 ./bin/flink run ... 中運行。
可以通過多種方式啟動 JobManager 和 TaskManager:直接在機器上作為 standalone 集群啟動、在容器中啟動、或者通過YARN等資源框架管理并啟動。TaskManager 連接到 JobManagers,宣布自己可用,并被分配工作。
JobManager:
JobManager 具有許多與協(xié)調(diào) Flink 應用程序的分布式執(zhí)行有關(guān)的職責:它決定何時調(diào)度下一個 task(或一組 task)、對完成的 task 或執(zhí)行失敗做出反應、協(xié)調(diào) checkpoint、并且協(xié)調(diào)從失敗中恢復等等。這個進程由三個不同的組件組成:
ResourceManager
ResourceManager 負責 Flink 集群中的資源提供、回收、分配,管理 task slots。
Dispatcher
Dispatcher 提供了一個 REST 接口,用來提交 Flink 應用程序執(zhí)行,并為每個提交的作業(yè)啟動一個新的 JobMaster。它還運行 Flink WebUI 用來提供作業(yè)執(zhí)行信息。
JobMaster
JobMaster 負責管理單個JobGraph的執(zhí)行。Flink 集群中可以同時運行多個作業(yè),每個作業(yè)都有自己的 JobMaster。
TaskManagers:
TaskManager(也稱為 worker)執(zhí)行作業(yè)流的 task,并且緩存和交換數(shù)據(jù)流。
必須始終至少有一個 TaskManager。在 TaskManager 中資源調(diào)度的最小單位是 task slot。TaskManager 中 task slot 的數(shù)量表示并發(fā)處理 task 的數(shù)量。請注意一個 task slot 中可以執(zhí)行多個算子。
4. Flink相比Spark Streaming有什么區(qū)別
1. 架構(gòu)模型
Spark Streaming 在運行時的主要角色包括:Master、Worker、Driver、Executor,F(xiàn)link 在運行時主要包含:Jobmanager、Taskmanager 和 Slot。
2. 任務調(diào)度
Spark Streaming 連續(xù)不斷的生成微小的數(shù)據(jù)批次,構(gòu)建有向無環(huán)圖 DAG,Spark Streaming 會依次創(chuàng)建 DStreamGraph、JobGenerator、JobScheduler。
Flink 根據(jù)用戶提交的代碼生成 StreamGraph,經(jīng)過優(yōu)化生成 JobGraph,然后提交給 JobManager 進行處理,JobManager 會根據(jù) JobGraph 生成 ExecutionGraph,ExecutionGraph 是 Flink 調(diào)度最核心的數(shù)據(jù)結(jié)構(gòu),JobManager 根據(jù) ExecutionGraph 對 Job 進行調(diào)度。
3. 時間機制
Spark Streaming 支持的時間機制有限,只支持處理時間。Flink 支持了流處理程序在時間上的三個定義:處理時間、事件時間、注入時間。同時也支持 watermark 機制來處理滯后數(shù)據(jù)。
4. 容錯機制
對于 Spark Streaming 任務,我們可以設置 checkpoint,然后假如發(fā)生故障并重啟,我們可以從上次 checkpoint 之處恢復,但是這個行為只能使得數(shù)據(jù)不丟失,可能會重復處理,不能做到恰一次處理語義。
Flink 則使用兩階段提交協(xié)議來解決這個問題。
5. 介紹下Flink的容錯機制(checkpoint)
Checkpoint機制是Flink可靠性的基石,可以保證Flink集群在某個算子因為某些原因(如 異常退出)出現(xiàn)故障時,能夠?qū)⒄麄€應用流圖的狀態(tài)恢復到故障之前的某一狀態(tài),保證應用流圖狀態(tài)的一致性。Flink的Checkpoint機制原理來自“Chandy-Lamport algorithm”算法。
每個需要Checkpoint的應用在啟動時,F(xiàn)link的JobManager為其創(chuàng)建一個 CheckpointCoordinator(檢查點協(xié)調(diào)器),CheckpointCoordinator全權(quán)負責本應用的快照制作。
CheckpointCoordinator(檢查點協(xié)調(diào)器),CheckpointCoordinator全權(quán)負責本應用的快照制作。

CheckpointCoordinator(檢查點協(xié)調(diào)器) 周期性的向該流應用的所有source算子發(fā)送 barrier(屏障)。
當某個source算子收到一個barrier時,便暫停數(shù)據(jù)處理過程,然后將自己的當前狀態(tài)制作成快照,并保存到指定的持久化存儲中,最后向CheckpointCoordinator報告自己快照制作情況,同時向自身所有下游算子廣播該barrier,恢復數(shù)據(jù)處理
下游算子收到barrier之后,會暫停自己的數(shù)據(jù)處理過程,然后將自身的相關(guān)狀態(tài)制作成快照,并保存到指定的持久化存儲中,最后向CheckpointCoordinator報告自身快照情況,同時向自身所有下游算子廣播該barrier,恢復數(shù)據(jù)處理。
每個算子按照步驟3不斷制作快照并向下游廣播,直到最后barrier傳遞到sink算子,快照制作完成。
當CheckpointCoordinator收到所有算子的報告之后,認為該周期的快照制作成功; 否則,如果在規(guī)定的時間內(nèi)沒有收到所有算子的報告,則認為本周期快照制作失敗。
文章推薦:
6. Flink checkpoint與Spark Streaming的有什么區(qū)別或優(yōu)勢嗎
spark streaming 的 checkpoint 僅僅是針對 driver 的故障恢復做了數(shù)據(jù)和元數(shù)據(jù)的 checkpoint。而 flink 的 checkpoint 機制 要復雜了很多,它采用的是輕量級的分布式快照,實現(xiàn)了每個算子的快照,及流動中的數(shù)據(jù)的快照。
7. Flink是如何保證Exactly-once語義的
Flink通過實現(xiàn)兩階段提交和狀態(tài)保存來實現(xiàn)端到端的一致性語義。分為以下幾個步驟:
開始事務(beginTransaction)創(chuàng)建一個臨時文件夾,來寫把數(shù)據(jù)寫入到這個文件夾里面
預提交(preCommit)將內(nèi)存中緩存的數(shù)據(jù)寫入文件并關(guān)閉
正式提交(commit)將之前寫完的臨時文件放入目標目錄下。這代表著最終的數(shù)據(jù)會有一些延遲
丟棄(abort)丟棄臨時文件
若失敗發(fā)生在預提交成功后,正式提交前??梢愿鶕?jù)狀態(tài)來提交預提交的數(shù)據(jù),也可刪除預提交的數(shù)據(jù)。
兩階段提交協(xié)議詳解:八張圖搞懂Flink的Exactly-once
8. 如果下級存儲不支持事務,F(xiàn)link怎么保證exactly-once
端到端的exactly-once對sink要求比較高,具體實現(xiàn)主要有冪等寫入和事務性寫入兩種方式。
冪等寫入的場景依賴于業(yè)務邏輯,更常見的是用事務性寫入。而事務性寫入又有預寫日志(WAL)和兩階段提交(2PC)兩種方式。
如果外部系統(tǒng)不支持事務,那么可以用預寫日志的方式,把結(jié)果數(shù)據(jù)先當成狀態(tài)保存,然后在收到 checkpoint 完成的通知時,一次性寫入 sink 系統(tǒng)。
9. Flink常用的算子有哪些
分兩部分:
數(shù)據(jù)讀取,這是Flink流計算應用的起點,常用算子有:
從內(nèi)存讀:fromElements
從文件讀:readTextFile
Socket 接入 :socketTextStream
自定義讀?。篶reateInput
處理數(shù)據(jù)的算子,常用的算子包括:Map(單輸入單輸出)、FlatMap(單輸入、多輸出)、Filter(過濾)、KeyBy(分組)、Reduce(聚合)、Window(窗口)、Connect(連接)、Split(分割)等。
推薦閱讀:一文學完Flink流計算常用算子(Flink算子大全)
10. Flink任務延時高,如何入手
在 Flink 的后臺任務管理中,我們可以看到 Flink 的哪個算子和 task 出現(xiàn)了反壓。最主要的手段是資源調(diào)優(yōu)和算子調(diào)優(yōu)。資源調(diào)優(yōu)即是對作業(yè)中的 Operator 的并發(fā)數(shù)(parallelism)、CPU(core)、堆內(nèi)存(heap_memory)等參數(shù)進行調(diào)優(yōu)。作業(yè)參數(shù)調(diào)優(yōu)包括:并行度的設置,State 的設置,checkpoint 的設置。
11. Flink是如何處理反壓的
Flink 內(nèi)部是基于 producer-consumer 模型來進行消息傳遞的,F(xiàn)link的反壓設計也是基于這個模型。Flink 使用了高效有界的分布式阻塞隊列,就像 Java 通用的阻塞隊列(BlockingQueue)一樣。下游消費者消費變慢,上游就會受到阻塞。
12. 如何排查生產(chǎn)環(huán)境中的反壓問題
1. 反壓出現(xiàn)的場景
反壓經(jīng)常出現(xiàn)在促銷、熱門活動等場景。短時間內(nèi)流量陡增造成數(shù)據(jù)的堆積或者消費速度變慢。
它們有一個共同的特點:數(shù)據(jù)的消費速度小于數(shù)據(jù)的生產(chǎn)速度。
2. 反壓監(jiān)控方法
通過Flink Web UI發(fā)現(xiàn)反壓問題。
Flink 的 TaskManager 會每隔 50 ms 觸發(fā)一次反壓狀態(tài)監(jiān)測,共監(jiān)測 100 次,并將計算結(jié)果反饋給 JobManager,最后由 JobManager 進行計算反壓的比例,然后進行展示。
這個比例展示邏輯如下:
OK: 0 <= Ratio <= 0.10,表示狀態(tài)良好正;
LOW: 0.10 < Ratio <= 0.5,表示有待觀察;
HIGH: 0.5 < Ratio <= 1,表示要處理了(增加并行度/subTask/檢查是否有數(shù)據(jù)傾斜/增加內(nèi)存)。
0.01,代表100次中有一次阻塞在內(nèi)部調(diào)用。
3. flink反壓的實現(xiàn)方式
Flink任務的組成由基本的“流”和“算子”構(gòu)成,“流”中的數(shù)據(jù)在“算子”間進行計算和轉(zhuǎn)換時,會被放入分布式的阻塞隊列中。當消費者的阻塞隊列滿時,則會降低生產(chǎn)者的數(shù)據(jù)生產(chǎn)速度
4. 反壓問題定位和處理
Flink會因為數(shù)據(jù)堆積和處理速度變慢導致checkpoint超時,而checkpoint是Flink保證數(shù)據(jù)一致性的關(guān)鍵所在,最終會導致數(shù)據(jù)的不一致發(fā)生。
數(shù)據(jù)傾斜:可以在 Flink 的后臺管理頁面看到每個 Task 處理數(shù)據(jù)的大小。當數(shù)據(jù)傾斜出現(xiàn)時,通常是簡單地使用類似 KeyBy 等分組聚合函數(shù)導致的,需要用戶將熱點 Key 進行預處理,降低或者消除熱點 Key 的影。
GC:不合理的設置 TaskManager 的垃圾回收參數(shù)會導致嚴重的 GC 問題,我們可以通過 -XX:+PrintGCDetails 參數(shù)查看 GC 的日志。
代碼本身:開發(fā)者錯誤地使用 Flink 算子,沒有深入了解算子的實現(xiàn)機制導致性能問題。我們可以通過查看運行機器節(jié)點的 CPU 和內(nèi)存情況定位問題。
13. Flink中的狀態(tài)存儲
Flink在做計算的過程中經(jīng)常需要存儲中間狀態(tài),來避免數(shù)據(jù)丟失和狀態(tài)恢復。選擇的狀態(tài)存儲策略不同,會影響狀態(tài)持久化如何和 checkpoint 交互。Flink提供了三種狀態(tài)存儲方式:MemoryStateBackend、FsStateBackend、RocksDBStateBackend。
14. Operator Chains(算子鏈)這個概念你了解嗎
為了更高效地分布式執(zhí)行,F(xiàn)link 會盡可能地將 operator 的 subtask 鏈接(chain)在一起形成 task。每個 task 在一個線程中執(zhí)行。將 operators 鏈接成 task 是非常有效的優(yōu)化:它能減少線程之間的切換,減少消息的序列化/反序列化,減少數(shù)據(jù)在緩沖區(qū)的交換,減少了延遲的同時提高整體的吞吐量。這就是我們所說的算子鏈。
15. Flink的內(nèi)存管理是如何做的
Flink 并不是將大量對象存在堆上,而是將對象都序列化到一個預分配的內(nèi)存塊上。此外,F(xiàn)link大量的使用了堆外內(nèi)存。如果需要處理的數(shù)據(jù)超出了內(nèi)存限制,則會將部分數(shù)據(jù)存儲到硬盤上。Flink 為了直接操作二進制數(shù)據(jù)實現(xiàn)了自己的序列化框架。
16. 如何處理生產(chǎn)環(huán)境中的數(shù)據(jù)傾斜問題
1. flink數(shù)據(jù)傾斜的表現(xiàn):
任務節(jié)點頻繁出現(xiàn)反壓,增加并行度也不能解決問題;
部分節(jié)點出現(xiàn)OOM異常,是因為大量的數(shù)據(jù)集中在某個節(jié)點上,導致該節(jié)點內(nèi)存被爆,任務失敗重啟。
2. 數(shù)據(jù)傾斜產(chǎn)生的原因:
業(yè)務上有嚴重的數(shù)據(jù)熱點,比如滴滴打車的訂單數(shù)據(jù)中北京、上海等幾個城市的訂單量遠遠超過其他地區(qū);
技術(shù)上大量使用了 KeyBy、GroupBy 等操作,錯誤的使用了分組 Key,人為產(chǎn)生數(shù)據(jù)熱點。
3. 解決問題的思路:
業(yè)務上要盡量避免熱點 key 的設計,例如我們可以把北京、上海等熱點城市分成不同的區(qū)域,并進行單獨處理;
技術(shù)上出現(xiàn)熱點時,要調(diào)整方案打散原來的 key,避免直接聚合;此外 Flink 還提供了大量的功能可以避免數(shù)據(jù)傾斜。
17. Flink中的Time有哪幾種
Flink中的時間有三種類型,如下圖所示:

Event Time:是事件創(chuàng)建的時間。它通常由事件中的時間戳描述,例如采集的日志數(shù)據(jù)中,每一條日志都會記錄自己的生成時間,F(xiàn)link通過時間戳分配器訪問事件時間戳。
Ingestion Time:是數(shù)據(jù)進入Flink的時間。
Processing Time:是每一個執(zhí)行基于時間操作的算子的本地系統(tǒng)時間,與機器相關(guān),默認的時間屬性就是Processing Time。
例如,一條日志進入Flink的時間為2021-01-22 10:00:00.123,到達Window的系統(tǒng)時間為2021-01-22 10:00:01.234,日志的內(nèi)容如下:2021-01-06 18:37:15.624 INFO Fail over to rm2
對于業(yè)務來說,要統(tǒng)計1min內(nèi)的故障日志個數(shù),哪個時間是最有意義的?—— eventTime,因為我們要根據(jù)日志的生成時間進行統(tǒng)計。
18. Flink對于遲到數(shù)據(jù)是怎么處理的
Flink中 WaterMark 和 Window 機制解決了流式數(shù)據(jù)的亂序問題,對于因為延遲而順序有誤的數(shù)據(jù),可以根據(jù)eventTime進行業(yè)務處理,對于延遲的數(shù)據(jù)Flink也有自己的解決辦法,主要的辦法是給定一個允許延遲的時間,在該時間范圍內(nèi)仍可以接受處理延遲數(shù)據(jù)
設置允許延遲的時間是通過allowedLateness(lateness: Time)設置
保存延遲數(shù)據(jù)則是通過sideOutputLateData(outputTag: OutputTag[T])保存
獲取延遲數(shù)據(jù)是通過DataStream.getSideOutput(tag: OutputTag[X])獲取
文章推薦:
Flink 中極其重要的 Time 與 Window 詳細解析
19. Flink中window出現(xiàn)數(shù)據(jù)傾斜怎么解決
window 產(chǎn)生數(shù)據(jù)傾斜指的是數(shù)據(jù)在不同的窗口內(nèi)堆積的數(shù)據(jù)量相差過多。本質(zhì)上產(chǎn)生這種情況的原因是數(shù)據(jù)源頭發(fā)送的數(shù)據(jù)量速度不同導致的。出現(xiàn)這種情況一般通過兩種方式來解決:
在數(shù)據(jù)進入窗口前做預聚合
重新設計窗口聚合的 key
20. Flink CEP編程中當狀態(tài)沒有到達的時候會將數(shù)據(jù)保存在哪里
在流式處理中,CEP 當然是要支持 EventTime 的,那么相對應的也要支持數(shù)據(jù)的遲到現(xiàn)象,也就是watermark的處理邏輯。CEP對未匹配成功的事件序列的處理,和遲到數(shù)據(jù)是類似的。在 Flink CEP的處理邏輯中,狀態(tài)沒有滿足的和遲到的數(shù)據(jù),都會存儲在一個Map數(shù)據(jù)結(jié)構(gòu)中,也就是說,如果我們限定判斷事件序列的時長為5分鐘,那么內(nèi)存中就會存儲5分鐘的數(shù)據(jù),這在我看來,也是對內(nèi)存的極大損傷之一。
推薦閱讀:一文學會Flink CEP
21. Flink設置并行度的方式
們在實際生產(chǎn)環(huán)境中可以從四個不同層面設置并行度:
操作算子層面(Operator Level)
.map(new?RollingAdditionMapper()).setParallelism(10)?//將操作算子設置并行度
執(zhí)行環(huán)境層面(Execution Environment Level)
$FLINK_HOME/bin/flink?的-p參數(shù)修改并行度
客戶端層面(Client Level)
env.setParallelism(10)
系統(tǒng)層面(System Level)
全局配置在flink-conf.yaml文件中,parallelism.default,默認是1:可以設置默認值大一點
需要注意的優(yōu)先級:算子層面>環(huán)境層面>客戶端層面>系統(tǒng)層面。
22. Flink中Task如何做到數(shù)據(jù)交換
在一個 Flink Job 中,數(shù)據(jù)需要在不同的 task 中進行交換,整個數(shù)據(jù)交換是有 TaskManager 負責的,TaskManager 的網(wǎng)絡組件首先從緩沖 buffer 中收集 records,然后再發(fā)送。Records 并不是一個一個被發(fā)送的,是積累一個批次再發(fā)送,batch 技術(shù)可以更加高效的利用網(wǎng)絡資源。
23. Flink的內(nèi)存管理是如何做的
Flink 并不是將大量對象存在堆上,而是將對象都序列化到一個預分配的內(nèi)存塊上。此外,F(xiàn)link大量的使用了堆外內(nèi)存。如果需要處理的數(shù)據(jù)超出了內(nèi)存限制,則會將部分數(shù)據(jù)存儲到硬盤上。Flink 為了直接操作二進制數(shù)據(jù)實現(xiàn)了自己的序列化框架。
24. 介紹下Flink的序列化
Flink 摒棄了 Java 原生的序列化方法,以獨特的方式處理數(shù)據(jù)類型和序列化,包含自己的類型描述符,泛型類型提取和類型序列化框架。
TypeInformation 是所有類型描述符的基類。它揭示了該類型的一些基本屬性,并且可以生成序列化器。
TypeInformation 支持以下幾種類型:
BasicTypeInfo: 任意 Java 基本類型或 String 類型
BasicArrayTypeInfo: 任意 Java 基本類型數(shù)組或 String 數(shù)組
WritableTypeInfo: 任意 Hadoop Writable 接口的實現(xiàn)類
TupleTypeInfo: 任意的 Flink Tuple 類型(支持 Tuple1 to Tuple25)。Flink tuples 是固定長度固定類型的 Java Tuple 實現(xiàn)
CaseClassTypeInfo: 任意的 Scala CaseClass(包括 Scala tuples)
PojoTypeInfo: 任意的 POJO (Java or Scala),例如,Java 對象的所有成員變量,要么是 public 修飾符定義,要么有 getter/setter 方法
GenericTypeInfo: 任意無法匹配之前幾種類型的類
25. Flink海量數(shù)據(jù)高效去重
基于狀態(tài)后端。
基于HyperLogLog:不是精準的去重。
基于布隆過濾器(BloomFilter);快速判斷一個key是否存在于某容器,不存在就直接返回。
基于BitMap;用一個bit位來標記某個元素對應的Value,而Key即是該元素。由于采用了Bit為單位來存儲數(shù)據(jù),因此可以大大節(jié)省存儲空間。
基于外部數(shù)據(jù)庫;選擇使用Redis或者HBase存儲數(shù)據(jù),我們只需要設計好存儲的Key即可,不需要關(guān)心Flink任務重啟造成的狀態(tài)丟失問題。
26. Flink SQL的是如何實現(xiàn)的

構(gòu)建抽象語法樹的事情交給了 Calcite 去做。SQL query 會經(jīng)過 Calcite 解析器轉(zhuǎn)變成 SQL 節(jié)點樹,通過驗證后構(gòu)建成 Calcite 的抽象語法樹(也就是圖中的 Logical Plan)。另一邊,Table API 上的調(diào)用會構(gòu)建成 Table API 的抽象語法樹,并通過 Calcite 提供的 RelBuilder 轉(zhuǎn)變成 Calcite 的抽象語法樹。然后依次被轉(zhuǎn)換成邏輯執(zhí)行計劃和物理執(zhí)行計劃。
在提交任務后會分發(fā)到各個 TaskManager 中運行,在運行時會使用 Janino 編譯器編譯代碼后運行。
