摘要:本文整理自移動軟體開發工程師謝磊在 Flink Forward Asia 2021 平臺建設專場的演講。本篇內容主要分為四個部分:
- 實時計算平臺建設
- 中移信令業務優化
- 穩定性實踐
- 未來方向的探索
中移(蘇州)軟體技術有限公司是中國行動通訊有限公司的全資子公司,公司定位為中國移動雲設施的構建者、雲服務的提供者、雲生態的繪製者。公司以移動云為運營中心,產品和服務在電信、政務、金融、交通等領域都有廣泛應用。
一、實時計算平臺介紹
實時計算引擎在移動雲的演進分為幾個階段:
- 2015 年到 16 年,我們使用的是第一代實時計算引擎 Apache Storm;
- 17 年我們開始調研 Apache Spark Streaming,它可以與自研框架進行整合,降低了運維壓力和維護成本;
- 18 年,使用者對雲端計算的需求越來越多,Storm 和 Spark已經無法很好地滿足業務。同時我們研究了流計算比較出名的幾篇文章,發現 Apache Flink 已經比較完整地具備了文中提到的一些語義;
- 19 年 - 20 年,我們開始實現雲服務,並把實時計算平臺上線至公有云和私有云;
- 20 年 - 21 年,我們開始調研實時數倉,並將 LakeHouse 上線移動雲。
目前 Flink 主要用於中移信令數字的處理、實時使用者畫像和埋點、實時數倉、實時運維監控、實時推薦以及移動雲的資料管道服務。
中移的實時計算平臺功能分為三大部分。
- 第一部分是服務管理,支援了任務生命週期的託管、Flink 和 SQL 作業、Spark Streaming 作業以及引擎多版本的支援;
- 第二部分是 SQL 的支援,提供了線上 Notebook 編寫、SQL 語法檢測、UDF 管理和後設資料管理;
- 第三部分是任務運維,支援實時任務的日誌檢索、實時效能指標採集以及訊息延遲報警和任務反壓報警等。
本文主要分享兩個核心設計:引擎多版本的設計和實時任務日誌檢索。
在日常有任務場景中,我們發現使用者程式除錯成本比較高,使用者嘗試新版本引擎的週期也比較長,此外無法規避使用者 hack 引擎的功能以及有些任務執行失敗但是沒有異常資訊,因此我們引入了引擎多版本設計。
多版本提交的流程如下:使用者的任務首先會提交到 rtp 服務,rtp 服務將使用者程式上傳到 HDFS 儲存,需要提交的時候再從 HDFS 拉回來提交到 Yarn 叢集。此類任務存在一個共性——作業中包含 Apache Flink 的核心包,這會導致很多問題。
因此,首先我們會與業務溝通,使作業包裡面不包含 Flink 的 core 包,但是這樣的收益比較小,所以我們在平臺側做了一次檢測,在使用者在上傳 jar 包的過程中主動檢測使用者包裡是否包含 core 包。如果發現作業包含了非法核心包,則會阻止使用者提交。
如此簡單的操作,卻為公司帶來了很大的收益:
- 第一,極大降低了一些低價值 bug 的定位成本;
- 第二,作業升級和回退版本更加方便;
- 第三,提高了作業的穩定性和安全性。
在日常業務場景中,我們需要通過日誌檢索來驗證流程的複雜邏輯。此外,原生 TM 的 UI 日誌打不開,容易卡死。以及 TM UI 不支援檢索,如上圖所示,當業務邏輯非常複雜的時候,Flink UI 無法提供以上功能。因此我們設計了實時任務日誌檢索功能。
實時任務日誌檢索的設計上需要考慮以下幾個問題:如何採集作業程式日誌,並將 TM 分佈在不同的機器上?如何不侵入作業進行採集日誌?如何限制作業列印大量無用日誌?
- 針對第一個問題,我們採用的push模式來降低採集日誌的壓力;
- 針對第二個問題,參考 spring 中的 AOP 機制,我們使用 AspectJWeaver,切入點是 log4j 的 input 或 event,之後把日誌傳送到 Sender;
- 針對第三個問題,我們採用的是 RateLimiter 來進行限流。
上圖是實時任務日誌檢索的整體設計。我們在原生的 TaskManager 下面加了 AOP 層,日誌會先通過 TaskManager 傳送 task,再傳送到 AOP。整個 AOP 對使用者無感知,因為採用了切面的方式。之後再傳送到 RateLimiter,再到 Sender,由 RateLimiter 進行限流的操作。接著日誌繼續傳送到 Kafka,做檢索的時候日誌會被髮送到 Elestic Search。
有了實時任務日誌檢索之後,業務程式不需要做任何改動就可以支援日誌的檢索。同時,開發人員可以便捷地驗證業務邏輯。得益於限流措施,也不會存在日誌儲存瓶頸。此外,也減輕了平臺管理的壓力。
二、中移信令業務優化
中國移動信令業務的出現是為了解決各級政府部門有關於移動使用者資源資料的需求,包括旅遊部門、應急部門、交通行業等,如交通規劃、交通調查、旅遊景區等重點區域的人口流量監測、流動人口監測管理等等。
依賴於中國移動手機使用者的高覆蓋率,利用行動通訊網路區域服務技術以及 GIS 技術,通過對移動使用者信令資料的統計,對城市人口數量、流動性等要素進行分析預測,為城市規劃、交通規劃、管理、資源配置、外來人口管理、政策制定等政府管理行為提供決策資料支援。
業務日均資料大概是 10PB,20 萬億/天,單條資料大小 0.5KB,包含了 2345G 上網資料、位置信令、省份城市、網路型別、介面型別等等。資料處理也比較複雜,要做資料加密、壓縮以及版本的統一等。上圖是處理信令數字時的條件和業務邏輯等。
將需求化繁為簡,應對到叢集上,就是一個上報閘道器。它會將各地的信令資料進行上傳,由 Flume 叢集進行資料接收,再傳輸到 Hadoop 叢集。上圖可以看到,Flume 與 Hadoop 之間存在一面物理牆。
隨著資料量增大,我們也遇到了很多問題:
- 第一,Flume 叢集會一直報警提示 Flume channel full;
- 第二,防火牆超限,也會進行報警;
- 第三,Flume 在寫 Kafka 的時候,Kafka 傳送端會傳送超時報警;
- 第四,下游處理信令資料的時候,Spark Streaming 處理是不穩定的。
上述問題總結起來可以分為兩大類:
- 第一類是寫入效能問題。Kafka 在寫入的時候頻繁超時,生產效能存在瓶頸。以及 Flume 在傳送資料時無法達到網路卡的上限速度;
- 第二類是架構設計問題。架構涉及的元件比較多導致維護的成本比較高;此外,元件職責不清晰,比如 Flume 中存在資料清洗的邏輯;還有 Spark 邏輯和處理邏輯複雜,存在多處 shuffle,處理效能不穩定。
首先要解決的是 PRO 寫入 Kafka 超時的問題。為了解決這個問題,我們進行了以下優化:
- 優化了防火牆埠;
- 優化了 Kafka 伺服器的一些效能引數;
- 在 Kafka 伺服器端進行了一些效能引數調優。
但是這並不能徹底解決 Flume 寫入 Kafka 超時的問題,於是我們把重點聚焦到客戶端。首先是客戶端的引數如何優化,尤其是 batch.size、buffer.memory 和 request.time.out 如何調優。其次是如何達到單機網路最大數網速,即單機情況下設定多少客戶端併發合適。
經過實踐我們發現,當 batch.size 為 256 兆,buffer.memory 為 128 兆時,效能會達到最優,但此時並沒有達到網路卡的最大速度。
於是我們進行了第二輪測試,增加了 compression.type,期望通過壓縮傳送的資料來提高傳送頻寬,但是結果並不符合我們的期望。
這是由於 Kafka 在低版本的時候存在一個問題,引數在它的驗證指令碼里的每個值都是一樣的,所以它的壓縮比會比較大。但是實際的生產環境中每條數字都是不一樣的,所以壓縮比非常小。
另外一個問題是如何達到網路卡的最大速度?最簡單的方式是增加並行度,但是並行度並不是越大越好。經過實踐發現,併發度為 4 的時候能達到網路卡的最大速度,超過 4 以後平均耗時會明顯增加,也會導致 Kafka 寫入超時。
第二點是 Flume channel full 的問題。
擴充套件服務的時候,服務的事務 API 處理是比較底層的,需要手動進行處理。此外服務的事務處理資料的時候,需要將資料進行拷貝。如上圖所示,當資料從 source 傳送到 channel 的時候,會把一份資料先 copy 到記憶體裡,從 channel 再傳送到 sink 的時候,又會從 channel 再 copy 到記憶體。這個過程中的兩次 copy 浪費了資源。而 Flink 做事務的時候是藉助於狀態管理,因而它的處理效能是比較穩定的。另外,Flink 擁有豐富的 source 和 sink,擴充套件性比較強。
因此,我們決定使用 Flink 代替 Flume 來解決問題。替換成 Flink 以後,提升了採集效能,解決了海量資料傳送效能瓶頸,穩定性顯著提高。同時,明確了元件職責,我們將原有的服務中存在的邏輯全部轉移至後端實時資料分解,讓採集層專注於資料匯聚,處理層專注於資料分揀。另外,我們統一了技術棧,端到端採用了 Flink 框架,獲得了更高的效能,也降低了開發和運維成本。
最終整體效能提升了 1/3 且降低了維護成本。
三、穩定性實踐
作業穩定性主要指服務故障以及處理方案,服務故障主要包括作業執行失敗、作業消費延遲、作業出現 OOM 以及作業異常重啟。對應的處理方案是可以將作業進行物理隔離,服務進行降級,加強資源監控以及對服務進行拆分。
而平臺維護人員最關心的是整體性的問題。
如果 ZooKeeper 叢集中有一臺伺服器出現了網路服務瞬斷,它也會引起大批量的任務重啟。Flink JobManager 會通過 ZooKeeper 來進行 leader 的選舉和發現 CheckpointID 的計數器管理。
於是我們分析了 ZooKeeper 網路狀態的轉換。客戶端在連線 ZooKeeper 叢集的時候,它的狀態先是 connected 狀態,網路瞬斷後它會變成 Suspended 狀態,Suspended 狀態會轉換為 lost 狀態,還會繼續轉換為 reconnected 狀態。Flink 在使用 ZooKeeper 的時候會依賴一個 curator2.0 元件,然而這個元件存在一個缺陷,遇到 Suspended 狀態就會直接將 leader 丟棄,這會導致大部分作業進行重啟,這對於我們的業務來說是不可接受的。
官方直到 Flink 1.14 版本才對此問題進行修復。在之前的版本下,需要重新寫 LeaderLatch,同時如果使用的是 Flink 1.8 版本,還需要同時修改 ZooKeeperCheckpointIDCounter。
四、未來方向的探索
未來,我們主要會在這兩個方向進行持續探索:
- 第一,資源利用方向。包括 Elastic Scaling 調研和 K8s Yunikorn 資源佇列調研。我們發現 Flink 上雲之後存在著資源佇列的問題,所以需要將使用者的資源進行分佇列管理;
- 第二,資料湖方向。首先是統一流批服務閘道器,做實時數倉的時候可能會採用不同的引擎,比如 Flink 和 Spark,它們屬於兩套不同的服務,所以需要做統一流批的服務閘道器。其次是資料血緣、資料資產和資料質量服務化。
更多 Flink 相關技術問題,可掃碼加入社群釘釘交流群
第一時間獲取最新技術文章和社群動態,請關注公眾號~