Azkaban容器化 - 設計文檔

本文翻譯自Azkaban官網文檔 Azkaban Containerized Executions - Design Doc

作者/關鍵貢獻者: Arvind Pruthi , Janki Akhani , Shardool , Deepak Jaiswal , Aditya Sharma , Abhishek Nath


老架構(裸金屬架構)背景/概覽

Azkaban老架構圖

  • 每一套Azkaban集羣都包含如下組件:一個web server,一組部署在物理機上的executor server,一個mysql(用於保存job狀態和歷史記錄)
  • 每一個executor server大約可以並行執行10個Flow(任務流),具體取決於每個Flow的消耗的資源
  • executor server定期(一般1秒)從mysql拉取處於待執行狀態的Flow,mysql相當於是一個隊列

Azkaban Executor Server的職責

分發任務

  • Executor Server定期從mysql拉取flows
  • 構建flow:解析所有的配置、在內存中構建一個圖、下載依賴文件、分配計算資源(線程池、執行目錄等)
  • 觸發調度

調度

  • 爲了保證任務並行執行,每一個executor server爲每一個flow都維護了一個獨立的線程池
  • 從hadoop name node獲取hadoop tokens以便提交YARN應用
  • 每一個job都是用admin賬號獨立加載
  • 在內存中維護flow的狀態機,並及時更新到mysql中,最後把flow產生的日誌都寫到mysql中

管理Flow

executor server對外暴露AJAX API,提供暫停、強制停止、恢復等操作,超過10天的flow會被強制停止。

管理日誌

AJAX API支持流式日誌,可以實時觀察執行中的flow/job,當flow/job結束後,所有的日誌都會以15MB每塊的大小保存到數據庫中。

部署

  • 部署executor server,先把新版代碼準備好,啓動前會先完成一些必要的測試,以便驗證環境符合預期
  • 測試通過後,把executor server置爲不可用模式,確保不會從數據庫拉取flowparticular executor除外)
  • 啓動新版代碼,狀態變爲可用,恢復任務的執行

裸金屬架構的問題

互相影響(無資源隔離)

Azkaban支持多種Job類型,也允許用戶自己上傳代碼,所以很容易發生部分任務佔用過多的資源(CPU、內存、磁盤),進而拖垮整個executor server,影響此server上的所有任務

彈性伸縮/維護問題(僵化的架構)

網站可靠性對彈性伸縮能力具有強烈的訴求,數十年前的架構就已經存儲了。但是裸金屬架構並不能從最近的新技術上獲益,這在雲計算領域已經司空見慣了。

缺少金絲雀發佈系統

Azkaban的executor server是所有計算的門戶,除了它自身的功能代碼、配置、任務類型之外,還屏蔽了hadoop、安全管理器、spark等基礎計算設施。當前缺少金絲雀機制以支持細粒度的新功能驗證。 根據Azkaban在Linkedin的使用的經驗看,在缺少合適的金絲雀系統的時候,每次滾動發佈代碼是多麼的痛苦。

無視YARN內部的任務隊列

Azkaban有自己的任務隊列和分發機制,這樣可以最大限度的發揮executor server的能力,但是它自己的隊列與YARN的隊列並不匹配,這經常導致YARN集羣過載。

發佈的問題

發佈過程中的環境驗證環節可能要持續10天,在這期間executor server都是不可用的,並且CPU和內存是閒置的。一次發佈如果有問題,需要executor server帶病運行的情況下,不斷的嘗試修復,可能導致GC暫停或者OOM,並且會污染其他的指標。

容器化的關鍵需求

  1. Azkaban的web server動態的爲每一個flow創建一個容器,也就是爲每一個flow提供一套完全獨立的運行環境。
  2. 快速響應激增的資源需求(可伸縮的架構)
  3. 提供一種機制以支持Azkaban各個組件各自獨立進化
    • 把發版的控制權交給對應的用戶:運行平臺、Azkaban本身、用戶Job
    • 讓用戶自己選擇Azkaban或者JobType的版本(在更新基礎設施的時候尤其有用)
  4. 提供一套垂直的金絲雀系統以支持Azkaban/jobtypes和運行平臺完全控制各自的代碼更新

未來的擴展

  1. 爲多個組件開發細粒度的金絲雀系統以支持各自獨立發版

架構概覽

容器化架構概覽

  1. Azkaban採用Disposable Container(一次性容器)的模式,這意味着每當flow被調度之前都會創建一個新的POD,並且在flow結束之後銷燬。
  2. 資源隔離體現在flow級別(而非job),jobssubflows都是flow的一部分;Job級別的資源也探索過,但是最終放棄了:
  • 它會極大的破快原來的架構,爲了實現job級別的資源隔離,大部分的代碼都需要重寫;
  • 爲每一個job創建一個pod會造成過多的資源消耗,還有一種做法是在一個POD裏面包含多個容器,但是這也會導致大部分flowjob相關的代碼被重寫;也許未來會重新考慮這個設計;
  1. 創建POD的時候使用默認的cpu、內存資源,也可以通過參數指定需要申請的資源
  2. 在這樣的設計下,web server必須部署在k8s之外,這樣做並不妨礙它與flowlog之間的通信,它們之間的通信通過Ingress Controller實現,這樣就不需要導出Flow的POD了;
  3. 爲了實現上述第三點需求,flow的pod的執行環境必須動態創建:
  • 在任務分發的環節,會提供動態選擇組件版本的功能,以便提供executor server的運行環境
  • 一系列的容器初始化工作將通過衆多組件的不同版本的組合來完成
  • 動態選擇的功能可以用來實現組件的金絲雀發佈
  • 需要一些Admin API來完成鏡像的管理工作

詳細設計

鏡像管理

  • 使用docker鏡像來創建flow的執行環境,爲了實現上述第三個需求,要使用預製的container模板來創建POD,下文的分發邏輯一節會詳述;
  • Azkaban的運行環境由以下依賴組成:
依賴類型 描述
平臺依賴 Hadoop、Hive、Spark、Pig、Dali、Ksudo等
Azkaban核心 Azkaban代碼包、配置、安全項,由Azkaban管理
JobTypes JobType開發人員開發的代碼/配置,由Azkaban管理,如KafkaPushJob, SparkJob
  • Azkaban核心在基礎鏡像(RHEL7)上加一層,形成Azkaban基礎鏡像
  • 其他的平臺依賴、JobTypes各自在Azkaban基礎鏡像之上新增獨立的層。爲了保持鏡像體積小,節約下載時間,可以使用busybox或者alpine技術來實現
  • 有的開發者的job-types鏡像需要特別定製,不依賴Azkaban。比如Kafka Push Job
FROM container-image-registry.mycorp.com/rhel7-base-image/rhel7-base-image:0.16.9

ARG KPJ_URL=https://artifactory.mycorp.com/kafka-push-job/kafka-push-job/0.2.61/kafka-push-job-0.2.61.jar

RUN curl $KPJ_URL --output ~/kafka-push-job-0.2.61.jar
  • 每個job-type都會基於一個公共的預製鏡像,這個預製鏡像會把所有的代碼包和配置文件都放到容器的外部捲上,此外部卷也會被掛載到應用容器(基於Azkaban基礎鏡像
  • job-type開發者使用鏡像管理API構造job-type鏡像,構造出來的鏡像可以作爲默認的job-type鏡像,flow的開發者可以使用DSL指定job-type鏡像的版本
  • flow執行的過程中使用version-setversion-number來唯一標識它的依賴的組件的狀態;這也有助於在測試環境復現失敗的flow,便於排查問題

鏡像管理API

API使用流程圖

API使用流程圖

數據庫ER圖

數據庫ER圖

分發邏輯

分發邏輯

狀態流程圖

狀態流程圖

kubernets的安全性

初始化容器

初始化k8s pod

運行Flow的容器

Ingress控制器

日誌

狀態頁面

使用裸金屬架構解決上述問題如何?

在kubernets上debug Azkaban

待解決事項

  1. 擱置了通過參數指定flow使用的鏡像的版本
  2. 擱置了通過參數設置版本
  3. 擱置了通過參數指定flow容器需要的CPU和內存
  4. debug問題
  5. 更多關於配置的技巧
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章