Apache-Flink深度解析-概述

王知無發表於2019-03-11

Apache-Flink深度解析-概述

                                                                          轉載自:https://dwz.cn/xrMCqbk5

摘要:
Apache Flink 的命脈 "命脈" 即生命與血脈,常喻極為重要的事物。系列的首篇,首篇的首段不聊Apache Flink的歷史,不聊Apache Flink的架構,不聊Apache Flink的功能特性,我們用一句話聊聊什麼是 Apache Flink 的命脈?我的答案是:Apache Flink 是以"批是流的特例"的認知進行系統設計的。

Apache Flink 的命脈

"命脈" 即生命與血脈,常喻極為重要的事物。系列的首篇,首篇的首段不聊Apache Flink的歷史,不聊Apache Flink的架構,不聊Apache Flink的功能特性,我們用一句話聊聊什麼是 Apache Flink 的命脈?我的答案是:Apache Flink 是以"批是流的特例"的認知進行系統設計的。

我們經常聽說 "天下武功,唯快不破",大概意思是說 "任何一種武功的招數都是有拆招的,唯有速度快,快到對手根本來不及反應,你就將對手KO了,對手沒有機會拆招,所以唯快不破"。 那麼這與Apache Flink有什麼關係呢?Apache Flink是Native Streaming(純流式)計算引擎,在實時計算場景最關心的就是"",也就是 "低延時"。

就目前最熱的兩種流計算引擎Apache Spark和Apache Flink而言,誰最終會成為No1呢?單從 "低延時" 的角度看,Spark是Micro Batching(微批式)模式,最低延遲Spark能達到0.5~2秒左右,Flink是Native Streaming(純流式)模式,最低延時能達到微秒。很顯然是相對較晚出道的 Apache Flink 後來者居上。 那麼為什麼Apache Flink能做到如此之 ""呢?根本原因是Apache Flink 設計之初就認為 "批是流的特例",整個系統是Native Streaming設計,每來一條資料都能夠觸發計算。相對於需要靠時間來積攢資料Micro Batching模式來說,在架構上就已經佔據了絕對優勢。


那麼為什麼關於流計算會有兩種計算模式呢?歸其根本是因為對流計算的認知不同,是"流是批的特例" 和 "批是流的特例" 兩種不同認知產物。

Micro Batching 模式

Micro-Batching 計算模式認為 "流是批的特例", 流計算就是將連續不斷的批進行持續計算,如果批足夠小那麼就有足夠小的延時,在一定程度上滿足了99%的實時計算場景。那麼那1%為啥做不到呢?這就是架構的魅力,在Micro-Batching模式的架構實現上就有一個自然流資料流入系統進行攢批的過程,這在一定程度上就增加了延時。具體如下示意圖:

Apache-Flink深度解析-概述

很顯然Micro-Batching模式有其天生的低延時瓶頸,但任何事物的存在都有兩面性,在大資料計算的發展歷史上,最初Hadoop上的MapReduce就是優秀的批模式計算框架,Micro-Batching在設計和實現上可以借鑑很多成熟實踐。

Native Streaming 模式

Native Streaming 計算模式認為 "批是流的特", 這個認知更貼切流的概念,比如一些監控類的訊息流,資料庫操作的binlog,實時的支付交易資訊等等自然流資料都是一條,一條的流入。Native Streaming 計算模式每條資料的到來都進行計算,這種計算模式顯得更自然,並且延時效能達到更低。具體如下示意圖:

Apache-Flink深度解析-概述

很明顯Native Streaming模式佔據了流計算領域 "低延時" 的核心競爭力,當然Native Streaming模式的實現框架是一個歷史先河,第一個實現
Native Streaming模式的流計算框架是第一個吃螃蟹的人,需要面臨更多的挑戰,後續章節我們會慢慢介紹。當然Native Streaming模式的框架實現上面很容易實現Micro-Batching和Batching模式的計算,Apache Flink就是Native Streaming計算模式的流批統一的計算引擎。

Apache Flink 按不同的需求支援Local,Cluster,Cloud三種部署模式,同時Apache Flink在部署上能夠與其他成熟的生態產品進行完美整合,如 Cluster模式下可以利用YARN(Yet Another Resource Negotiator)/Mesos整合進行資源管理,在Cloud部署模式下可以與GCE(Google Compute Engine), EC2(Elastic Compute Cloud)進行整合。

Local 模式

該模式下Apache Flink 整體執行在Single JVM中,在開發學習中使用,同時也可以安裝到很多端類裝置上。參考

Cluster模式

該模式是典型的投產的叢集模式,Apache Flink 既可以Standalone的方式進行部署,也可以與其他資源管理系統進行整合部署,比如與YARN進行整合。Standalone Cluster 參考 YARN Cluster 參考

這種部署模式是典型的Master/Slave模式,我們以Standalone Cluster模式為例示意如下:

Apache-Flink深度解析-概述

其中JM(JobManager)是Master,TM(TaskManager)是Slave,這種Master/Slave模式有一個典型的問題就是SPOF(single point of failure), SPOF如何解決呢?Apache Flink 又提供了HA(High Availability)方案,也就是提供多個Master,在任何時候總有一個JM服役,N(N>=1)個JM候選,進而解決SPOF問題,示意如下:
Apache-Flink深度解析-概述

在實際的生產環境我們都會配置HA方案,目前Alibaba內部使用的也是基於YARN Cluster的HA方案。

Cloud 模式

該模式主要是與成熟的雲產品進行整合,Apache Flink官網介紹了Google的GCE 參考,Amazon的EC2 參考,在Alibaba我們也可以將Apache Flink部署到Alibaba的ECS(Elastic Compute Service)。

完善的容錯機制

什麼是容錯

容錯(Fault Tolerance) 是指容忍故障,在故障發生時能夠自動檢測出來並使系統能夠自動回覆正常執行。當出現某些指定的網路故障、硬體故障、軟體錯誤時,系統仍能執行規定的一組程式,或者說程式不會因系統中的故障而中止,並且執行結果也不會因系統故障而引起計算差錯。

容錯的處理模式

在一個分散式系統中由於單個程式或者節點當機都有可能導致整個Job失敗,那麼容錯機制除了要保證在遇到非預期情況系統能夠"執行"外,還要求能"正確執行",也就是資料能按預期的處理方式進行處理,保證計算結果的正確性。計算結果的正確性取決於系統對每一條計算資料處理機制,一般有如下三種處理機制:

  • At Most Once:最多消費一次,這種處理機制會存在資料丟失的可能。

  • At Least Once:最少消費一次,這種處理機制資料不會丟失,但是有可能重複消費。

  • Exactly Once:精確一次,無論何種情況下,資料都只會消費一次,這種機制是對資料準確性的最高要求,在金融支付,銀行賬務等領域必須採用這種模式。

Apache Flink的容錯機制

Apache Flink的Job會涉及到3個部分,外部資料來源(External Input), Flink內部資料處理(Flink Data Flow)和外部輸出(External Output)。如下示意圖:
Apache-Flink深度解析-概述

目前Apache Flink 支援兩種資料容錯機制:

  • At Least Once

  • Exactly Once

其中 Exactly Once 是最嚴格的容錯機制,該模式要求每條資料必須處理且僅處理一次。那麼對於這種嚴格容錯機制,一個完整的Flink Job容錯要做到 End-to-End 的 容錯必須結合三個部分進行聯合處理,根據上圖我們考慮三個場景:

系統內部容錯

Apache Flink利用Checkpointing機制來處理容錯,Checkpointing的理論基礎 Stephan 在 Lightweight Asynchronous Snapshots for Distributed Dataflows 進行了細節描述,該機制源於有K. MANI CHANDY和LESLIE LAMPORT 發表的 Determining-Global-States-of-a-Distributed-System Paper。Apache Flink 基於Checkpointing機制對Flink Data Flow實現了At Least OnceExactly Once 兩種容錯處理模式。

Apache Flink Checkpointing的內部實現會利用 Barriers,StateBackend等後續章節會詳細介紹的技術來將資料的處理進行Marker。Apache Flink會利用Barrier將整個流進行標記切分,如下示意圖:
Apache-Flink深度解析-概述

這樣Apache Flink的每個Operator都會記錄當前成功處理的Checkpoint,如果發生錯誤,就會從上一個成功的Checkpoint開始繼續處理後續資料。比如 Soruce Operator會將讀取外部資料來源的Position實時的記錄到Checkpoint中,失敗時候會從Checkpoint中讀取成功的position繼續精準的消費資料。每個運算元會在Checkpoint中記錄自己恢復時候必須的資料,比如流的原始資料和中間計算結果等資訊,在恢復的時候從Checkpoint中讀取並持續處理流資料。

外部Source容錯

Apache Flink 要做到 End-to-EndExactly Once 需要外部Source的支援,比如上面我們說過 Apache Flink的Checkpointing機制會在Source節點記錄讀取的Position,那就需要外部資料提供讀取的Position和支援根據Position進行資料讀取。

外部Sink容錯

Apache Flink 要做到 End-to-EndExactly Once 相對比較困難,如上場景三所述,當Sink Operator節點當機,重新恢復時候根據Apache Flink 內部系統容錯 exactly once的保證,系統會回滾到上次成功的Checkpoin繼續寫入,但是上次成功Checkpoint之後當前Checkpoint未完成之前已經把一部分新資料寫入到kafka了. Apache Flink自上次成功的Checkpoint繼續寫入kafka,就造成了kafka再次接收到一份同樣的來自Sink Operator的資料,進而破壞了End-to-EndExactly Once 語義(重複寫入就變成了At Least Once了),如果要解決這一問題,Apache Flink 利用Two phase commit(兩階段提交)的方式來進行處理。本質上是Sink Operator 需要感知整體Checkpoint的完成,並在整體Checkpoint完成時候將計算結果寫入Kafka。

流批統一的計算引擎

批與流是兩種不同的資料處理模式,如Apache Storm只支援流模式的資料處理,Apache Spark只支援批(Micro Batching)模式的資料處理。那麼Apache Flink 是如何做到既支援流處理模式也支援批處理模式呢?

統一的資料傳輸層

開篇我們就介紹Apache Flink 的 "命脈"是以"批是流的特例"為導向來進行引擎的設計的,系統設計成為 "Native Streaming"的模式進行資料處理。那麼Apache FLink將批模式執行的任務看做是流式處理任務的特殊情況,只是在資料上批是有界的(有限數量的元素)。

Apache Flink 在網路傳輸層面有兩種資料傳輸模式:

  • PIPELINED模式 - 即一條資料被處理完成以後,立刻傳輸到下一個節點進行處理。

  • BATCH 模式 - 即一條資料被處理完成後,並不會立刻傳輸到下一個節點進行處理,而是寫入到快取區,如果快取寫滿就持久化到本地硬碟上,最後當所有資料都被處理完成後,才將資料傳輸到下一個節點進行處理。

對於批任務而言同樣可以利用PIPELINED模式,比如我要做count統計,利用PIPELINED模式能拿到更好的執行效能。只有在特殊情況,比如SortMergeJoin,這時候我們需要全域性資料排序,才需要BATCH模式。大部分情況流與批可用統一的傳輸策略,只有特殊情況,才將批看做是流的一個特例繼續特殊處理。

統一任務排程層

Apache Flink 在任務排程上流與批共享統一的資源和任務排程機制(後續章節會詳細介紹)。

統一的使用者API層

Apache Flink 在DataStremAPI和DataSetAPI基礎上,為使用者提供了流批統一的上層TableAPI和SQL,在語法和語義上流批進行高度統一。(其中DataStremAPI和DataSetAPI對流和批進行了分別抽象,這一點並不優雅,在Alibaba內部對其進行了統一抽象)。

求同存異

Apache Flink 是流批統一的計算引擎,並不意味著流與批的任務都走統一的code path,在對底層的具體運算元的實現也是有各自的處理的,在具體功能上面會根據不同的特性區別處理。比如 批沒有Checkpoint機制,流上不能做SortMergeJoin。

元件棧

我們上面內容已經介紹了很多Apache Flink的各種元件,下面我們整體概覽一下全貌,如下:
Apache-Flink深度解析-概述

TableAPI和SQL都建立在DataSetAPI和DataStreamAPI的基礎之上,那麼TableAPI和SQL是如何轉換為DataStream和DataSet的呢?

TableAPI&SQL到DataStrem&DataSet的架構

TableAPI&SQL最終會經過Calcite優化之後轉換為DataStream和DataSet,具體轉換示意如下:

Apache-Flink深度解析-概述

對於流任務最終會轉換成DataStream,對於批任務最終會轉換成DataSet。

ANSI-SQL的支援

Apache Flink 之所以利用ANSI-SQL作為使用者統一的開發語言,是因為SQL有著非常明顯的優點,如下:

Apache-Flink深度解析-概述

  • Declarative - 使用者只需要表達我想要什麼,不用關心如何計算。

  • Optimized - 查詢優化器可以為使用者的 SQL 生成最優的執行計劃,獲取最好的查詢效能。

  • Understandable - SQL語言被不同領域的人所熟知,用SQL 作為跨團隊的開發語言可以很大地提高效率。

  • Stable - SQL 是一個擁有幾十年歷史的語言,是一個非常穩定的語言,很少有變動。

  • Unify - Apache Flink在引擎上對流與批進行統一,同時又利用ANSI-SQL在語法和語義層面進行統一。

無限擴充套件的優化機制

Apache Flink 利用Apache Calcite對SQL進行解析和優化,Apache Calcite採用Calcite是開源的一套查詢引擎,實現了兩套Planner:

  • HepPlanner - 是RBO(Rule Base Optimize)模式,基於規則的優化。

  • VolcanoPlanner - 是CBO(Cost Base Optimize)模式,基於成本的優化。

Flink SQL會利用Calcite解析優化之後,最終轉換為底層的DataStrem和Dataset。上圖中 Batch rules和Stream rules可以根據優化需要無限新增優化規則。

Apache Flink 優秀的架構就像一座摩天大廈的地基一樣為Apache Flink 持久的生命力打下了良好的基礎,為打造Apache Flink豐富的功能生態留下無限的空間。

豐富的類庫和運算元

類庫

  • CEP - 複雜事件處理類庫,核心是一個狀態機,廣泛應用於事件驅動的監控預警類業務場景。

  • ML - 機器學習類庫,機器學習主要是識別資料中的關係、趨勢和模式,一般應用在預測類業務場景。

  • GELLY - 圖計算類庫,圖計算更多的是考慮邊和點的概念,一般被用來解決網狀關係的業務場景。

運算元

Apache Flink 提供了豐富的功能運算元,對於資料流的處理來講,可以分為單流處理(一個資料來源)和多流處理(多個資料來源)。

多流操作

如上通過UION和JOIN我們可以將多流最終變成單流,Apache Flink 在單流上提供了更多的操作運算元。

單流操作

將多流變成單流之後,我們按資料輸入輸出的不同歸類如下:

型別輸入輸出Table/SQL運算元DataStream/DataSet運算元
Scalar Function11Built-in & UDF,Map
Table Function1N(N>=0)Built-in & UDTFFlatMap
Aggregate FunctionN(N>=0)1Built-in & UDAFReduce

如上表格對單流上面操作做簡單歸類,除此之外還可以做 過濾,排序,視窗等操作,我們後續章節會逐一介紹。

存在的問題

Apache Flink 目前的架構還存在很大的優化空間,比如前面提到的DataStreamAPI和DataSetAPI其實是流與批在API層面不統一的體現,同時看具體實現會發現DataStreamAPI會生成Transformation tree然後生成StreamGraph,最後生成JobGraph,底層對應StreamTask,但DataSetAPI會形成Operator tree,flink-optimize模組會對Batch Plan進行優化,形成Optimized Plan 後形成JobGraph,最後形成BatchTask。具體示意如下:
Apache-Flink深度解析-概述

這種情況其實 DataStreamAPI到Runtime 和 DataSetAPI到Runtime的實現上並沒有得到最大程度的統一和複用。在這一點上面Aalibab 企業版的Flink在架構和實現上都進行了進一步優化。

Apache Flink元件架構優化

元件棧

Alibaba 對Apache Flink進行了大量的架構優化,如下架構是一直努力的方向,大部分功能還在持續開發中,具體如下:
Apache-Flink深度解析-概述

如上架構我們發現較大的變化是:

  • QP/QE/QO - 我們增加了QP/QE/QO層,在這一層進行統一的流和批的查詢優化和底層運算元的轉換。

  • DAG API - 我們在Runtime層面統一抽象API介面,在API層對流與批進行統一。

TableAPI&SQL到Runtime的架構

Apache Flink執行層是流批統一的設計,在API和運算元設計上面我們儘量達到流批的共享,在TableAPI和SQL層無論是流任務還是批任務最終都轉換為統一的底層實現。這個層面最核心的變化是批最終也會生成StreamGraph,執行層執行Stream Task,如下:
Apache-Flink深度解析-概述

小結

本篇概要的介紹了"批是流的特例"這一設計觀點是Apache Flink的"命脈",它決定了Apache Flink的執行模式是純流式的,這在實時計算場景的"低延遲"需求上,相對於Micro Batching模式佔據了架構的絕對優勢,同時概要的向大家介紹了Apache Flink的部署模式,容錯處理,引擎的統一性和Apache Flink的架構,最後和大家分享了Apache Flink的優化架構。

本篇沒有對具體技術進行詳細展開,大家只要對Apache Flink有初步感知,頭腦中知道Alibaba對Apache Flink進行了架構優化,增加了眾多功能就可以了,至於Apache Flink的具體技術細節和實現原理,以及Alibaba對Apache Flink做了哪些架構優化和增加了哪些功能後續章節會展開介紹!


  • 海量【java和大資料的面試題+視訊資料】整理在公眾號,關注後可以下載~
  • 更多大資料技術歡迎和作者一起探討~

                           Apache-Flink深度解析-概述


相關文章