摘要:本文整理自螞蟻集團高階技術專家、螞蟻集團流計算平臺負責人李志剛,在 Flink Forward Asia 2022 平臺建設專場的分享。本篇內容主要分為四個部分:
- 主要挑戰
- 架構方案
- 核心技術介紹
- 未來規劃
一、主要挑戰
1.1 金融場景業務特點介紹
第一部分是時效性。金融場景追求時效性,特別是一些風控類的業務。首先,無論是當機還是其他風險情況,對業務的影響需要在秒級以內。其次,業務邏輯經常變更,不能影響時效性。最後,金融業務上下游依賴特別複雜,需要保證時效性不受到影響。
第二部分是正確性。金融資料在任何情況下,計算出來資料必須保證 100%正確。不能因為出現任何故障或者其他問題導致資料出錯,一旦資料出錯業務是不可接受的。當前很多業務都是先開發一套離線的資料模型,然後再開發實時的資料模型,這兩邊如果使用了不同的引擎,就這會導致資料核對相當困難。如果資料出現問題,我們需要像寫 JAVA 程式碼或者 C++程式碼一樣,有比較方便的除錯技術,發現問題所在,並進行修正。
第三部分是穩定性。螞蟻業務混布在大的物理叢集,有線上業務、離線業務、實時業務。在如此複雜、多變、混布的環境下,需要保證實時業務的穩定性,不能因為在雲化環境下的 K8s 元件或者其他元件影響實時業務。在申請特別大的 Pod 資源時,時間會特別長,就滿足不了實時業務的秒級標準。由於金融場景這些特點,我們提出創新的解決方案。
1.2 螞蟻流計算業務的基本情況
流計算規模大概在 78w Core,1.2w+個流作業,所有的叢集都執行在雲原生的叢集上。我們每年支撐的大促活動特別多,支援 15 次以上的大促活動。由於大促業務會經常變化,需要動態的彈性計算能力。
1.3 流計算業務的主要挑戰
近幾年,實時計算的技術處於穩定期,在彈性方面的挑戰有以下部分:
- 在大促常態化後,叢集可以隨時擴縮容。
- 在混布環境下,如何保證實時業務的穩定性。不能因為別的業務影響到實時計算穩定性。
- 流計算最核心的技術是最佳化狀態的效能。如何極致最佳化狀態效能,保證在任何大資料 Join 或者視窗的情況下沒有效能問題。
在易用性方面的挑戰有以下部分:
- 金融業務或者 BI 業務會隨時進行變更。如何在變更的情況下,快速重啟作業。
- 如何解決 SQL 作業除錯難問題。
- 如何做到流批統一。
1.4 應對挑戰的方法
在易用性方面,我們的解決方案是:
- 對實時計算平臺進行改造,提出熱啟動技術,解決在雲化環境下啟動慢的問題。
- 除錯 SQL 程式碼像在 IDEA 除錯 JAVA 程式碼一樣,解決排查資料困難的難題。
- 提出了基於 Flink 的流批統一的開發平臺。
在彈性方面,因為大促活動非常多,需要隨時擴縮容。所以我們的解決方案是:
- 基於 K8s 全面進行混布。
- 對 Flink 原生的 K8s 模式進行改造,提出雲原生的 Flink 叢集模式,避免由於 K8s 的問題導致影響實時業務穩定性。
二、架構方案
<p style="text-align:center">螞蟻實時計算平臺的架構圖</p>
最底層是 K8s 平臺,上一層是 Flink runtime 流批一體,螞蟻流計算的核心技術。提出了 K8s 叢集模式,採用開源社群 DophinScheduler 來實現工作流的排程。
核心技術包括記憶體最佳化、視窗最佳化、複雜多變的雲化環境下的智慧診斷(如何發現問題,問題的定位等);調節流計算作業的引數困難,因此提出基於 AI 學習演算法自動化解決調參問題;社群版本 RocksDB 狀態在某些情況下效能不好,我們做了狀態儲存 AntKV,相比 RocksDB 效能有兩倍的提升。
提出了除錯 SQL,像除錯 JAVA 程式碼一樣方便的功能;熱啟動解決作業啟動速度慢的問題;使用者只要寫一套 SQL 作業,指定跑流模式還是批模式,解決使用者不用寫兩套程式碼和其他開發的問題。
三、核心技術介紹
3.1 熱啟動技術
第一部分,為什麼需要熱啟動技術?
首先,開發實時作業的人都知道,修改作業引數,比如記憶體、併發等,改完之後重啟整個作業的時間特別長。特別在雲原生環境下,提交作業、申請 Pod、Pod 發下來、拉起映象等一系列流程,要花費幾分鐘。對於金融的實時業務來說很難接受。
其次是流量突變,在大促活動時,流量經常會發生變化。面對這種變化,我們需要快速適應它,改併發、記憶體、UDF 的情況經常發生。如果使用原生版本的 Flink,流程會特別長。從改,到提交,再到資源真正下來、作業跑起來等流程平均下來可能要四分鐘。
我們要怎麼解決呢?
我們提出了熱啟動技術,它的技術原理是使用者在前端介面,會請求一個 rest 服務。然後我們把修改後的執行計劃引數提供給 rest,會做一些前置校驗。接著把前置校驗後的引數和執行計劃,提到已經在跑的那個作業上。當它拿到新的執行計劃後,會把舊的暫停,然後 cancel 掉,恢復之後再慢慢建立出來。
總的來說,把新的執行計劃提上去,把舊的暫停,然後根據新的執行計劃生成新的部署模式。這麼做的好處是,繞過了前面的 SQL 編譯階段,包括 SQL 下載 Jar 包等複雜的流程,節省了 Pod 申請的時間,作業重啟操作在秒級完成。
<p style="text-align:center">熱啟動技術處理流程</p>
第一,將攜帶過來的新 JobGragh 和舊的 JobGragh 進行 merge,將舊的 JobGragh 中可以複用的資料進行回填到新的 JobGragh 中,包括 Jar 包、資源、檔案等。
第二,新的執行計劃生成後,把舊的 Task、中間的 Checkpoint Coordinator 中間的協調節點暫停掉。
第三,全部暫停後,把新的 JobGragh 排程起來,載入新的狀態。如果新的執行計劃排程失敗,需要有回滾技術,回滾到上一個正常狀態,保證使用者操作體驗的友好性。
<p style="text-align:center">熱啟動效果</p>
採用熱啟動技術,作業操作時間節省 90%以上。也就是說,原來大部分啟動作業需要 300 秒,現在使用熱啟動技術只需要兩秒,甚至一秒。
3.2 K8S 叢集模式
第二部分,為什麼需要 K8s 叢集模式?
- 上圖右側是開源社群版本提供的原生 K8s 提交 Flink 作業方式。首先 K8s Client 找 K8s 的 API Server 申請 K8s Service,K8s 啟動 K8s 的 deployment,然後拉起 Master 角色,再在 Master 裡申請 Flink 需要的 Pod,在 Pod 啟動 TaskManager 等流程。 這些複雜流程都依賴 K8s 元件,像 API Server、K8s Master,這就會導致單點。一旦 API Server 出現升級或者故障,就會影響作業的提交、運維等。在螞蟻實踐下來,歷史上出現過很多問題,碰到 K8s 叢集升級會導致實時作業不能提交、運維。
- 申請大的資源 Pod 時,時間就會特別漫長,甚至是五分鐘級的,對使用者體驗特別糟糕。
- 申請大 Pod 32 核 64GB 的經常失敗。
- 在實時業務大促活動時,不能動態的滿足業務新增資源需求。
- K8s API Server 效能是有瓶頸的。如果一次大批次建立幾百個 Pod,就會特別慢,容易超時。
為了解決以上問題,我們提出了 K8s 叢集模式。
<p style="text-align:center">K8s 叢集模式</p>
基本思路是先透過 Operator 向 K8s 申請大量資源,然後 ClusterManager 會把資源 hold 住。之後提交作業,就不用去找 K8s 的 API Server 或者 Master 申請 Service、Deployment 等資源。
這樣有什麼好處呢?
首先,可以減少或者不需要和 API Server、Master 打交道。其次,Pod 已經申請在機器上,就不用每次提交作業的時候,再申請新的 Pod,可以節省大量時間。
從上圖可以看到:由於 K8s 元件導致的問題,直接減少 95%。作業啟動的時間,從以前的 100 秒以上,減少到現在的 50 秒,再加上熱啟動技術,一兩秒就把作業啟動起來。資源利用率提高了 5%。
3.3 流批一體技術
第三部分,為什麼需要流批一體技術?
假如要開發 800 個指標的 BI 報表,後面發現了有 750 個要用離線開發,有 650 個要用 Flink 實時開發,中間還會有 500 個是重複的。重複的意思是離線也要做一套 SQL,實時也要做一套,但實際上它的業務邏輯是一模一樣的。這樣就會導致在資料開發的過程中,有很多重複工作。比如你用批引擎開發了一套,然後又用 Flink 實時引擎開發了一套,兩邊的 SQL 語法都不一樣,核對起來就特別困難。為了解決當前業務開發的痛點,就提出了螞蟻的流批一體技術。
如上圖所示,流批一體技術底層也在 K8s 上。再上一層我們用的是 Flink runtime。
在往上一層是外掛化 shuffle service、外掛化排程、外掛化狀態。
- 外掛化 shuffle service。shuffle service 在批計算非常重要,比如可以透過 shuffle service 解決在雲化環境下本地盤很小的問題。
- 外掛化排程。流和批的排程方式是不一樣的,排程也可以外掛化。
- 外掛化狀態。比如 RocksDB、記憶體、AntKV 型的狀態型別。
最上面是平臺的統一入口。使用者在統一入口上可以選擇統一寫一套 SQL,然後指定跑流還是批,這樣就解決了寫兩套 SQL 的難題。
<p style="text-align:center">Flink 除錯技術</p>
開發的時候可能要寫一個批的 SQL 和流的 SQL。如果資料經常有問題,寫 JAVA 程式碼、C++程式碼都知道,使用 IDE 或者 GDB 等工具,進行單步除錯。我們提出了對 SQL 程式碼單步除錯技術。方案有兩種:第一種方案,修改在 Flink 程式碼裡的所有運算元,包括批的運算元、流的運算元。然後在入口處增加 trace 程式碼,即在入口處把輸入資料打出來,在輸出的地方把輸出資料打出來。但這個方案有一個問題,會侵入原生的 Flink 引擎程式碼,導致程式碼很不優雅。第二種方案,位元組碼增強。
那麼位元組碼增強技術是怎麼做的呢?大家可能知道,平時從 IDE 裡除錯 JAVA 程式碼或別的程式碼時,實際上底層是透過 JAVA agent 技術進行除錯的。JAVA agent 是一門技術,透過這個技術可以把類代理掉。也就是在執行類之前 mock 掉新的類,然後自己控制這個新的類的行為。所以 JAVA agent 是透過把跑的類代理掉,然後透過代理跑真正要跑的類。從上圖右側可以看出,底層 Flink 引擎的程式碼是不會改的。所以透過代理的方式,在類載入之前透過 JAVA agent 代理出改寫的新類。
新類主要分為兩部分,第一部分是 Stream Operator。在執行完 Stream Operator 後,會插入輸入、輸出的方法,這樣就可以把運算元的輸入資料和輸出資料列印出來,即透過 Byte Buddy 來實現類的改寫。
這裡有一個問題,Flink 程式碼中有很多 codegen 程式碼,執行的時候會自動生成一些動態程式碼,就是把一些函式呼叫合成一個函式來執行的。但透過 JAVA agent 的 Byte Buddy 改寫類的時候,如果呼叫的是內部方法就會有問題。
從上圖可以看出,透過 JAVA agent 技術對 codegen 進行類的重寫。先把 codegen 程式碼下載一份到本地儲存起來,再透過 Byte Buddy 把它改寫,之後再插入輸入輸出程式碼,這樣就可以看到運算元的輸入輸出。就像除錯 JAVA 程式碼一樣,輸入是什麼、輸出是什麼、下節點的輸入是什麼、下節點的輸出是什麼,都可以詳細的列印出來。
四、未來規劃
第一,最佳化 Flink 批效能、支援全向量化計算。業界也有很多引擎在做全向量化計算,透過一些開源技術,比如 Databricks 公司的全向量化計算引擎,它的效能提升了兩倍以上。
第二,基於機器學習的自動化調優。由於流計算裡的引數較多,使用者用起來有些門檻,我們將透過機器學習的方法來解決自動化調引數問題。
第三,發展基於 Flink 的湖倉技術。流批統一後,儲存、計算、平臺都會統一,這樣一個入口就能解決使用者批、流、AI、學習等所有計算需求。
第四,雲化環境下智慧化診斷。雲化環境比較複雜,出現問題很難排查到具體問題。我們提出了一個智慧化診斷工具,它可以診斷到底層雲化環境的情況,比如機器、IP、機器負載等一系列情況,幫助使用者快速發現問題。
第五,流批混合部署下分時排程,提升利用率。流批不僅是引擎的統一,統一之後還要進一步提升資源的利用率,我們將在提升利用率的方向上繼續努力。
更多內容
活動推薦
阿里雲基於 Apache Flink 構建的企業級產品-實時計算Flink版現開啟活動:
99 元試用 實時計算Flink版(包年包月、10CU)即有機會獲得 Flink 獨家定製衛衣;另包 3 個月及以上還有 85 折優惠!
瞭解活動詳情:https://www.aliyun.com/product/bigdata/sc