螞蟻實時計算團隊的AntFlink提交攻堅之路
背景說明
Blink提交採用程式模型(包裝flink info/run命令)進行作業執行計劃的生成和作業的提交,這個基本是大資料計算引擎jstorm/spark/flink的共識,採用該方式的優點在於:
簡單:
使用者只需在自己的jar包中進行邏輯處理
引擎client負責以方法呼叫形式呼叫使用者main方法,然後編譯、提交 乾淨
程式模型使用者包用完銷燬,引擎版本包透過目錄隔離,不用考慮多版本問題。
技術演進
JVM 程式冷啟動層面最佳化
CDS
缺點:
僅能做到作業級別class複用:
原因:由於不同使用者作業很大可能依賴不同版本的包,做class快取時就會存在衝突。
間接帶來的問題:
每個作業需要快取大量class,對brs服務磁碟帶來巨大壓力(單個作業快取資料100MB以上)。
引入CDS清理機制:由於blink作業操作並不符合近期操作原則,此時後續作業操作cds命中不了。
AOT
缺點:
1、有較多限制,同時業內並沒有大規模使用:
暫不支援自定義ClassLoader 不支援CMS和ZGC
2、在我們場景測試下來,效果並不好
常駐服務生成
可以在blink rest server機器上,部署額外服務,負責生成plan/jobgraph(該服務和blink rest server同屬一個程式)
2、面臨核心痛點問題:
引擎版本間的相容性沒有保證,如何支援引擎多版本?
方案1:多程式方案(每個版本額外啟動一個常駐程式)
為了更快速地支援業務需求、快速迭代,我們團隊基本保持著半個月內發版的頻率。 為了儘快fix使用者問題,也會發布臨時版本 基於此,該方案不可行,否則會有大量進場。 方案2:多classloader方案
每個版本一個classloader,透過classloader做jar包隔離。
引擎多版本classloader方案實現思路
先做下簡要背景說明,作業包可分為下面4種情況
flink/lib依賴包
launcher包:包涵和引擎互動的包。如plan/jobgraph的生成、資源plan apply到jobgraph中、熱更新等
user jar使用者jar包:作業級別
connnector/backend外掛包
引擎當前為了支援平臺包優先順序高於引擎端而設計 可以當做使用者jar包來看
引入version classloader
可以簡單使用該classloader層級關係做隔離
由於每個作業的user jar包不同,則version classloader沒法複用
version classloader用完及釋放,此時和程式模型相比也就沒有太大區別,即效能會不好。
進一步引入reuqest level classloader
思路:
由於version級別的classloader,很少或者不變動,可複用。
request級別的classloader每次用完立即釋放
由於每個作業的使用者jar不同,沒法複用
launcher包的功能如何暴露給spring boot server(即blink rest server)使用呢?
spring boot server透過反射呼叫launcher包中的方法即可;
但是遵循以下規則即可: 由於該spring boot server和flink打交道透過launcher包,暴露的方法引數務必注意只能是jdk的類。 假如暴露的引數使用的是開源庫的類,哪怕version classloader和spring boot的app都有該jar包,但是此時類是不同的classloader載入了,會導致LinkageError問題。
優點:
version classloader和spring boot的app classloader沒有繼承關係,做到了乾淨隔離,因此該spring boot可以隨便依賴flink、甚至blink或者其他依賴,並不影響該服務; 將version classloader cache起來,複用率非常高;
當同版本更新發布或者測試環境希望僅僅更新某變更jar包做驗證時,透過監聽版本包目錄jar包變更,讓classloader快取失效,重新構建即可。
思考
為啥hive/spark/flink計算引擎都是透過自定義classloader方案,不採用類似上面的方案,如下圖1所示呢?
自定義classloader本質上是想解決使用者jar和引擎包衝突的問題 ; 但是使用者包和引擎包的互動: 1) 不可能像上面方案互動是單向的 上面方案:spring boot server僅單向訪問引擎launcher提供的介面; 而對於計算引擎來說,user code訪問引擎程式碼,引擎程式碼依賴user code的返回值是不可避免的。 2) 不可能像上面方案約束暴露的方法引數必須為jdk的類 否則使用者用起來一定很不爽; 基於上面兩點,計算引擎自然不可能使用下面圖1方案,而是圖2方案。
那麼計算引擎使用圖2的方案存在什麼問題呢?
由於相互互動,同一個類被不同的classloader載入然後相互引用,細節見筆者分析的文件連結[1]; 雖然flink對此做了很多改進,但是該問題無法根本解決;
比如引擎已經約束好哪些包是必須交給app classloader載入,防止被user classloader載入,那麼相互引用就不會有問題; 但不可能放進去很多,否則不同版本三方包衝突問題不就隨之而來。所以又暴露了使用者級別配置,使用者作業執行時報LinkageError問題,使用者把對應的包路徑塞入配置即可。但如果兩個classloader比如需要且引用,則沒有辦法解;
一般地,使用者外掛包該錯,很簡單,user jar打上依賴即可 但是有些情況,就比較繞。
先鋪墊下基礎知識, classloader類載入機制3原則:
全盤負責:所謂全盤負責,就是當一個類載入器負責載入某個Class時,該Class所依賴和引用其他Class也將由該類載入器負責載入,除非顯示使用另外一個類載入器來載入,如class.forName(, classloader)。
雙親委派:所謂的雙親委派,則是先讓父類載入器試圖載入該Class,只有在父類載入器無法載入該類時才嘗試從自己的類路徑中載入該類。通俗的講,就是某個特定的類載入器在接到載入類的請求時,首先將載入任務委託給父載入器,依次遞迴,如果父載入器可以完成類載入任務,就成功返回;只有父載入器無法完成此載入任務時,才自己去載入。
快取機制:快取機制將會保證所有載入過的Class都會被快取,當程式中需要使用某個Class時,類載入器先從快取區中搜尋該Class,只有當快取區中不存在該Class物件時,系統才會讀取該類對應的二進位制資料,並將其轉換成Class物件,存入緩衝區中。這就是為很麼修改了Class後,必須重新啟動JVM,程式所做的修改才會生效的原因。
此時B在程式啟動時,已經被父classloader載入。然後呼叫user code時,呼叫了A -> B -> C。由於B已經被父classloader載入,根據全盤負責原則此時C將交給父classloader載入,而父classloader沒有該C的jar包,則報ClassNotFoundExceotion。
但是使用者就很困惑,呼叫鏈明明是我的程式碼,而且我的包中已經有該class,為什麼會報這個錯呢?
解決辦法:
將B從父classpath去除。不可行,這樣父classloader在程式啟動前,就報ClassNotFoundExceotion了;
對user code中B 做shade改包名,一般該解法可行。但是比較trick的是使用者程式碼依賴的B不是依賴形式使用,而是以hard code編碼方式。如果讓使用者改動依賴程式碼,就很麻煩。
最終臨時是將該依賴打入到父classpath。但是對於引擎來說,就會有較大改動。如果是廣泛使用的包,又會很容易和其他使用者作業衝突。
舉例:A, B, C三個類依賴關係如下圖,但是類B對應的jar在兩個classloader中都有。
效果
透過多版本classloader方案最佳化後,經測試簡單作業plan耗時從10秒降低到1秒以內,有數量級級別的提升。
同時,從背景說明章節的圖中可看到絕大多數作業都為簡單作業;
作業提交和jobgraph生成解耦
blink 採用single job的session模式,提交作業時先拉起JobManager,然後同步方式等pod拉起之後(拉起需要申請pod比較耗時),之後在編譯作業生成jobgraph。如果發現不相容再退出JM作業,則前面耗時的工作白做了。
基於此,我們實現flink支援k8s per job模式,解耦作業提交和jobgraph生成。在客戶端提前生成jobgraph,如果不相容直接報錯了,無需拉起JobManager。
解耦後,可以做很多最佳化。運維態不變更作業。可以直接複用已經生成的jobgraph,無需再重複生成等。
同時,為了統一程式碼棧,降低開發成本,也擴充套件datastream作業支援per job模式提交。
結語
參考文件連結:
[1]%20《包衝突常見解法》
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70024922/viewspace-2931873/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- [杭州]螞蟻中介軟體團隊招Go工程師Go工程師
- 降本提效!註冊中心在螞蟻集團的蛻變之路
- 螞蟻轉崗面試之路面試
- 螞蟻金服微貸前端技術團隊 緊急招聘公告前端
- [深圳]螞蟻金服香港團隊招聘前端核心成員(全新市場、全新產品、全新團隊)前端
- 螞蟻集團:截止2023年螞蟻集團全球專利申請超3.2萬件
- 螞蟻金服的 3D 互動探索之路3D
- Flink 在螞蟻實時特徵平臺的深度應用特徵
- 螞蟻集團洪春濤 螞蟻高效能圖資料庫TuGraph-DB技術思考及實踐資料庫
- 深度 | 金融級訊息佇列的演進 — 螞蟻金服的實踐之路佇列
- [廣州]螞蟻金服中介軟體團隊誠招Go,地點廣州天河Go
- 螞蟻集團宣佈雲原生大規模叢集化機密計算框架 KubeTEE 開源框架
- 打造高效小團隊 - 團隊程式碼提交流程 && 規範
- 2024.08.28螞蟻
- 螞蟻集團萬級規模 K8s 叢集 etcd 高可用建設之路K8S
- 開發者解讀:為什麼螞蟻要用融合計算這種新計算模式?模式
- 螞蟻集團技術風險程式碼化平臺實踐(MaaS)
- 掘金 AMA:聽螞蟻金服 OceanBase 團隊的技術專家-- 慶濤聊資料庫那些事資料庫
- 螞蟻集團 Service Mesh 進展回顧與展望
- 實時智慧決策引擎在螞蟻金服風險管理中的實踐
- 深度 | 螞蟻金服自動化運維大規模 Kubernetes 叢集的實踐之路運維
- [從原始碼學設計]螞蟻金服SOFARegistry之時間輪的使用原始碼
- 螞蟻金服 DB Mesh 的探索與實踐
- 螞蟻實時低程式碼研發和流批一體的應用實踐
- 螞蟻金服 Service Mesh 深度實踐
- 螞蟻金服 Service Mesh 實踐探索
- 螞蟻集團上市招股書及簡要資料
- 《Oddity》團隊淺談「業餘遊戲設計師」的堅守與執念遊戲設計師
- 3.30螞蟻筆試筆試
- 螞蟻研究報告
- 攀登規模化的高峰 - 螞蟻集團大規模 Sigma 叢集 ApiServer 優化實踐APIServer優化
- 螞蟻金服正式成為 CNCF 雲原生計算基金會黃金會員
- ANTMINER螞蟻KS3-9.4T,強勁大算力S3
- 掘金 AMA:聽螞蟻金服 mPaaS 團隊技術專家--凝睇講客戶端推送 & 997 那些事客戶端
- 讓量子計算走近大眾:潘建偉、陸朝陽團隊證實盲量子計算的可行性
- 螞蟻金服 Service Mesh 實踐探索 | Qcon 實錄
- 螞蟻科技上市前的轉身
- DevOps 團隊如何防禦 API 攻擊devAPI