flink面試相關手冊

概述

2019 年是大數據實時計算領域最不平凡的一年,2019 年 1 月阿里巴巴 Blink (內部的 Flink 分支版本)開源,大數據領域一夜間從 Spark 獨步天下走向了兩強爭霸的時代。Flink 因爲其天然的流式計算特性以及強大的處理性能成爲炙手可熱的大數據處理框架。

時至今日,Flink 已經發展到 1.9 版本,在大數據開發領域,面試中對於 Flink 的考察已經是大數據開發求職者必須面對的,本文結合自己作爲面試官過程中的經驗詳細總結了近 50 個關於 Flink 的面試考察點。

在本文中,分爲以下幾個部分:

第一部分:Flink 中的核心概念和基礎篇,包含了 Flink 的整體介紹、核心概念、算子等考察點。

第二部分:Flink 進階篇,包含了 Flink 中的數據傳輸、容錯機制、序列化、數據熱點、反壓等實際生產環境中遇到的問題等考察點。

第三部分:Flink 源碼篇,包含了 Flink 的核心代碼實現、Job 提交流程、數據交換、分佈式快照機制、Flink SQL 的原理等考察點。

第一部分:Flink 中的核心概念和基礎考察

一、 簡單介紹一下 Flink

Flink 是一個框架和分佈式處理引擎,用於對無界和有界數據流進行有狀態計算。並且 Flink 提供了數據分佈、容錯機制以及資源管理等核心功能。

Flink提供了諸多高抽象層的API以便用戶編寫分佈式任務:

  • DataSet API, 對靜態數據進行批處理操作,將靜態數據抽象成分佈式的數據集,用戶可以方便地使用Flink提供的各種操作符對分佈式數據集進行處理,支持Java、Scala和Python。

  • DataStream API,對數據流進行流處理操作,將流式的數據抽象成分佈式的數據流,用戶可以方便地對分佈式數據流進行各種操作,支持Java和Scala。

  • Table API,對結構化數據進行查詢操作,將結構化數據抽象成關係表,並通過類SQL的DSL對關係表進行各種查詢操作,支持Java和Scala。

此外,Flink 還針對特定的應用領域提供了領域庫,例如: Flink ML,Flink 的機器學習庫,提供了機器學習Pipelines API並實現了多種機器學習算法。 Gelly,Flink 的圖計算庫,提供了圖計算的相關API及多種圖計算算法實現。

根據官網的介紹,Flink 的特性包含:

支持高吞吐、低延遲、高性能的流處理
支持帶有事件時間的窗口 (Window) 操作
支持有狀態計算的 Exactly-once 語義
支持高度靈活的窗口 (Window) 操作,支持基於 time、count、session 以及 data-driven 的窗口操作
支持具有 Backpressure 功能的持續流模型
支持基於輕量級分佈式快照(Snapshot)實現的容錯
一個運行時同時支持 Batch on Streaming 處理和 Streaming 處理
Flink 在 JVM 內部實現了自己的內存管理
支持迭代計算
支持程序自動優化:避免特定情況下 Shuffle、排序等昂貴操作,中間結果有必要進行緩存

二、 Flink 相比傳統的 Spark Streaming 有什麼區別?

這個問題是一個非常宏觀的問題,因爲兩個框架的不同點非常之多。但是在面試時有非常重要的一點一定要回答出來:Flink 是標準的實時處理引擎,基於事件驅動。而 Spark Streaming 是微批(Micro-Batch)的模型。

下面我們就分幾個方面介紹兩個框架的主要區別:

  1. 架構模型
    Spark Streaming 在運行時的主要角色包括:Master、Worker、Driver、Executor,Flink 在運行時主要包含:Jobmanager、Taskmanager和Slot。

  2. 任務調度
    Spark Streaming 連續不斷的生成微小的數據批次,構建有向無環圖DAG,Spark Streaming 會依次創建 DStreamGraph、JobGenerator、JobScheduler。
    Flink 根據用戶提交的代碼生成 StreamGraph,經過優化生成 JobGraph,然後提交給 JobManager進行處理,JobManager 會根據 JobGraph 生成 ExecutionGraph,ExecutionGraph 是 Flink 調度最核心的數據結構,JobManager 根據 ExecutionGraph 對 Job 進行調度。

  3. 時間機制
    Spark Streaming 支持的時間機制有限,只支持處理時間。 Flink 支持了流處理程序在時間上的三個定義:處理時間、事件時間、注入時間。同時也支持 watermark 機制來處理滯後數據。

  4. 容錯機制
    對於 Spark Streaming 任務,我們可以設置 checkpoint,然後假如發生故障並重啓,我們可以從上次 checkpoint 之處恢復,但是這個行爲只能使得數據不丟失,可能會重複處理,不能做到恰好一次處理語義。

Flink 則使用兩階段提交協議來解決這個問題。

三、 Flink 的組件棧有哪些?

根據 Flink 官網描述,Flink 是一個分層架構的系統,每一層所包含的組件都提供了特定的抽象,用來服務於上層組件。在這裏插入圖片描述
自下而上,每一層分別代表:Deploy 層:該層主要涉及了Flink的部署模式,在上圖中我們可以看出,Flink 支持包括local、Standalone、Cluster、Cloud等多種部署模式。Runtime 層:Runtime層提供了支持 Flink 計算的核心實現,比如:支持分佈式 Stream 處理、JobGraph到ExecutionGraph的映射、調度等等,爲上層API層提供基礎服務。API層:API 層主要實現了面向流(Stream)處理和批(Batch)處理API,其中面向流處理對應DataStream API,面向批處理對應DataSet API,後續版本,Flink有計劃將DataStream和DataSet API進行統一。Libraries層:該層稱爲Flink應用框架層,根據API層的劃分,在API層之上構建的滿足特定應用的實現計算框架,也分別對應於面向流處理和麪向批處理兩類。面向流處理支持:CEP(複雜事件處理)、基於SQL-like的操作(基於Table的關係操作);面向批處理支持:FlinkML(機器學習庫)、Gelly(圖處理)。

四、Flink 的運行必須依賴 Hadoop組件嗎?

Flink可以完全獨立於Hadoop,在不依賴Hadoop組件下運行。但是做爲大數據的基礎設施,Hadoop體系是任何大數據框架都繞不過去的。Flink可以集成衆多Hadooop 組件,例如Yarn、Hbase、HDFS等等。例如,Flink可以和Yarn集成做資源調度,也可以讀寫HDFS,或者利用HDFS做檢查點。

五、你們的Flink集羣規模多大?

大家注意,這個問題看起來是問你實際應用中的Flink集羣規模,其實還隱藏着另一個問題:Flink可以支持多少節點的集羣規模?
在回答這個問題時候,可以將自己生產環節中的集羣規模、節點、內存情況說明,同時說明部署模式(一般是Flink on Yarn),除此之外,用戶也可以同時在小集羣(少於5個節點)和擁有 TB 級別狀態的上千個節點上運行 Flink 任務。

六、Flink的基礎編程模型瞭解嗎?

在這裏插入圖片描述
上圖是來自Flink官網的運行流程圖。通過上圖我們可以得知,Flink 程序的基本構建是數據輸入來自一個 Source,Source 代表數據的輸入端,經過 Transformation 進行轉換,然後在一個或者多個Sink接收器中結束。數據流(stream)就是一組永遠不會停止的數據記錄流,而轉換(transformation)是將一個或多個流作爲輸入,並生成一個或多個輸出流的操作。執行時,Flink程序映射到 streaming dataflows,由流(streams)和轉換操作(transformation operators)組成。

七、Flink集羣有哪些角色?各自有什麼作用?

在這裏插入圖片描述
Flink 程序在運行時主要有 TaskManager,JobManager,Client三種角色。其中JobManager扮演着集羣中的管理者Master的角色,它是整個集羣的協調者,負責接收Flink Job,協調檢查點,Failover 故障恢復等,同時管理Flink集羣中從節點TaskManager。

TaskManager是實際負責執行計算的Worker,在其上執行Flink Job的一組Task,每個TaskManager負責管理其所在節點上的資源信息,如內存、磁盤、網絡,在啓動的時候將資源的狀態向JobManager彙報。

Client是Flink程序提交的客戶端,當用戶提交一個Flink程序時,會首先創建一個Client,該Client首先會對用戶提交的Flink程序進行預處理,並提交到Flink集羣中處理,所以Client需要從用戶提交的Flink程序配置中獲取JobManager的地址,並建立到JobManager的連接,將Flink Job提交給JobManager。

八、說說 Flink 資源管理中 Task Slot 的概念

在這裏插入圖片描述
在Flink架構角色中我們提到,TaskManager是實際負責執行計算的Worker,TaskManager 是一個 JVM 進程,並會以獨立的線程來執行一個task或多個subtask。爲了控制一個 TaskManager 能接受多少個 task,Flink 提出了 Task Slot 的概念。

簡單的說,TaskManager會將自己節點上管理的資源分爲不同的Slot:固定大小的資源子集。這樣就避免了不同Job的Task互相競爭內存資源,但是需要主要的是,Slot只會做內存的隔離。沒有做CPU的隔離。

九、說說 Flink 的常用算子?

Flink 最常用的常用算子包括:Map:DataStream → DataStream,輸入一個參數產生一個參數,map的功能是對輸入的參數進行轉換操作。Filter:過濾掉指定條件的數據。KeyBy:按照指定的key進行分組。Reduce:用來進行結果彙總合併。Window:窗口函數,根據某些特性將每個key的數據進行分組(例如:在5s內到達的數據)

十、說說你知道的Flink分區策略?

什麼要搞懂什麼是分區策略。分區策略是用來決定數據如何發送至下游。目前 Flink 支持了8中分區策略的實現。
在這裏插入圖片描述
上圖是整個Flink實現的分區策略繼承圖:

GlobalPartitioner:數據會被分發到下游算子的第一個實例中進行處理。

ShufflePartitioner:數據會被隨機分發到下游算子的每一個實例中進行處理。

RebalancePartitioner:數據會被循環發送到下游的每一個實例中進行處理。

RescalePartitioner:這種分區器會根據上下游算子的並行度,循環的方式輸出到下游算子的每個實例。這裏有點難以理解,假設上游並行度爲2,編號爲A和B。下游並行度爲4,編號爲1,2,3,4。那麼A則把數據循環發送給1和2,B則把數據循環發送給3和4。假設上游並行度爲4,編號爲A,B,C,D。下游並行度爲2,編號爲1,2。那麼A和B則把數據發送給1,C和D則把數據發送給2。

BroadcastPartitioner:廣播分區會將上游數據輸出到下游算子的每個實例中。適合於大數據集和小數據集做Jion的場景。

ForwardPartitioner:ForwardPartitioner 用於將記錄輸出到下游本地的算子實例。它要求上下游算子並行度一樣。簡單的說,ForwardPartitioner用來做數據的控制檯打印。

KeyGroupStreamPartitioner:Hash分區器。會將數據按 Key 的 Hash 值輸出到下游算子實例中。

CustomPartitionerWrapper:用戶自定義分區器。需要用戶自己實現Partitioner接口,來定義自己的分區邏輯。例如:

static classCustomPartitionerimplementsPartitioner<String> {
      @Override
      publicintpartition(String key, int numPartitions) {
          switch (key){
              case "1":
                  return 1;
              case "2":
                  return 2;
              case "3":
                  return 3;
              default:
                  return 4;
          }
      }
  }
十一、Flink的並行度瞭解嗎?Flink的並行度設置是怎樣的?

Flink中的任務被分爲多個並行任務來執行,其中每個並行的實例處理一部分數據。這些並行實例的數量被稱爲並行度。

我們在實際生產環境中可以從四個不同層面設置並行度:

  • 操作算子層面(Operator Level)
  • 執行環境層面(Execution Environment Level)
  • 客戶端層面(Client Level)
  • 系統層面(System Level)

需要注意的優先級:算子層面>環境層面>客戶端層面>系統層面。

十二、Flink的Slot和parallelism有什麼區別?

官網上十分經典的圖:
在這裏插入圖片描述
slot是指taskmanager的併發執行能力,假設我們將 taskmanager.numberOfTaskSlots 配置爲3 那麼每一個 taskmanager 中分配3個 TaskSlot, 3個 taskmanager 一共有9個TaskSlot。
在這裏插入圖片描述
parallelism是指taskmanager實際使用的併發能力。假設我們把 parallelism.default 設置爲1,那麼9個 TaskSlot 只能用1個,有8個空閒。

十三、Flink有沒有重啓策略?說說有哪幾種?

Flink 實現了多種重啓策略。

  • 固定延遲重啓策略(Fixed Delay Restart Strategy)
  • 故障率重啓策略(Failure Rate Restart Strategy)
  • 沒有重啓策略(No Restart Strategy)
  • Fallback重啓策略(Fallback Restart Strategy)
十四、用過Flink中的分佈式緩存嗎?如何使用?

Flink實現的分佈式緩存和Hadoop有異曲同工之妙。目的是在本地讀取文件,並把他放在 taskmanager 節點中,防止task重複拉取。

val env = ExecutionEnvironment.getExecutionEnvironment

// register a file from HDFS
env.registerCachedFile("hdfs:///path/to/your/file", "hdfsFile")

// register a local executable file (script, executable, ...)
env.registerCachedFile("file:///path/to/exec/file", "localExecFile", true)

// define your program and execute
...
val input: DataSet[String] = ...
val result: DataSet[Integer] = input.map(new MyMapper())
...
env.execute()
十五、說說Flink中的廣播變量,使用時需要注意什麼?

我們知道Flink是並行的,計算過程可能不在一個 Slot 中進行,那麼有一種情況即:當我們需要訪問同一份數據。那麼Flink中的廣播變量就是爲了解決這種情況。

我們可以把廣播變量理解爲是一個公共的共享變量,我們可以把一個dataset 數據集廣播出去,然後不同的task在節點上都能夠獲取到,這個數據在每個節點上只會存在一份。

十六、說說Flink中的窗口?

來一張官網經典的圖:
在這裏插入圖片描述
Flink 支持兩種劃分窗口的方式,按照time和count。如果根據時間劃分窗口,那麼它就是一個time-window 如果根據數據劃分窗口,那麼它就是一個count-window。

flink支持窗口的兩個重要屬性(size和interval)

如果size=interval,那麼就會形成tumbling-window(無重疊數據) 如果size>interval,那麼就會形成sliding-window(有重疊數據) 如果size< interval, 那麼這種窗口將會丟失數據。比如每5秒鐘,統計過去3秒的通過路口汽車的數據,將會漏掉2秒鐘的數據。

通過組合可以得出四種基本窗口:

  • time-tumbling-window 無重疊數據的時間窗口,設置方式舉例:timeWindow(Time.seconds(5))
  • time-sliding-window 有重疊數據的時間窗口,設置方式舉例:timeWindow(Time.seconds(5), Time.seconds(3))
  • count-tumbling-window無重疊數據的數量窗口,設置方式舉例:countWindow(5)
  • count-sliding-window 有重疊數據的數量窗口,設置方式舉例:countWindow(5,3)
十七、說說Flink中的狀態存儲?

Flink在做計算的過程中經常需要存儲中間狀態,來避免數據丟失和狀態恢復。選擇的狀態存儲策略不同,會影響狀態持久化如何和 checkpoint 交互。

Flink提供了三種狀態存儲方式:MemoryStateBackend、FsStateBackend、RocksDBStateBackend。

十八、Flink 中的時間有哪幾類

Flink 中的時間和其他流式計算系統的時間一樣分爲三類:事件時間,攝入時間,處理時間三種。

如果以 EventTime 爲基準來定義時間窗口將形成EventTimeWindow,要求消息本身就應該攜帶EventTime。如果以 IngesingtTime 爲基準來定義時間窗口將形成 IngestingTimeWindow,以 source 的systemTime爲準。如果以 ProcessingTime 基準來定義時間窗口將形成 ProcessingTimeWindow,以 operator 的systemTime 爲準。

十九、Flink 中水印是什麼概念,起到什麼作用?

Watermark 是 Apache Flink 爲了處理 EventTime 窗口計算提出的一種機制, 本質上是一種時間戳。 一般來講Watermark經常和Window一起被用來處理亂序事件。

二十、Flink Table & SQL 熟悉嗎?TableEnvironment這個類有什麼作用

TableEnvironment是Table API和SQL集成的核心概念。

這個類主要用來:

  • 在內部catalog中註冊表
  • 註冊外部catalog
  • 執行SQL查詢
  • 註冊用戶定義(標量,表或聚合)函數
  • 將DataStream或DataSet轉換爲表
  • 持有對ExecutionEnvironment或StreamExecutionEnvironment的引用
二十、Flink SQL的實現原理是什麼?是如何實現 SQL 解析的呢?

首先大家要知道 Flink 的SQL解析是基於Apache Calcite這個開源框架。
在這裏插入圖片描述
基於此,一次完整的SQL解析過程如下:

  • 用戶使用對外提供Stream SQL的語法開發業務應用
  • 用calcite對StreamSQL進行語法檢驗,語法檢驗通過後,轉換成calcite的邏輯樹節點;最終形成calcite的邏輯計劃
  • 採用Flink自定義的優化規則和calcite火山模型、啓發式模型共同對邏輯樹進行優化,生成最優的Flink物理計劃
  • 對物理計劃採用janino codegen生成代碼,生成用低階API DataStream 描述的流應用,提交到Flink平臺執行

第二部分:Flink 面試進階篇

一、Flink是如何支持批流一體的?

在這裏插入圖片描述
本道面試題考察的其實就是一句話:Flink的開發者認爲批處理是流處理的一種特殊情況。批處理是有限的流處理。Flink 使用一個引擎支持了DataSet API 和 DataStream API。

二、Flink是如何做到高效的數據交換的?

在一個Flink Job中,數據需要在不同的task中進行交換,整個數據交換是有 TaskManager 負責的,TaskManager 的網絡組件首先從緩衝buffer中收集records,然後再發送。Records 並不是一個一個被髮送的,二是積累一個批次再發送,batch 技術可以更加高效的利用網絡資源。

三、Flink是如何做容錯的?

Flink 實現容錯主要靠強大的CheckPoint機制和State機制。Checkpoint 負責定時製作分佈式快照、對程序中的狀態進行備份;State 用來存儲計算過程中的中間狀態。

四、Flink 分佈式快照的原理是什麼?

Flink的分佈式快照是根據Chandy-Lamport算法量身定做的。簡單來說就是持續創建分佈式數據流及其狀態的一致快照。
在這裏插入圖片描述
核心思想是在 input source 端插入 barrier,控制 barrier 的同步來實現 snapshot 的備份和 exactly-once 語義。

五、Flink 是如何保證Exactly-once語義的?

Flink通過實現兩階段提交和狀態保存來實現端到端的一致性語義。 分爲以下幾個步驟:

  • 開始事務(beginTransaction)創建一個臨時文件夾,來寫把數據寫入到這個文件夾裏面
  • 預提交(preCommit)將內存中緩存的數據寫入文件並關閉
  • 正式提交(commit)將之前寫完的臨時文件放入目標目錄下。這代表着最終的數據會有一些延遲
  • 丟棄(abort)丟棄臨時文件

若失敗發生在預提交成功後,正式提交前。可以根據狀態來提交預提交的數據,也可刪除預提交的數據。

六、Flink 的 kafka 連接器有什麼特別的地方?

Flink源碼中有一個獨立的connector模塊,所有的其他connector都依賴於此模塊,Flink 在1.9版本發佈的全新kafka連接器,摒棄了之前連接不同版本的kafka集羣需要依賴不同版本的connector這種做法,只需要依賴一個connector即可。

七、說說 Flink的內存管理是如何做的?

Flink 並不是將大量對象存在堆上,而是將對象都序列化到一個預分配的內存塊上。此外,Flink大量的使用了堆外內存。如果需要處理的數據超出了內存限制,則會將部分數據存儲到硬盤上。Flink 爲了直接操作二進制數據實現了自己的序列化框架。

理論上Flink的內存管理分爲三部分:

  • Network Buffers:這個是在TaskManager啓動的時候分配的,這是一組用於緩存網絡數據的內存,每個塊是32K,默認分配2048個,可以通過“taskmanager.network.numberOfBuffers”修改
  • Memory Manage pool:大量的Memory Segment塊,用於運行時的算法(Sort/Join/Shuffle等),這部分啓動的時候就會分配。下面這段代碼,根據配置文件中的各種參數來計算內存的分配方法。(heap or off-heap,這個放到下節談),內存的分配支持預分配和lazy load,默認懶加載的方式。
  • User Code,這部分是除了Memory Manager之外的內存用於User code和TaskManager本身的數據結構。
八、說說 Flink的序列化如何做的?

Java本身自帶的序列化和反序列化的功能,但是輔助信息佔用空間比較大,在序列化對象時記錄了過多的類信息。

Apache Flink摒棄了Java原生的序列化方法,以獨特的方式處理數據類型和序列化,包含自己的類型描述符,泛型類型提取和類型序列化框架。

TypeInformation 是所有類型描述符的基類。它揭示了該類型的一些基本屬性,並且可以生成序列化器。TypeInformation 支持以下幾種類型:

  • BasicTypeInfo: 任意Java 基本類型或 String 類型
  • BasicArrayTypeInfo: 任意Java基本類型數組或 String 數組
  • WritableTypeInfo: 任意 Hadoop Writable 接口的實現類
  • TupleTypeInfo: 任意的 Flink Tuple 類型(支持Tuple1 to Tuple25)。Flink tuples 是固定長度固定類型的Java Tuple實現
  • CaseClassTypeInfo: 任意的 Scala CaseClass(包括 Scala tuples)
  • PojoTypeInfo: 任意的 POJO (Java or Scala),例如,Java對象的所有成員變量,要麼是 public 修飾符定義,要麼有 getter/setter 方法
  • GenericTypeInfo: 任意無法匹配之前幾種類型的類

針對前六種類型數據集,Flink皆可以自動生成對應的TypeSerializer,能非常高效地對數據集進行序列化和反序列化。

九、 Flink中的Window出現了數據傾斜,你有什麼解決辦法?

window產生數據傾斜指的是數據在不同的窗口內堆積的數據量相差過多。本質上產生這種情況的原因是數據源頭髮送的數據量速度不同導致的。出現這種情況一般通過兩種方式來解決:

  • 在數據進入窗口前做預聚合
  • 重新設計窗口聚合的key
十、 Flink中在使用聚合函數 GroupBy、Distinct、KeyBy 等函數時出現數據熱點該如何解決?

數據傾斜和數據熱點是所有大數據框架繞不過去的問題。處理這類問題主要從3個方面入手:

  • 在業務上規避這類問題
    例如一個假設訂單場景,北京和上海兩個城市訂單量增長几十倍,其餘城市的數據量不變。這時候我們在進行聚合的時候,北京和上海就會出現數據堆積,我們可以單獨數據北京和上海的數據。
  • Key的設計上
    把熱key進行拆分,比如上個例子中的北京和上海,可以把北京和上海按照地區進行拆分聚合。
  • 參數設置
    Flink 1.9.0 SQL(Blink Planner) 性能優化中一項重要的改進就是升級了微批模型,即 MiniBatch。原理是緩存一定的數據後再觸發處理,以減少對State的訪問,從而提升吞吐和減少數據的輸出量。
十一、Flink任務延遲高,想解決這個問題,你會如何入手?

在Flink的後臺任務管理中,我們可以看到Flink的哪個算子和task出現了反壓。最主要的手段是資源調優和算子調優。資源調優即是對作業中的Operator的併發數(parallelism)、CPU(core)、堆內存(heap_memory)等參數進行調優。作業參數調優包括:並行度的設置,State的設置,checkpoint的設置。

十二、Flink是如何處理反壓的?

Flink 內部是基於 producer-consumer 模型來進行消息傳遞的,Flink的反壓設計也是基於這個模型。Flink 使用了高效有界的分佈式阻塞隊列,就像 Java 通用的阻塞隊列(BlockingQueue)一樣。下游消費者消費變慢,上游就會受到阻塞。

十三、Flink的反壓和Strom有哪些不同?

Storm 是通過監控 Bolt 中的接收隊列負載情況,如果超過高水位值就會將反壓信息寫到 Zookeeper ,Zookeeper 上的 watch 會通知該拓撲的所有 Worker 都進入反壓狀態,最後 Spout 停止發送 tuple。

Flink中的反壓使用了高效有界的分佈式阻塞隊列,下游消費變慢會導致發送端阻塞。

二者最大的區別是Flink是逐級反壓,而Storm是直接從源頭降速。

十四、 Operator Chains(算子鏈)這個概念你瞭解嗎?

爲了更高效地分佈式執行,Flink會儘可能地將operator的subtask鏈接(chain)在一起形成task。每個task在一個線程中執行。將operators鏈接成task是非常有效的優化:它能減少線程之間的切換,減少消息的序列化/反序列化,減少數據在緩衝區的交換,減少了延遲的同時提高整體的吞吐量。這就是我們所說的算子鏈。

十五、 Flink什麼情況下才會把Operator chain在一起形成算子鏈?

兩個operator chain在一起的的條件:

  • 上下游的並行度一致
  • 下游節點的入度爲1 (也就是說下游節點沒有來自其他節點的輸入)
  • 上下游節點都在同一個 slot group 中(下面會解釋 slot group)
  • 下游節點的 chain 策略爲 ALWAYS(可以與上下游鏈接,map、flatmap、filter等默認是ALWAYS)
  • 上游節點的 chain 策略爲 ALWAYS 或 HEAD(只能與下游鏈接,不能與上游鏈接,Source默認是HEAD)
  • 兩個節點間數據分區方式是 forward(參考理解數據流的分區)
  • 用戶沒有禁用 chain
十六、 說說Flink1.9的新特性?
  • 支持hive讀寫,支持UDF
  • Flink SQL TopN和GroupBy等優化
  • Checkpoint跟savepoint針對實際業務場景做了優化
  • Flink state查詢
十七、消費kafka數據的時候,如何處理髒數據?

可以在處理前加一個fliter算子,將不符合規則的數據過濾出去。

第三部分:Flink 面試源碼篇

一、Flink Job的提交流程

用戶提交的Flink Job會被轉化成一個DAG任務運行,分別是:StreamGraph、JobGraph、ExecutionGraph,Flink中JobManager與TaskManager,JobManager與Client的交互是基於Akka工具包的,是通過消息驅動。整個Flink Job的提交還包含着ActorSystem的創建,JobManager的啓動,TaskManager的啓動和註冊。

二、Flink所謂"三層圖"結構是哪幾個"圖"?

一個Flink任務的DAG生成計算圖大致經歷以下三個過程:

  • StreamGraph 最接近代碼所表達的邏輯層面的計算拓撲結構,按照用戶代碼的執行順序向StreamExecutionEnvironment添加StreamTransformation構成流式圖。
  • JobGraph 從StreamGraph生成,將可以串聯合並的節點進行合併,設置節點之間的邊,安排資源共享slot槽位和放置相關聯的節點,上傳任務所需的文件,設置檢查點配置等。相當於經過部分初始化和優化處理的任務圖。
  • ExecutionGraph 由JobGraph轉換而來,包含了任務具體執行所需的內容,是最貼近底層實現的執行圖。
三、JobManger在集羣中扮演了什麼角色?

JobManager 負責整個 Flink 集羣任務的調度以及資源的管理,從客戶端中獲取提交的應用,然後根據集羣中 TaskManager 上 TaskSlot 的使用情況,爲提交的應用分配相應的 TaskSlot 資源並命令 TaskManager 啓動從客戶端中獲取的應用。

JobManager 相當於整個集羣的 Master 節點,且整個集羣有且只有一個活躍的 JobManager ,負責整個集羣的任務管理和資源管理。

JobManager 和 TaskManager 之間通過 Actor System 進行通信,獲取任務執行的情況並通過 Actor System 將應用的任務執行情況發送給客戶端。

同時在任務執行的過程中,Flink JobManager 會觸發 Checkpoint 操作,每個 TaskManager 節點 收到 Checkpoint 觸發指令後,完成 Checkpoint 操作,所有的 Checkpoint 協調過程都是在 Fink JobManager 中完成。

當任務完成後,Flink 會將任務執行的信息反饋給客戶端,並且釋放掉 TaskManager 中的資源以供下一次提交任務使用。

四、JobManger在集羣啓動過程中起到什麼作用?

JobManager的職責主要是接收Flink作業,調度Task,收集作業狀態和管理TaskManager。它包含一個Actor,並且做如下操作:

  • RegisterTaskManager: 它由想要註冊到JobManager的TaskManager發送。註冊成功會通過AcknowledgeRegistration消息進行Ack。
  • SubmitJob: 由提交作業到系統的Client發送。提交的信息是JobGraph形式的作業描述信息。
  • CancelJob: 請求取消指定id的作業。成功會返回CancellationSuccess,否則返回CancellationFailure。
  • UpdateTaskExecutionState: 由TaskManager發送,用來更新執行節點(ExecutionVertex)的狀態。成功則返回true,否則返回false。
  • RequestNextInputSplit: TaskManager上的Task請求下一個輸入split,成功則返回NextInputSplit,否則返回null。
  • JobStatusChanged: 它意味着作業的狀態(RUNNING, CANCELING, FINISHED,等)發生變化。這個消息由ExecutionGraph發送。
五、TaskManager在集羣中扮演了什麼角色?

TaskManager 相當於整個集羣的 Slave 節點,負責具體的任務執行和對應任務在每個節點上的資源申請和管理。

客戶端通過將編寫好的 Flink 應用編譯打包,提交到 JobManager,然後 JobManager 會根據已註冊在 JobManager 中 TaskManager 的資源情況,將任務分配給有資源的 TaskManager節點,然後啓動並運行任務。

TaskManager 從 JobManager 接收需要部署的任務,然後使用 Slot 資源啓動 Task,建立數據接入的網絡連接,接收數據並開始數據處理。同時 TaskManager 之間的數據交互都是通過數據流的方式進行的。

可以看出,Flink 的任務運行其實是採用多線程的方式,這和 MapReduce 多 JVM 進行的方式有很大的區別,Flink 能夠極大提高 CPU 使用效率,在多個任務和 Task 之間通過 TaskSlot 方式共享系統資源,每個 TaskManager 中通過管理多個 TaskSlot 資源池進行對資源進行有效管理。

六、TaskManager在集羣啓動過程中起到什麼作用?

TaskManager的啓動流程較爲簡單: 啓動類:org.apache.flink.runtime.taskmanager.TaskManager 核心啓動方法 : selectNetworkInterfaceAndRunTaskManager 啓動後直接向JobManager註冊自己,註冊完成後,進行部分模塊的初始化。

七、Flink 計算資源的調度是如何實現的?

TaskManager中最細粒度的資源是Task slot,代表了一個固定大小的資源子集,每個TaskManager會將其所佔有的資源平分給它的slot。

通過調整 task slot 的數量,用戶可以定義task之間是如何相互隔離的。每個 TaskManager 有一個slot,也就意味着每個task運行在獨立的 JVM 中。每個 TaskManager 有多個slot的話,也就是說多個task運行在同一個JVM中。

而在同一個JVM進程中的task,可以共享TCP連接(基於多路複用)和心跳消息,可以減少數據的網絡傳輸,也能共享一些數據結構,一定程度上減少了每個task的消耗。 每個slot可以接受單個task,也可以接受多個連續task組成的pipeline,如下圖所示,FlatMap函數佔用一個taskslot,而key Agg函數和sink函數共用一個taskslot:
在這裏插入圖片描述

八、簡述Flink的數據抽象及數據交換過程?

Flink 爲了避免JVM的固有缺陷例如java對象存儲密度低,FGC影響吞吐和響應等,實現了自主管理內存。MemorySegment就是Flink的內存抽象。默認情況下,一個MemorySegment可以被看做是一個32kb大的內存塊的抽象。這塊內存既可以是JVM裏的一個byte[],也可以是堆外內存(DirectByteBuffer)。

在MemorySegment這個抽象之上,Flink在數據從operator內的數據對象在向TaskManager上轉移,預備被髮給下個節點的過程中,使用的抽象或者說內存對象是Buffer。

對接從Java對象轉爲Buffer的中間對象是另一個抽象StreamRecord。

九、Flink 中的分佈式快照機制是如何實現的?

Flink的容錯機制的核心部分是製作分佈式數據流和操作算子狀態的一致性快照。 這些快照充當一致性checkpoint,系統可以在發生故障時回滾。 Flink用於製作這些快照的機制在“分佈式數據流的輕量級異步快照”中進行了描述。 它受到分佈式快照的標準Chandy-Lamport算法的啓發,專門針對Flink的執行模型而定製。
在這裏插入圖片描述
barriers在數據流源處被注入並行數據流中。快照n的barriers被插入的位置(我們稱之爲Sn)是快照所包含的數據在數據源中最大位置。例如,在Apache Kafka中,此位置將是分區中最後一條記錄的偏移量。 將該位置Sn報告給checkpoint協調器(Flink的JobManager)。

然後barriers向下遊流動。當一箇中間操作算子從其所有輸入流中收到快照n的barriers時,它會爲快照n發出barriers進入其所有輸出流中。 一旦sink操作算子(流式DAG的末端)從其所有輸入流接收到barriers n,它就向checkpoint協調器確認快照n完成。在所有sink確認快照後,意味快照着已完成。

一旦完成快照n,job將永遠不再向數據源請求Sn之前的記錄,因爲此時這些記錄(及其後續記錄)將已經通過整個數據流拓撲,也即是已經被處理結束。

十、簡單說說FlinkSQL的是如何實現的?

Flink 將 SQL 校驗、SQL 解析以及 SQL 優化交給了Apache Calcite。Calcite 在其他很多開源項目裏也都應用到了,譬如 Apache Hive, Apache Drill, Apache Kylin, Cascading。Calcite 在新的架構中處於核心的地位,如下圖所示。
在這裏插入圖片描述
構建抽象語法樹的事情交給了 Calcite 去做。SQL query 會經過 Calcite 解析器轉變成 SQL 節點樹,通過驗證後構建成 Calcite 的抽象語法樹(也就是圖中的 Logical Plan)。另一邊,Table API 上的調用會構建成 Table API 的抽象語法樹,並通過 Calcite 提供的 RelBuilder 轉變成 Calcite 的抽象語法樹。然後依次被轉換成邏輯執行計劃和物理執行計劃。

在提交任務後會分發到各個 TaskManager 中運行,在運行時會使用 Janino 編譯器編譯代碼後運行。

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