峰值6億/秒,F(xiàn)link在京東的應(yīng)用與優(yōu)化實(shí)踐
導(dǎo)讀:Flink是目前流式處理領(lǐng)域的熱門引擎,在實(shí)時(shí)數(shù)倉(cāng)、實(shí)時(shí)風(fēng)控、實(shí)時(shí)推薦等多個(gè)場(chǎng)景有著廣泛的應(yīng)用。京東于2018年開始基于Flink+k8s深入打造高性能、穩(wěn)定、可靠、易用的實(shí)時(shí)計(jì)算平臺(tái),支撐了京東內(nèi)部多條業(yè)務(wù)線平穩(wěn)度過(guò)618、雙11多次大促。本文將分享京東Flink在應(yīng)用過(guò)程中遇到的問(wèn)題、挑戰(zhàn)和解決方案,在性能、穩(wěn)定性、易用性等方面對(duì)社區(qū)版Flink所做的深入的定制和優(yōu)化,以及未來(lái)的展望和規(guī)劃。今天的分享主要分為三個(gè)部分:
演進(jìn)和應(yīng)用
Flink優(yōu)化改進(jìn)
未來(lái)規(guī)劃
首先給大家介紹Flink在京東的發(fā)展歷程、平臺(tái)架構(gòu)、應(yīng)用和業(yè)務(wù)規(guī)模。
1. 發(fā)展歷程

京東在2014年基于storm打造了第一代流式處理平臺(tái),它可以較好的滿足數(shù)據(jù)處理的實(shí)時(shí)性要求。不過(guò)它有一些局限性,比如對(duì)于一些數(shù)據(jù)量特別大的場(chǎng)景,顯得有些力不從心。于是我們?cè)?017年引入了spark streaming,利用它的微批處理來(lái)應(yīng)對(duì)這種業(yè)務(wù)場(chǎng)景。隨著業(yè)務(wù)的發(fā)展和業(yè)務(wù)規(guī)模的擴(kuò)大,2018年我們引入了具有低延遲、高吞吐,同時(shí)支持狀態(tài)計(jì)算和恰好一次語(yǔ)義能力的新一代計(jì)算引擎Flink,同時(shí)開始基于k8s進(jìn)行實(shí)時(shí)計(jì)算的容器化升級(jí)。到2019年,實(shí)時(shí)計(jì)算全部跑在k8s上了,我們基于Flink1.8開始打造全新的SQL平臺(tái)。在2020、2021年,我們進(jìn)行了統(tǒng)一引擎的工作,并初步支持智能診斷和彈性伸縮,過(guò)去流處理是我們關(guān)注的重點(diǎn),我們平臺(tái)也開始支持批處理,整個(gè)平臺(tái)朝著流批一體智能化的方向演進(jìn)。
2. 平臺(tái)架構(gòu)

京東實(shí)時(shí)計(jì)算平臺(tái)以Flink為核心,部署在K8S集群上,狀態(tài)保存在HDFS中,用Zoopkeeper來(lái)實(shí)現(xiàn)高可用。支持京東內(nèi)部自研消息隊(duì)列JDQ,數(shù)據(jù)可以寫入Hive、HBase等存儲(chǔ)里。
3. 應(yīng)用場(chǎng)景

目前絕大多數(shù)實(shí)時(shí)場(chǎng)景都會(huì)通過(guò)Flink來(lái)計(jì)算,同時(shí)部分批處理的任務(wù)也會(huì)用Flink來(lái)支持。
4. 業(yè)務(wù)規(guī)模

京東在性能、穩(wěn)定性、易用性等方面對(duì)社區(qū)版Flink做了深入的定制和優(yōu)化工作。
1. 預(yù)覽拓?fù)?/span>

支持用戶提交作業(yè)之后可以預(yù)覽拓?fù)?,可以選中每一個(gè)算子進(jìn)行并行度設(shè)置和槽位的分組預(yù)覽,同時(shí)也可以清楚的看到網(wǎng)絡(luò)資源的使用情況等等,通過(guò)這樣的方式用戶可以非常方便的對(duì)任務(wù)進(jìn)行調(diào)優(yōu)。
在修改拓?fù)渑渲玫臅r(shí)候,我們通常需要知道算子和配置之間的穩(wěn)定關(guān)系,對(duì)于算子我們會(huì)根據(jù)通過(guò)用戶在算子中指定的uidHash或者uid,或者算子在拓?fù)渲械奈恢萌缜昂箨P(guān)系來(lái)生成一個(gè)唯一的key與配置構(gòu)成穩(wěn)定的對(duì)應(yīng)關(guān)系。用戶可以在線調(diào)整算子的配置并進(jìn)行預(yù)覽。

2. 背壓量化
當(dāng)下游消費(fèi)跟不上上游的數(shù)據(jù)生產(chǎn)時(shí),作業(yè)會(huì)遇到一些瓶頸,可以通過(guò)Flink UI的Monitor看到背壓的高低和位置。這種方式存在一些問(wèn)題:
有的場(chǎng)景下采集不到背壓
無(wú)法跟蹤歷史背壓情況
背壓影響不直觀
大并行度時(shí)被壓采集壓力大

還可以通過(guò)Flink Task Metries來(lái)查看被壓情況,這種方式可以解決追蹤歷史背壓的問(wèn)題,支持將背壓情況采集到普米修斯或其他服務(wù)里進(jìn)行歷史的查看。但仍存在下面一些問(wèn)題:
不同的Flink版本指標(biāo)差異
分析背壓有一定門檻
背壓影響不直觀

優(yōu)化方案:
采集背壓發(fā)生的位置、時(shí)間和次數(shù)指標(biāo)作為指標(biāo)上報(bào)
背壓監(jiān)控+運(yùn)行拓?fù)?,精?zhǔn)反映背壓現(xiàn)場(chǎng)情況
3. 文件系統(tǒng)支持多配置
改進(jìn)背景:業(yè)務(wù)人員希望把狀態(tài)放在公共集群,同時(shí)又想讀取業(yè)務(wù)集市里業(yè)務(wù)數(shù)據(jù);用戶希望把數(shù)據(jù)從一個(gè)OSS存儲(chǔ)讀出,處理后到另一個(gè)OSS存儲(chǔ)。

解決方案:基于Flink文件系統(tǒng)的基本機(jī)制進(jìn)行改進(jìn),使用不同的schema將不同的服務(wù)的配置進(jìn)行隔離。

4. 數(shù)據(jù)分發(fā)優(yōu)化
優(yōu)化背景:在算子上下游并行度不一樣時(shí),在Flink中默認(rèn)數(shù)據(jù)分發(fā)機(jī)制是rebalance,即將所有數(shù)據(jù)依次分發(fā)給下游所有的并行度,這種分發(fā)機(jī)制一般情況下都是可以很好的工作的。不過(guò),對(duì)于一些特殊場(chǎng)景,可以進(jìn)一步優(yōu)化提升計(jì)算性能。

①?采用基于負(fù)載的動(dòng)態(tài)的rebalance
當(dāng)下游算子的各個(gè)Task負(fù)載不均衡時(shí),處理最慢的Task將會(huì)成為計(jì)算的瓶頸,為此我們開發(fā)了基于下游負(fù)載情況進(jìn)行動(dòng)態(tài)分發(fā)的動(dòng)態(tài)rebalance機(jī)制:上游算子Task在分發(fā)數(shù)據(jù)時(shí),優(yōu)先發(fā)送給下游處理最快的Task,而不是采用round-robin的方式均分發(fā)送。通過(guò)這種優(yōu)化,我們經(jīng)過(guò)大量測(cè)試發(fā)現(xiàn),在負(fù)載不均衡的場(chǎng)景中計(jì)算性能可以提升近一倍。
②?使用rescale代替rebalance
如果上游并行度數(shù)據(jù)比較均勻且上下游并行度數(shù)量成比例,此時(shí)就可以采用rescale代替rebalance機(jī)制提升性能。實(shí)現(xiàn)機(jī)制是將上游每個(gè)并行度的輸出數(shù)據(jù)按照下游并行度進(jìn)行分區(qū)分發(fā),不是分發(fā)到下游所有并行度,比如上游算子并行度為2,下游算子并行度為4,就可以將上游的第一個(gè)并行度的數(shù)據(jù)分發(fā)到下游前2個(gè)并行度,上游第二個(gè)并行度的數(shù)據(jù)分發(fā)到下游后2個(gè)并行度。
這種分發(fā)機(jī)制不僅減少了網(wǎng)絡(luò)buffer,提高了網(wǎng)絡(luò)效率,還降低了上下游的相關(guān)程度,有利于使用Flink的region機(jī)制進(jìn)行故障恢復(fù)。
5. 最后一次CP作為SP
優(yōu)化背景:在異常情況下需要進(jìn)行任務(wù)重啟或遷移時(shí),作業(yè)來(lái)不及或者根本無(wú)法完成savepoint,導(dǎo)致會(huì)有較長(zhǎng)時(shí)間的狀態(tài)丟失。
為了解決這個(gè)問(wèn)題,我們開發(fā)了最后一次cp作為sp的功能,并與產(chǎn)品平臺(tái)JRC進(jìn)行了深度集成?;具^(guò)程是這樣的:在任務(wù)停止時(shí),會(huì)將最后一次checkpoint持久化;在下一次任務(wù)啟動(dòng)時(shí),用戶可以選擇從最新cp恢復(fù)任務(wù);在任務(wù)運(yùn)行起來(lái)并完成一次cp后,會(huì)將上次持久化的cp刪除掉,釋放存儲(chǔ)空間。

6. 其他優(yōu)化

HDFS優(yōu)化:合并小文件,降低RPC調(diào)用等。
讀取本地文件時(shí)增加buffer用于緩沖提高讀寫性能。
zk防抖:在網(wǎng)絡(luò)抖動(dòng)、計(jì)算節(jié)點(diǎn)負(fù)載壓力較大或zk服務(wù)短暫無(wú)響應(yīng)時(shí),會(huì)導(dǎo)致job manager / task manager與zk短暫斷開連接導(dǎo)致任務(wù)重啟,通過(guò)防抖優(yōu)化可以避免任務(wù)重啟,提高穩(wěn)定性。
任務(wù)局部恢復(fù):支持作業(yè)Failover時(shí)只恢復(fù)個(gè)別失敗的Task,從而避免整個(gè)任務(wù)重啟的巨大開銷,適用于可以容忍少量數(shù)據(jù)丟失的場(chǎng)景。
集群多任務(wù)調(diào)度隔離:把同一集群中不同任務(wù)的算子調(diào)度到不同taskManager中避免不同任務(wù)相互影響。
日志增強(qiáng):支持日志分離、日志級(jí)別動(dòng)態(tài)配置等
SQL擴(kuò)展:窗口支持增量計(jì)算, 支持offset
智能診斷:支持對(duì)作業(yè)大多數(shù)場(chǎng)景進(jìn)行自動(dòng)分析診斷,給出問(wèn)題診斷結(jié)果和建議。

流批一體是今年比較火的一個(gè)方向,在一個(gè)引擎里同時(shí)支持低延遲的流處理和高性能的批處理,可以做到架構(gòu)統(tǒng)一,代碼復(fù)用,降低用戶使用成本,同時(shí)避免流批割裂帶來(lái)的口徑不統(tǒng)一的問(wèn)題。目前部分業(yè)務(wù)場(chǎng)景已經(jīng)落地。
第二個(gè)方向就是提高穩(wěn)定性。Flink任務(wù)恢復(fù)機(jī)制有較大的開銷,無(wú)論是全部重啟還是region重啟,都會(huì)對(duì)業(yè)務(wù)有一定的影響。如何在容器環(huán)境下進(jìn)一步提高任務(wù)恢復(fù)的速度,減少對(duì)業(yè)務(wù)的影響,是我們努力的一個(gè)方向。
第三個(gè)方向是智能運(yùn)維,如何做到對(duì)任務(wù)的智能診斷,根據(jù)作業(yè)運(yùn)行情況進(jìn)行參數(shù)自動(dòng)調(diào)整、彈性伸縮等,這是我們目前正在進(jìn)行中的工作。
第四個(gè)方向是AI的探索實(shí)現(xiàn)。AI也是目前比較火的一個(gè)方向,如何結(jié)合Flink更好地實(shí)現(xiàn)AI實(shí)時(shí)化、智能化的場(chǎng)景也是我們將來(lái)要發(fā)力的一個(gè)方向。
