複雜分佈式架構下的計算治理之路:計算中間件Linkis

前言

在當前的複雜分佈式架構環境下,服務治理已經大行其道。但目光往下一層,從上層APP、Service,到底層計算引擎這一層面,卻還是各個引擎各自爲政,Client-Server模式緊耦合滿天飛的情況。如何做好“計算治理”,讓複雜環境下各種類型的大量計算任務,都能更簡潔、靈活、有序、可控的提交執行,和保障成功返回結果?計算中間件Linkis就是上述問題的最佳實踐。

一、複雜分佈式架構環境下的計算治理有什麼問題?

1. 什麼是複雜分佈式架構環境?

分佈式架構,指的是系統的組件分佈在通過網絡相連的不同計算機上,組件之間通過網絡傳遞消息進行通信和協調,協同完成某一目標。一般來說有水平(集羣化)和垂直(功能模塊切分)兩個拆分方向,以解決高內聚低耦合、高併發、高可用等方面問題。

多個分佈式架構的系統,組成分佈式系統羣,就形成了一個相對複雜的分佈式架構環境。通常包含多種上層應用服務,多種底層基礎計算存儲引擎。如下圖1所示:

圖片

2. 什麼是計算治理?

就像《微服務設計》一書中提到的,如同城市規劃師在面對一座龐大、複雜且不斷變化的城市時,所需要做的規劃、設計和治理一樣,龐大複雜的軟件系統環境中的各種區域、元素、角色和關係,也需要整治和管理,以使其以一種更簡潔、優雅、有序、可控的方式協同運作,而不是變成一團亂麻。

在當前的複雜分佈式架構環境下,大量APP、Service間的通信、協調和管理,已經有了從SOA(Service-Oriented Architecture)到微服務的成熟理念,及從ESB到Service Mesh的衆多實踐,來實現其從服務註冊發現、配置管理、網關路由,到流控熔斷、日誌監控等一系列完整的服務治理功能。服務治理框架的“中間件”層設計,可以很好的實現服務間的解耦、異構屏蔽和互操作,並提供路由、流控、狀態管理、監控等治理特性的共性提煉和複用,增強整個架構的靈活性、管控能力、可擴展性和可維護性。

但目光往下一層,你會發現在從APP、Service,到後臺引擎這一層面,卻還是各個引擎各自爲政,Client-Server模式緊耦合滿天飛的情況。在大量的上層應用,和大量的底層引擎之間,缺乏一層通用的“中間件”框架設計。類似下圖2的網狀。

圖片

計算治理,關注的正是上層應用和底層計算(存儲)引擎之間,從Client到Server的連接層範圍,所存在的緊耦合、靈活性和管控能力欠缺、缺乏複用能力、可擴展性、可維護性差等問題。要讓複雜分佈式架構環境下各種類型的計算任務,都能更簡潔、靈活、有序、可控的提交執行,和成功返回結果。如下圖3所示:

圖片

3. 計算治理問題描述

更詳細的來看計算治理的問題,可以分爲如下治(architecture,架構層面)和理(insight,細化特性)兩個層面。

(1)計算治理之治(architecture)-架構層面問題。

緊耦合問題,上層應用和底層計算存儲引擎間的CS連接模式。

所有APP& Service和底層計算存儲引擎,都是通過Client-Server模式相連,處於緊耦合狀態。以Analytics Engine的Spark爲例,如下圖4:

圖片

這種狀態會帶來如下問題:

  • 引擎client的任何改動(如版本升級),將直接影響每一個嵌入了該client的上層應用;當應用系統數量衆多、規模龐大時,一次改動的成本會很高;
  • 直連模式,導致上層應用缺乏,對跨底層計算存儲引擎實例級別的,路由選擇、負載均衡等能力;或者說依賴於特定底層引擎提供的特定連接方式實現,有的引擎有一些,有的沒有;
  • 隨着時間推移,不斷有新的上層應用和新的底層引擎加入進來,整體架構和調用關係將愈發複雜,可擴展性、可靠性和可維護性降低。

重複造輪子問題,每個上層應用工具系統都要重複解決計算治理問題。

每個上層應用都要重複的去集成各種client,創建和管理client到引擎的連接及其狀態,包括底層引擎元數據的獲取與管理。在併發使用的用戶逐漸變多、併發計算任務量逐漸變大時,每個上層應用還要重複的去解決多個用戶間在client端的資源爭用、權限隔離,計算任務的超時管理、失敗重試等等計算治理問題。

圖片

想象你有10個併發任務數過百的上層應用,不管是基於Web的IDE開發環境、可視化BI系統,還是報表系統、工作流調度系統等,每個接入3個底層計算引擎。上述的計算治理問題,你可能得逐一重複的去解決10*3=30遍,而這正是當前在各個公司不斷髮生的現實情況,其造成的人力浪費不可小覷。

擴展難問題,上層應用新增對接底層計算引擎,維護成本高,改動大。

在CS的緊耦合模式下,上層應用每新增對接一個底層計算引擎,都需要有較大改動。

以對接Spark爲例,在上層應用系統中的每一臺需要提交Spark作業的機器,都需要部署和維護好Java和Scala運行時環境和變量,下載和部署Spark Client包,且配置並維護Spark相關的環境變量。如果要使用Spark on YARN模式,那麼你還需要在每一臺需要提交Spark作業的機器上,去部署和維護Hadoop 相關的jar包和環境變量。再如果你的Hadoop集羣需要啓用Kerberos的,那麼很不幸,你還需要在上述的每臺機器去維護和調試keytab、principal等一堆Kerberos相關配置。

圖片

這還僅僅是對接Spark一個底層引擎。隨着上層應用系統和底層引擎的數量增多,需要維護的關係會是個笛卡爾積式的增長,光Client和配置的部署維護,就會成爲一件很令人頭疼的事情。

應用孤島問題,跨不同應用工具、不同計算任務間的互通問題。

多個相互有關聯的上層應用,向後臺引擎提交執行的不同計算任務之間,往往是有所關聯和共性的,比如需要共享一些用戶定義的運行時環境變量、函數、程序包、數據文件等。當前情況往往是一個個應用系統就像一座座孤島,相關信息和資源無法直接共享,需要手動在不同應用系統裏重複定義和維護。

典型例子是在數據批處理程序開發過程中,用戶在數據探索開發IDE系統中定義的一系列變量、函數,到了數據可視化系統裏往往又要重新定義一遍;IDE系統運行生成的數據文件位置和名稱,不能直接方便的傳遞給可視化系統;依賴的程序包也需要從IDE系統下載、重新上傳到可視化系統;到了工作流調度系統,這個過程還要再重複一遍。不同上層應用間,計算任務的運行依賴缺乏互通、複用能力。

圖片

(2)計算治理之理(insight)-細化特性問題:

除了上述的架構層面問題,要想讓複雜分佈式架構環境下,各種類型的計算任務,都能更簡潔、靈活、有序、可控的提交執行,和成功返回結果,計算治理還需關注高併發,高可用,多租戶隔離,資源管控,安全增強,計算策略等等細化特性問題。這些問題都比較直白易懂,這裏就不一一展開論述了。

二、基於計算中間件Linkis的計算治理-治之路(Architecture)

1. Linkis 架構設計介紹

  • 核心功能模塊與流程

計算中間件Linkis,是微衆銀行專門設計用來解決上述緊耦合、重複造輪子、擴展難、應用孤島等計算治理問題的。當前主要解決的是複雜分佈式架構的典型場景-數據平臺環境下的計算治理問題。

Linkis作爲計算中間件,在上層應用和底層引擎之間,構建了一層中間層。能夠幫助上層應用,通過其對外提供的標準化接口(如HTTP, JDBC, Java …),快速的連接到多種底層計算存儲引擎(如Spark、Hive、TiSpark、MySQL、Python等),提交執行各種類型的計算任務,並實現跨上層應用間的計算任務運行時上下文和依賴的互通和共享。且通過提供多租戶、高併發、任務分發和管理策略、資源管控等特性支持,使得各種計算任務更靈活、可靠、可控的提交執行,成功返回結果,大大降低了上層應用在計算治理層的開發和運維成本、與整個環境的架構複雜度,填補了通用計算治理軟件的空白。

圖片

圖片

要更詳細的瞭解計算任務通過Linkis的提交執行過程,我們先來看看Linkis核心的“計算治理服務”部分的內部架構和流程。如下圖:

圖片

計算治理服務:計算中間件的核心計算框架,主要負責作業調度和生命週期管理、計算資源管理,以及引擎連接器的生命週期管理。

公共增強服務:通用公共服務,提供基礎公共功能,可服務於Linkis各種服務及上層應用系統。

其中計算治理服務的主要模塊如下:

  • 入口服務Entrance,負責接收作業請求,轉發作業請求給對應的Engine,並實現異步隊列、高併發、高可用、多租戶隔離

  • 應用管理服務AppManager,負責管理所有的EngineConnManager和EngineConn,並提供EngineConnManager級和EngineConn級標籤能力;加載新引擎插件,向RM申請資源, 要求EM根據資源創建EngineConn;基於標籤功能,爲作業分配可用EngineConn。

  • 資源管理服務 ResourceManager,接收資源申請,分配資源,提供系統級、用戶級資源管控能力,併爲EngineConnManager級和EngineConn提供負載管控。

  • 引擎連接器管理服務 EngineConn Manager,負責啓動EngineConn,管理EngineConn的生命週期,並定時向RM上報資源和負載情況。

  • 引擎連接器EngineConn,負責與底層引擎交互,解析和轉換用戶作業,提交計算任務給底層引擎,並實時監聽底層引擎執行情況,回推相關日誌、進度和狀態給Entrance。

如上圖所示,一個作業的提交執行主要分爲以下11步:

1.上層應用向計算中間件提交作業,微服務網關SpringCloud Gateway接收作業並轉發給Entrance。

2. Entrance消費作業,爲作業向AppManager申請可用EngineConn。

3.如果不存在可複用的Engine,AppManager嘗試向ResourceManager申請資源,爲作業啓動一個新EngineConn。

4.申請到資源,要求EngineConnManager依照資源啓動新EngineConn

5.EngineConnManager啓動新EngineConn,並主動回推新EngineConn信息。

6. AppManager將新EngineConn分配給Entrance,Entrance將EngineConn分配給用戶作業,作業開始執行,將計算任務提交給EngineConn。

7.EngineConn將計算任務提交給底層計算引擎。

8.EngineConn實時監聽底層引擎執行情況,回推相關日誌、進度和狀態給Entrance,Entrance通過WebSocket,主動回推EngineConn傳過來的日誌、進度和狀態給上層應用系統。

9.EngineConn執行完成後,回推計算任務的狀態和結果集信息,Entrance將作業和結果集信息更新到JobHistory,並通知上層應用系統。

10.上層應用系統訪問JobHistory,拿到作業和結果集信息。

11.上層應用系統訪問Storage,請求作業結果集。

計算任務管理策略支持

在複雜分佈式環境下,一個計算任務往往不單會是簡單的提交執行和返回結果,還可能需要面對提交失敗、執行失敗、hang住等問題,且在大量併發場景下還需通過計算任務的調度分發,解決租戶間互相影響、負載均衡等問題。

Linkis通過對計算任務的標籤化,實現了在任務調度、分發、路由等方面計算任務管理策略的支持,並可按需配置超時、自動重試,及灰度、多活等策略支持。如下圖11。

圖片

基於Spring Cloud微服務框架

說完了業務架構,我們現在來聊聊技術架構。在計算治理層環境下,很多類型的計算任務具有生命週期較短的特徵,如一個Spark job可能幾十秒到幾分鐘就執行完,EngineConn(EnginConnector)會是大量動態啓停的狀態。前端用戶和Linkis中其他管理角色的服務,需要能夠及時動態發現相關服務實例的狀態變化,並獲取最新的服務實例訪問地址信息。同時需要考慮,各模塊間的通信、路由、協調,及各模塊的橫向擴展、負載均衡、高可用等能力。

基於以上需求,Linkis 實際是基於Spring Cloud微服務框架技術,將上述的每一個模塊/角色,都封裝成了一個微服務,構建了多個微服務組,整合形成了Linkis的完整計算中間件能力。如下圖12:

圖片

從多租戶管理角度,上述服務可區分爲租戶相關服務,和租戶無關服務兩種類型。租戶相關服務,是指一些任務邏輯處理負荷重、資源消耗高,或需要根據具體租戶、用戶、物理機器等,做隔離劃分、避免相互影響的服務,如Entrance, EnginConn(EnginConnector) Manager, EnginConn;其他如App Manger, Resource Manager、Context Service等服務,都是租戶無關的。

Eureka 承擔了微服務動態註冊與發現中心,及所有租戶無關服務的負載均衡、故障轉移功能。

Eureka有個侷限,就是在其客戶端,對後端微服務實例的發現與狀態刷新機制,是客戶端主動輪詢刷新,最快可設1秒1次(實際要幾秒才能完成刷新)。這樣在Linkis這種需要快速刷新大量後端EnginConn等服務的狀態的場景下,時效得不到滿足,且定時輪詢刷新對Eureka server、對後端微服務實例的成本都很高。

爲此我們對Spring Cloud Ribbon做了改造,在其中封裝了Eureka client的微服務實例狀態刷新方法,並把它做成滿足條件主動請求刷新,而不會再頻繁的定期輪詢。從而在滿足時效的同時,大大降低了狀態獲取的成本。如下圖:

圖片

Spring Cloud Gateway 承擔了外部請求Linkis的入口網關的角色,幫助在服務實例不斷髮生變化的情況下,簡化前端用戶的調用邏輯,快速方便的獲取最新的服務實例訪問地址信息。

Spring Cloud Gateway有個侷限,就是一個WebSocket客戶端只能將請求轉發給一個特定的後臺服務,無法完成一個WebSocket客戶端通過網關API對接後臺多個WebSocket微服務,而這在我們的Entrance HA等場景需要用到。

爲此Linkis對Spring Cloud Gateway做了相應改造,在Gateway中實現了WebSocket路由轉發器,用於與客戶端建立WebSocket連接。建立連接成功後,會自動分析客戶端的WebSocket請求,通過規則判斷出請求該轉發給哪個後端微服務,然後將WebSocket請求轉發給對應的後端微服務實例。詳見Github上Linkis的Wiki中,“Gateway的多WebSocket請求轉發實現”一文。

圖片

Spring Cloud OpenFeign提供的HTTP請求調用接口化、解析模板化能力,幫助Linkis構建了底層RPC通信框架。

但基於Feign的微服務之間HTTP接口的調用,只能滿足簡單的A微服務實例根據簡單的規則隨機選擇B微服務之中的某個服務實例,而這個B微服務實例如果想異步回傳信息給調用方,是無法實現的。同時,由於Feign只支持簡單的服務選取規則,無法做到將請求轉發給指定的微服務實例,無法做到將一個請求廣播給接收方微服務的所有實例。

Linkis基於Feign實現了一套自己的底層RPC通信方案,集成到了所有Linkis的微服務之中。一個微服務既可以作爲請求調用方,也可以作爲請求接收方。作爲請求調用方時,將通過Sender請求目標接收方微服務的Receiver;作爲請求接收方時,將提供Receiver用來處理請求接收方Sender發送過來的請求,以便完成同步響應或異步響應。如下圖示意。詳見Github上Linkis的Wiki中,“Linkis RPC架構介紹”一文。

圖片

至此,Linkis對上層應用和底層引擎的解耦原理,其核心架構與流程設計,及基於Spring Cloud微服務框架實現的,各模塊微服務化動態管理、通信路由、橫向擴展能力介紹完畢。

2.   解耦:Linkis如何解耦上層應用和底層引擎

Linkis作爲計算中間件,在上層應用和底層引擎之間,構建了一層中間層。上層應用所有計算任務,先通過HTTP、WebSocket、Java等接口方式提交給Linkis,再由Linkis轉交給底層引擎。原有的上層應用以CS模式直連底層引擎的緊耦合得以解除,因此實現瞭解耦。如下圖所示:

圖片

通過解耦,底層引擎的變動有了Linkis這層中間件緩衝,如引擎client的版本升級,無需再對每一個對接的上層應用做逐個改動,可在Linkis層統一完成。並能在Linkis層,實現對上層應用更加透明和友好的升級策略,如灰度切換、多活等策略支持。且即使後繼接入更多上層應用和底層引擎,整個環境複雜度也不會有大的變化,大大降低了開發運維工作負擔。

3.   複用:對於上層應用,Linkis如何凝練計算治理模塊供複用,避免重複開發

上層應用複用Linkis示例(Scriptis)

有了Linkis,上層應用可以基於Linkis,快速實現對多種後臺計算存儲引擎的對接支持,及變量、函數等自定義與管理、資源管控、多租戶、智能診斷等計算治理特性。

好處:

以微衆銀行與Linkis同時開源的,交互式數據開發探索工具Scriptis爲例,Scriptis的開發人員只需關注Web UI、多種數據開發語言支持、腳本編輯功能等純前端功能實現,Linkis包辦了其從存儲讀寫、計算任務提交執行、作業狀態日誌更新、資源管控等等幾乎所有後臺功能。基於Linkis的大量計算治理層能力的複用,大大降低了Scriptis項目的開發成本,使得Scritpis目前只需要有限的前端人員,即可完成維護和版本迭代工作。

如下圖,Scriptis項目99.5%的代碼,都是前端的JS、CSS代碼。後臺基本完全複用Linkis。

圖片

4.   快速擴展:對於底層引擎,Linkis如何以很小的開發量,實現新底層引擎快速對接

模塊化可插拔的計算引擎接入設計,新引擎接入簡單快速

對於典型交互式模式計算引擎(提交任務,執行,返回結果),用戶只需要buildApplication和executeLine這2個方法,沒錯,2個方法,2個方法,就可以完成一個新的計算引擎接入Linkis,代碼量極少。示例如下。

(1). AppManager部分:用戶必須實現的接口是ApplicationBuilder,用來封裝新引擎連接器實例啓動命令。

//用戶必須實現的方法: 用於封裝新引擎連接器實例啓動命令

def buildApplication(protocol:Protocol):ApplicationRequest  

(2). EngineConn部分:用戶只需實現executeLine方法,向新引擎提交執行計算任務:

 //用戶必須實現的方法:用於調用底層引擎提交執行計算任務
def executeLine(context: EngineConnContext,code: String): ExecuteResponse   

引擎相關其他功能/方法都已有默認實現,無定製化需求可直接複用。

5. 連通,Linkis如何打通應用孤島

通過Linkis提供的上下文服務,和存儲、物料庫服務,接入的多個上層應用之間,可輕鬆實現環境變量、函數、程序包、數據文件等,相關信息和資源的共享和複用,打通應用孤島。

圖片

  • Context Service上下文服務介紹

Context Service(CS)爲不同上層應用系統,不同計算任務,提供了統一的上下文管理服務,可實現上下文的自定義和共享。在Linkis中,CS需要管理的上下文內容,可分爲元數據上下文、數據上下文和資源上下文3部分。

圖片

元數據上下文,定義了計算任務中底層引擎元數據的訪問和使用規範,主要功能如下:

  • 提供用戶的所有元數據信息讀寫接口(包括Hive表元數據、線上庫表元數據、其他NOSQL如HBase、Kafka等元數據);

  • 計算任務內所需元數據的註冊、緩存和管理。

  • 數據上下文,定義了計算任務中數據文件的訪問和使用規範。管理數據文件的元數據。

  • 運行時上下文,管理各種用戶自定義的變量、函數、代碼段、程序包等。

  • 同時Linkis 也提供了統一的物料管理和存儲服務,上層應用可根據需要對接,從而可實現腳本文件、程序包、數據文件等存儲層的打通。

三、基於計算中間件Linkis的計算治理-理之路(Insight)

Linkis計算治理細化特性設計與實現介紹,在高併發、高可用、多租戶隔離、資源管控、計算任務管理策略等方面,做了大量細化考量和實現,保障計算任務在複雜條件下成功執行。

1.  計算任務的高併發支持

Linkis的Job基於多級異步設計模式,服務間通過高效的RPC和消息隊列模式進行快速通信,並可以通過給Job打上創建者、用戶等多種類型的標籤進行任務的轉發和隔離來提高Job的併發能力。通過Linkis可以做到1個入口服務(Entrance)同時承接超1萬+在線的Job請求。

多級異步的設計架構圖如下:

圖片

如上圖所示Job從GateWay到Entrance後,Job從生成到執行,到信息推送經歷了多個線程池,每個環節都通過異步的設計模式,每一個線程池中的線程都採用運行一次即結束的方式,降低線程開銷。整個Job從請求—執行—到信息推送全都異步完成,顯著的提高了Job的併發能力。

這裏針對計算任務最關鍵的一環Job調度層進行說明,海量用戶成千上萬的併發任務的壓力,在Job調度層中是如何進行實現的呢?

在請求接收層,請求接收隊列中,會緩存前端用戶提交過來的成千上萬計算任務,並按系統/用戶層級劃分的調度組,分發到下游Job調度池中的各個調度隊列;到Job調度層,多個調度組對應的調度器,會同時消費對應的調度隊列,獲取Job並提交給Job執行池進行執行。過程中大量使用了多線程、多級異步調度執行等技術。示意如下圖:

圖片

2. 其他細化特性

Linkis還在高可用、多租戶隔離、資源管控、計算任務管理策略等方面,做了很多細化考量和實現。篇幅有限,在這裏不再詳述每個細化特性的實現,可參見Github上Linkis的Wiki。後繼我們會針對Linkis的計算治理-理之路(Insight)的細化特性相關內容,再做專題介紹。

四、結語

基於如上解耦、複用、快速擴展、連通等架構設計優點,及高併發、高可用、多租戶隔離、資源管控等細化特性實現,計算中間件Linkis在微衆生產環境的應用效果顯著。極大的助力了微衆銀行一站式大數據平臺套件WeDataSphere的快速構建,且構成了WeDataSphere全連通、多租戶、資源管控等企業級特性的基石。

Linkis在微衆應用情況如下圖:

圖片

我們已將Linkis開源,Github repo地址:
https://github.com/WeBankFinTech/Linkis

歡迎對類似計算治理問題感興趣的同學,參與到計算中間件Linkis的社區協作中,共同把Linkis建設得更加完善和易用。

作者介紹:

邸帥,微衆銀行大數據平臺負責人,主導微衆銀行WeDataSphere大數據平臺套件的建設運營與開源,具備豐富的大數據平臺開發建設實踐經驗。

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