1. 程式人生 > >大眾點評ETL資料傳輸平臺整體架構

大眾點評ETL資料傳輸平臺整體架構

1.1 平臺整體架構

該企業的資料傳輸平臺主要由三部分構成:

1) 一部分是基於QuartzDocker的排程系統。主要功能是負責排程和執行ETL任務。監視和變換當前任務例項的狀態,當例項狀態發生變化或者符合變化條件時主動更新資料庫和記憶體中例項狀態。

2) 一部分是資料交換工具Wormhole。主要用來多個數據庫之間資料的交換,是ETL平臺的基礎。這個工具我們一般把它整合到Docker映象中,同時我們還集成了各種指令碼任務和Java執行環境的映象,具體的選擇取決於任務的型別。

3) 最後是基於Web的圖形化工具。主要用來幫助使用者手工配置任務、監控任務執行狀態和日誌檢視進行除錯。對任務和例項進行管理。管理操作包括掛起,預跑,置為成功,修改

,殺死正在執行的例項等。

 

          4.1  ETL傳輸平臺架構

如上圖(圖4.1)所示,使用者通過Web介面來建立和管理任務,把資料儲存到資料庫中,而Quartz排程系統的定時任務會把狀態為新建的任務讀出,初始化為例項,接著檢查上游例項和併發狀況,並申請資源,接下來就是根據負載均衡選擇執行機,遠端啟動執行機上的容器,並把容器和例項對映關係存入資料庫中。執行機上Docker守護程序收到啟動命令後,還需要從遠端倉庫中根據任務型別下載映象,如果是傳輸任務就下載Wormhole映象,並設定啟動命令為Wormhole啟動命令(其他任務型別類似)。容器執行後,有定時任務會向每臺執行機查詢容器列表,並逐一檢查容器的狀態,更新例項和容器在資料庫中的狀態。這樣,整個

ETL傳輸平臺就正常運轉了起來。

1.2 排程系統Kepler架構

 

圖 4.2  Kepler架構圖                

排程系統Kepler機制的關鍵就是排程機上的三個定時任務(如圖4.2Init任務、Ready任務和Running任務。

1) Init定時任務的執行頻率是10分鐘一次,用途是從資料庫中獲得所有有效任務檢查下一次觸發時間是否在,根據任務新建它的例項,並把這些例項儲存到例項表中和記憶體Init佇列中。

2) Ready定時任務執行頻率是1分鐘一次,負責把Init佇列中的任務例項,檢查執行條件(如前置任務的例項是否執行完成,是否有同時併發執行的例項等)是否滿足,然後申請一些共享資源,主要是

HiveMysql等併發資源,這一切成功後就把例項的狀態改為Ready並把它從Init佇列移到Ready佇列中,並在資料庫中更改例項狀態為Ready

3) Running程序的頻率是30秒一次,主要如任務是定時通過Zookeeper查詢線上的機器以免出現分配新的任務到已下線的機器上,以及選擇被佔Slot(槽位,對應一個Docker容器用的標準資源量)數最少的機器為任務執行的目標機器。然後根據任務型別確定映象名稱,利用Docker Client API遠端建立和啟動Docker容器。

另外,排程系統的三個比較重要的元件:資源管理器,負責統計所有任務依賴的共享資源,保證它們的總和不達到上限;狀態管理器,維護這各種狀態的例項列表;容器排程器,維護當前執行的容器列表和存活的執行機列表。

1.3 資料交換工具Wormhole架構

下面介紹一下Wormhole的架構,這裡有兩張圖:

 

圖 4.3  Wormhole架構圖

 

圖 4.4  WormholeSplitter元件

4.3所示的是整個Wormhole的架構,但Splitter的作用不是很明顯。圖4.4說明了Splitter的作用。可以看出傳輸任務和資料來源的關係是一對一,而與輸出目的地的關係是一對多。

Wormhole可以在各種資料儲存型別之間高速交換資料。整體上是Framework + Plugin架構[15]Framework提供了以行為單位的資料流緩衝機制,分片和多執行緒讀、寫機制,讀寫分離的資料交換佇列等高效能資料傳輸技術。框架為讀寫、分片、預處理等外掛都提供了通用的介面,針對每個資料型別的外掛實現類負責處理具體的連線和讀寫等規則。一個數據傳輸任務對應一個程序,全部資料傳輸都在記憶體中進行。

框架為讀寫、分片、預處理等外掛都提供了通用的介面,這些介面分ReaderWriter兩類,如果你需要開發面向某種型別資料來源的外掛,只需實現這些介面即可。比如資料來源是Oracle,資料傳輸目標是Mysql,那麼對應要開發的讀寫外掛就是出 OracleReaderMysqlWriter外掛,分片是OracleReaderSplitterMysqlWriterSplitter。預處理是OracleReaderPeripheryMysqlWriterPeriphery。把這些類實現相關介面即可,就算是加入了框架中。。

在生產實踐中,每個資料輸入型別除了要開發ReaderWriter,考慮到傳輸過程的效能和複雜性,還要為每個ReaderWriter開發一個SplitterPeriphery來做分段讀、寫和讀寫預處理工作。

Wormhole的資料交換主要使用了兩種技術:讀寫雙緩衝佇列與執行緒池。下面詳細介紹。執行緒池是一種複用執行緒物件、減少建立執行緒花銷的技術手段[16]。現線上程池技術應用廣泛。無論是主流的Web伺服器TCP連線、資料庫訪問連線、檔案、郵件之類的連線都有使用。這主要是因為兩點:第一,這些伺服器訪問都有一個共同的特點:訪問量大、頻率高但每次連線的時間短。第二,執行緒池相對其他多執行緒技術也有如下的優點:1)執行緒數可以預先設定,並在實際使用中控制在預定數的一定範圍內。這樣就能有效控制建立多個執行緒帶來的記憶體消耗,同時也減輕了JVM在垃圾回收上的壓力。2)複用預先建立或已經存在的執行緒,提高了資源的利用效率。多個訪問連線複用執行緒,這就大大節省了執行緒物件建立的時間,並且節省了系統資源,防止資源浪費[17]3)提高系統響應速度。現在有資料表明,現代伺服器在短時間內處理大量訪問請求會建立大量執行緒,執行緒的建立和銷燬時間會成為系統性能的瓶頸。因此複用執行緒物件能夠降低伺服器訪問的延遲。

在網際網路經典TCP協議伺服器的請求處理邏輯中,監聽TCP連線、資料傳送和接收等事件的是主執行緒,而具體資料的收發則由Handler執行緒處理。於是就需要一個佇列在主執行緒和各個Handler執行緒之間交換資料,類似於經典的生產者-消費者模式。這個佇列讀寫都需要加鎖,在實際處理過程中實際併發效能並不特別好,如果我們要提高併發效能就要用到雙端緩衝佇列。

雙端緩衝佇列是讀寫分離的兩個佇列,傳送資料的執行緒把資料插入寫佇列,而讀取資料的執行緒則從讀佇列中讀取資料[18]。如果讀資料時讀佇列為空且寫佇列不為空,則交換兩個佇列,否則阻塞等待。這個過程中有兩把鎖發揮作用:一是寫鎖。寫鎖用於寫執行緒把資料插入寫佇列時以及讀佇列和寫佇列進行交換時。不過佇列交換時,讀執行緒必須具有讀寫兩把鎖,否則會死鎖。二是讀鎖。讀鎖只用於讀執行緒從讀佇列中獲取資料時。最後還要讀寫緩衝佇列長度的問題,佇列短時,能夠保證資料交換的及時性,但如果太短,佇列交換頻繁會降低併發效能。所以一般資料量大時佇列長一些,反之則短一些。另外,雙端緩衝佇列還有兩種實現策略使用於不同場景:

1) 讀優先。資料消費者發現讀佇列為空時嘗試交換讀寫佇列。這種情況適合讀比寫速度慢的情況下。

2) 寫優先。資料生產者發現寫佇列滿時嘗試交換讀寫佇列。這種情況適合寫比讀慢的情況下。

1.4 開發前臺Galaxy架構

開發前臺是MVC(模型-檢視-控制器)的架構。使用者在檢視層次配置管理任務,控制層負責處理業務邏輯和轉發請求,模型層(資料訪問層)進行持久化管理。考慮到系統的靈活性,我們並沒把控制層和資料訪問層放在同一伺服器叢集上訪問,而是進行的分離,中間採用了該企業的服務框架中介軟體,進行遠端RPC訪問。下面我們來看看GalaxyGalaxy-Halley的後端架構圖(如圖4.5

 

圖 4.5  GalaxyGalaxy-Halley後端架構圖

可以看出,使用者在Web上配置和管理自己的任務發起Http請求,請求從Nginx伺服器通過負載均衡交替選擇伺服器,由於沒有Session Sticky,所以必須在Web前端儲存使用者登入資訊(內部系統,並不存在安全問題)。Galaxy伺服器在處理完邏輯後,就需要向Galaxy-Halley資料庫服務發起遠端RPC呼叫,獲取或者修改例項資訊。

 

圖 4.6  任務程式碼或檔案上線架構圖

下面我們重點討論任務程式碼上線模組。模組的架構如上圖(如圖4.6)。

使用者有些檔案必須從本地上傳,有些程式碼則是專案的程式碼,可以從Github上拉取專案打包結果,釋出到執行機上。整個釋出流程大概是:使用者把檔案上傳到Galaxy Server或者Galaxy Server拉取Github的打包結果成功後,再把檔案上傳到Hdfs。利用Zookeeper實現的、個數與執行機個數相當的分散式訊息佇列釋出訊息給執行機,執行在執行機上的訊息消費程式接收到訊息後,立刻到Hdfs上的指定地址下載程式碼到該任務在執行機上的預訂目錄,無論下載成功還是失敗,立刻往資料庫中插入一條消費狀態資訊。Galaxy通過間隔一段時間輪詢資料庫來獲取整個釋出消費過程中各執行機的消費狀況,一旦有機器消費失敗或者時間超時,則返回失敗。

1.5 本章小結

本章主要介紹了平臺的整體架構設計和三個模組(排程系統、資料交換工具、開發前臺)的架構設計,為下一章的具體實現打好基礎。