基於Flink打造實時計算平臺爲企業賦能

本文是清香白蓮在知乎的分享,很有借鑑意義,分享給大家。

原文地址:https://zhuanlan.zhihu.com/p/143169143

隨着互聯網技術的廣泛使用,信息的實時性對業務的開展越來越重要,特別是業務的異常信息,沒滯後一點帶來的就是直接的經濟損失。所以實時信息處理能力,越來越成爲企業的重要競爭力之一。Flink作爲業內公認的性能最好的實時計算引擎,以席捲之勢被各大公司用來進處理實時數據。然而Flink任務開發成本高,運維工作量大,面對瞬息萬變得業務需求,工程師往往是應接不暇。如果能有一套實時計算平臺,讓工程師或者業務分析人員通過簡單的SQL或者拖拽式操作就可以創建Flink任務,無疑可以快速提升業務的迭代能力。

1. 方法論—Lambda架構

如何設計大數據處理平臺呢?目前業界基本都是採用了Lambda架構(Lambda Architecture),該架構是由工程師南森·馬茨(Nathan Marz)在BackType和Twitter的大數據處理實踐中總結出的,示意圖如下。

Lambda架構

Lambda 共分爲三層,分別是批處理層(Batch Layer),速度處理層(Speed Layer),以及服務層(Serving Layer),用途分別如下:

  • 批處理層(Batch Layer),存儲管理主數據集和預先批處理計算好的視圖。這部分數據對及時性要求不高,但對準確性要求較高,會以批處理的方式同步到主庫中,處理過程通常以定時任務的形式存在。

  • 速度處理層(Speed Layer),負責處理實時數據。這部分數據需要實時的計算出結果,支持隨時供用戶查看,通常對準確性要求不高,主要通過流式計算引擎計算出結果。通常這些數據最終還是會通過批處理層入庫,並針對部分計算結果進行校驗。

  • 服務層(Serving Layer),數據進入到平臺以後,會進行存儲、同步、計算、分析等一系列分析計算過程。但是,最終都是需要提供給用戶使用的。針對業務需求的差異性,會有一個服務層將提煉出的數據以報表、儀表盤、API 接口等形式提供給用戶。

具體如何落實,主要有兩種方式,業務場景和通用組件來進行。

  • 自底向上:從業務場景需求出發,先做苦逼的數據搬運工,再從中總結出重複與最耗時的工作進行平臺化組件化,一步步堆磚頭添瓦,建立大數據平臺。這種方式可以讓數據針對具體的業務發揮作用,一開始效率非常低,需要大量的人肉工作,複雜的業務需求甚至需要資深的大數據開發工程師花費多個人日才能處理。在平臺建設的過程中,平臺也可能會面臨不斷重構的風險。工程團隊與業務部門工作耦合度太高,消耗太多溝通成本。

  • 自頂向下:先磨刀再砍柴,將大數據平臺中和具體的業務實現無關的通用功能組件抽離出來,做成簡單易用的數據產品,常見的需求可以通過SQL或者簡單的拖拽操作就能完成。這種方式處理需求效率高,門檻低,平臺做的好業務部們都可以自己分析數據,而且工程師與業務部門工作耦合度低,可以花更多時間再平臺建設上。但前期投入成本大,對產品經理/架構師的經驗要求非常高,要能使開發的產品再未來很好的業務使用需求,否則很可能變成造輪子。

這兩種方式各有優缺點,具體採用哪種方式,可實際根據業務的特點來選擇,但更多的是兩種方式穿插採用。

2. 功能設計

Flink提供了多層的API,越上層的API使用起來越簡單,但靈活性受限。越底層的API功能越強大,但對開發能力要求越高。

Flink API

2.1 SQL定義任務

根據Uber的使用經驗,70%的流處理任務都可以用SQL實現,再結合UDF,基本上一般需求都能解決,業內的大數據處理平臺上任務大部分都是也是以SQL+UDF的方式實現的,比如Hive,Dataworks,EasyCount與SparkSQL等。所以平臺開發語言以SQL爲主,可以讓沒有大數據開發能力的業務分析人員就可以使用。通過SQL定義Flink任務的設計如下:

  • 用DDL創建源表、(維表)、結果表;

  • 用DML定義計算任務。

  • 定義任務參數,如計算資源、最大並行度、udf的jar包位置等。

示例如下:

目前(Flink 1.10)已經實現了很多外部數據connector的DDL支持,對於不支持的數據源也可以通過擴展Calcite語法,自己解析DDL,將source或sink的目標對象映射成關係表。

Flink SQL得解析能力較弱,嵌套太多與太過複雜的SQL可能會解析失敗,所以INSERT語句不宜太複雜,可以添加對創建視圖的DDL的支持,簡化對SQL子查詢的多次嵌套引用。這項功能在未來的Flink中會得到支持,具體詳見FLIP-71。目前可以通過在TableEnvironment API中將SELECT語句的執行結果註冊爲Table對象來實現。

Table table = tableEnvironment.sqlQuery("SELECT user_id, user_name, login_time FROM user_login_log");
tableEnvironment.registerTable("table_name", table);

此外爲了方便debug,可以實現對select語句的支持,直接打印處理結果,而不是sink到外部存儲。

然而SQL並非是圖靈完備語言,對於部分複雜的功能需求,可能很難甚至無法用SQL實現。這時候平臺需要支持讓用戶將自幾開發的Jar包上傳到平臺去運行。

有了這兩項功能基本上已經可以滿足所有的使用需求了,產品在此基礎上可以做得更加傻瓜化,也就是通過拖拽式操作來定義流失計算任務。

2.2 用戶自定義Jar

對於某些計算任務可能通過SQL定義的話執行效率不高,通過Java或者Scala調用Flink更底層的API會更好,這時候我們希望平臺支持運行用戶自定義Jar。實現方案如下:

  • 要求用戶將Jar上傳到HDFS或者其他文件系統,並在任務配置裏面指定Jar的位置與執行命令;

  • 任務提交時,平臺會解析任務配置,從文件系統下載用戶Jar包,並執行任務的啓動命令。

2.3 拖拽式操作

爲了進一步降低使用門檻或者提升開發效率,可以實現通過拖拽式操作來定義任務。其原理時將數據處理常見的SELECT、JOIN、Filter、INSERT操作以及Sink、Source Table和各種UDF等定義成流程圖中的節點,用戶定義完流程圖後,平臺將流程圖轉化成SQL或者直接轉化成Flink代碼去執行。

3. 平臺架構設計

Flink通過對數據抽象成流表,實現了批流一體化的任務設計,即同一套代碼即可以用於批處理也可以用於處理流失數據,只需要修改數據源即可,處理邏輯完全不需要變。這就對實現Lamda架構具備了天然優勢,不再需要專門的批處理引擎。整個平臺的架構設計如下

  • 最上層爲UI界面,常見任務有相應的Op實現,自定義任務採用Flink SQL與UDF或者用戶Jar。

  • 執行引擎將前端定義的業務流程通過Flink SQL API翻譯成Flink Job。

  • 通過workflow對任務進行調度。

  • 在下面是負責執行計算的flink,以及它可能會調用的其他框架,如機器學習、NLP等任務會調用tensorflow,stanford cornlp等。

  • 最底層是物理集羣,除了Flink任務外,外部數據存儲系統如HDFS、Hbase、Kafka等也可以跑在這個公共集羣上。集羣的管理通過Yarn或者K8S實現。

4. 集羣資源管理

目前Flink已經實現了在Yarn集羣上的穩定運行,只要在Flink客戶端有Hadoop配置文件,就可以在客戶端通過Bash命令直接向Yarn集羣提交Flink任務,業內主要也是用Yarn來管理運行Flink任務的集羣資源的,如Uber的AthenaX。Flink on Yarn提供了兩種運行模式:

  • Session模式:先啓動一個Flink集羣,然後像該集羣提交任務,不同任務共用一個JobManager,即便沒有提交任務。由於需要預先啓動一個Flink集羣,即便沒有任務運行,這部分物理集羣資源也不能被回收;

  • Per-Job模式:爲每個任務單獨啓動一個集羣,每個任務獨立運行,物理集羣資源可以根據任務數量按需申請。

這兩種方式各有優缺點,一般而言,如果式以頻繁提交的短期任務,如批處理爲主,則適合Session模式,如果以長期運行的流式任務爲主,則適合用Per-Job模式。

K8S提供了更強大的集羣資源管理工具,具有更好的用戶體驗,已經發展爲雲服務廠商首選的資源管理與任務調度工具。Flink on K8S也是未來的發展趨勢,Flink社區也提供了相應的docker image與K8S資源配置文件,用於在K8S集羣中啓動Flink集羣運行Flink任務。在Flink 1.11中將支持直接從Flink客戶端提交任務到K8S集羣的功能。

5. 任務提交

有兩種模式可以將Flink任務提交到集羣去執行,即Client模式與Application模式,其中Application模式尚且不成熟,目前主要採用Client模式。

5.1 Client模式

在Client模式中,任務的提交需要有一個Flink Client,將任務需要的相關jar或者UDF都下載到本地,然後通過flink command編譯出任務的JobGraph,再將JobGraph與相關依賴提交給集羣去執行。目前業內主要有兩者實現方式,個人推薦第二種方式:

  • 啓動一個client,所有作業都通過這個client去提交的,因爲用的是同一個進程,所以不能加載 過多的jar包,還要注意不同任務之間UDF的衝突。

  • 爲每一個任務單獨啓動一個client進程(容器),在這個進程內下載需要的jar包,編譯出任務的JobGraph,並提交任務。這樣可以做到每個用戶用到的jar包或UDF不會衝突。

5.2 Application模式

在Client模式的缺點很顯著,如果請求量大的話,同一時刻Client需要下載大量jar包,並消耗大量CPU資源去編譯JobGraph,無論是網絡還是CPU都很容易成爲系統瓶頸。

針對Client模式的確定,社區提出了Application模式,只需要將任務所需要地資源文件上傳到集羣,在集羣中完成Flink JobGraph的編譯與任務地執行。Application模式社區也提出了兩種提交方式。

Flink-as-a-library

顧名思義,把flink本身作爲需要本地化的依賴,用戶程序的main函數就是一個自足的應用,因此可以直接用yarn命令來提交任務。

yarn jar MY_FLINK_JOB.jar myMainClass args...

但如果集羣是HA部署的話,同一時刻會有多個競爭者執行用戶程序的main函數,但最後被選中的leader只有一個,其他進程需要自己退出main函數。這種打斷進程的操作需要拋異常來實現,這點在編程上很不優雅。並且用戶對Flink集羣的生命週期管理受限於execute()的時間窗口。

所以社區最終採納的是下面的ClusterEntrypoint模式。

ClusterEntrypoint

實現一個新的ClusterEntrypoint 即 ApplicationClusterEntryPoint ,其生命週期與用戶任務的main函數一致。它主要做以下這些事情

  • 下載用戶jar與相關依賴資源;

  • 選舉leader去執行用戶程序的main函數;

  • 當用戶的main函數執行結束後終止該Flink集羣;

  • 確保集羣的HA與容錯性。

所以這種模式整個Flink集羣的生命週期由ApplicationClusterEntryPoint,擁有更大的靈活性。目前該功能尚且處於開發階段,預計會在Flink 1.11中發佈,具體進展詳見FLIP-85。

此外如果採用的是Session模式在跑Flink on Yarn的話,還可以通過Web API來提交任務。

6. 任務編排

對於單個任務或者流式任務的編排,主要就是每個任務的優先級問題,一般直接使用Yarn的調度功能就夠了。Yarn內置了三種調度器,並且支持優先級分數的設置與優先級ACL,一般需求都能滿足。

對於批處理任務,整個pipeline中一般存在多個子任務,不同子任務的執行次序存在依賴關係。這時候一般採用專業的workflow框架去編排這些子任務,workflow框架會對這些子任務進行拓撲排序,再去調度執行。常見的workflow有Airflow、Azkaban、Oozie、Conductor等,其中Airflow最爲流行,但是它是個python項目,workflow也是用python定義的,Azkaban社區也較爲活躍,原生支持Hadoop生態的任務,用戶體驗也較好。

7. 權限管理

平臺的建立最終是爲用戶服務的,這就需要考慮用戶的多樣性,可能是企業內部客戶、合作伙伴還有終端用戶。平臺需要根據不同用戶的不i同權限,提供不同的服務。在平臺建設過程中通常需要考慮:

  • 用戶的權限和角色管理。

  • 業務分組功能,針對業務分類、子分類對用戶進行劃分。

  • 根據數據功能進行不同的安全等級管理,包括流程管理、血緣關係的管理等。

  • 支持對元數據的檢索和瀏覽。

對於權限管理問題,Hadoop採用了Kerberos模塊來實現客戶端的身份認證與ACL,在Flink on Yarn佈署中,目前已經支持在flink客戶端實現Kerberos認證。

Kerberos只能提供服務器之間的認證,企業需要更加精細化的權限控制,還需要更加複雜的ACL模塊,甚至是企業自己實現的ACL模塊。在Flink 1.11中安全訪問控制模塊將被實現爲可插拔的而模塊,任何第三方的ACL模塊都可以輕鬆的集成進來。

8. 元數據管理

元數據的管理是數倉建設必不可少的部分,可以讓用戶知道平臺中存在哪些數據,他們的結構是什麼樣子,以及他們之間的關係。這樣一來,很多業務需求可以在已有的數據源的基礎上做些簡單的計算就可以滿足,減少了大量的重複計算工作。

8.1 表管理

Hive提供了豐富的元數據存儲查詢功能,Flink可以通過HiveCatalog來使用Hive的元存儲功能來實現跨session管理自己的元數據。用戶可以在某個任務裏面將它的Kafka或者ElasticSerach表的Schema存入Hive的元數據庫,然後在另一個任務中通過HiveCatalog直接獲取並使用這些表。

此外Flink還可以直接讀寫Hive表。

8.2 血緣關係管理

可以通過解析每個flink sql任務的source、sink表以及維表,這樣就可以建立這些表之間的血緣關係。

9. 日誌收集

日誌可以幫助我們觀察整個作業運行的情況,尤其是在job出問題之後,可以幫助我們復現問題現場,分析原因。對於本地無法debug的代碼,也可以通過運行日誌來輔助debug。所以收集任務的運行日誌,對平臺的建設是必不可少的。

由於flink任務的運行過程是先在客戶端編譯成JobGraph,再提交到Flink集羣運行,所以每個任務的日誌包括客戶端的提交日誌與任務在集羣上的運行日誌。

9.1 client日誌

Flink客戶端默認使用的日誌框架是log4j,可以通過修改conf/log4j-cli.properties文件對客戶端日誌的輸出進行設置。如進行如下設置可以將flink客戶端INFO級別的日誌輸出到控制檯與文件中。

log4j.rootLogger=INFO, file, console

可以將通過配置輸出到郵件、消息隊列或者數據庫等,也可以通過自定義的Appender或者公司統一的日服API上報到公司統一的日誌採集系統(如Flume、fluentd或者kafka等)。實際可根據平臺的架構與用戶量將客戶端日誌輸出到合適的位置供用戶查看。

9.2 cluster日誌

如果Flink是運行在 YARN 上,YARN 會幫我們做這件事,例如在 Container 運行完成時,YARN 會把日誌收集起來傳到 HDFS,可以用命令 yarn logs -applicationId <applicationId> 來查看相關日誌。

當然實際應用中不大可能讓用戶這樣查看日誌,一般還是要將日誌上報到專業的日誌服務框架如EFK中,用戶通過報表(如Kibana)或者API來查看,甚至配置郵件短信報警等。我們利用基於Flume的Log4j Appender 定製了自己的日誌收集器,從服務器異步發送日誌到Kafka中,再通過Kafka將日誌傳到日服的數據庫中(一般是Elasticsearch)。這樣可以儘可能地降低日誌採集對運行作業的影響。

如果Flink是運行再K8S 上,K8S本身並沒有提供日誌收集功能,目前一般是使用 fluentd來收集日誌。

fluentd是一個CNCF項目,它通過配置一些規則,比如正則匹配,就可以將logs目錄下的*.log 、*.out 及 *.gc日誌定期的上傳到 HDF 或者通過kafa寫入Elasticsearch 集羣,以此來解決我們的日誌收集功能。這也意味着在Flink集羣的POD裏面,除了運行TM或JM容器之外,我們需要再啓動一個運行着fluentd進程的容器(sidecar)。

10. 監控報警

在job出問題後,雖然日誌可以幫助我復現問題現場,分析原因。但最好還是可以實時監控任務的運行狀況,出現問題能及時報警,好做出應急措施,防止發生生產事故。目前業界已經有很多種監控系統解決方案,比如在阿里內部使用比較多的 Druid、開源InfluxDB 或者商用集羣版 InfluxDB、CNCF的 Prometheus 或者 Uber 開源的 M3 等等。

10.1 Prometheus

Prometheus是一個開源的,基於metrics(度量)的一個開源監控系統,誕生於2012年,主要是使用go語言開發的,並於2016年成爲成爲CNCF第二個成員,現已被大量的組織使用於工業生產環境中。

Prometheus在指標採集領域具備先天優勢,它提供了強大的數據模型和查詢語言,不僅可以很方便的查看系統的性能指標,還可以結合mtail從日誌中提取Metric指標,如Error出現次數,發送到時間序列數據庫,實現日誌告警。

對於Flink任務平臺需要支持監控以下指標

  • Flink本身的metric,可以將精確到每個subtask的operator,主要通過promethues push gateway上報。

  • Flink Cluster、task/operator IO、JVM 、Source、Sink、維表IO等。

  • 任務延遲,重啓次數等。

  • 自定義Metric,一般針對具體任務。

10.2 Grafana

有了Prometheus來監控任務後,還需要有一個可視化工具來展示Prometheus收集的指標。Grafana是Prometheus的最佳搭檔,它是一款用Go語言開發的開源數據可視化工具,可以做數據監控和數據統計,帶有告警功能,並且自帶權限管理功能。

Grafana支持的可視化方式有很多種,不過Graph、Table、Pie chart 這三種基本就已經滿足數據展現要求了。

使用起來也很簡單,跟商業的BI報表工具類似,先選擇圖表類型

然後選擇數據庫,寫好sql,就可以制定一個報表。

11. 總結

流失計算是在內存中事實進行的,數據很多時候也是直接來自生產環境,無論是框架還是業務邏輯都比批處理複雜多了。對平臺的建設也提出了嚴峻的挑戰,Flink作爲新一代的流失計算引擎,功能還在不斷完善中,剛開始使用必然會踩很多坑。當然踩坑的過程也是學習的過程,爲了趟過坑,你必然要做很多的技術調研,對平臺與很多組件的認知也會不斷加深。

推薦閱讀:

Flink State 誤用之痛,竟然 90% 以上的 Flink 開發都不懂

Flink 1.11中對接Hive新特性及如何構建數倉體系

基於 Flink SQL CDC 的實時數據同步方案

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