"山寨"一個 AWS Batch

去年參加了 AWS re:Invent 2016, 最喜歡也最需要的新產品莫過于 AWS Batch. 回來幾個月了發現中國區依舊沒有上線, 然后就手癢癢"山寨"了一個, 跑著還很穩定. 記錄一下"山寨"過程中的思考.

0x00 AWS Batch 拆解

什么是 AWS Batch? 官方介紹:

AWS Batch 讓開發人員、科學家和工程師能夠輕松高效地在 AWS 上運行成千上萬項批處理計算任務。AWS Batch 可根據提交的批處理任務的數量和特定資源要求,動態預置計算資源 (CPU 或 內存優化型實例) 的最佳數量和類型。借助 AWS Batch,您無需安裝和管理運行您的任務所使用的批處理計算軟件或服務器群集,從而使您能夠專注于分析結果和解決問題。AWS Batch 可以跨多種 AWS 計算服務和功能 (如 Amazon EC2 和競價型實例) 計劃、安排和執行您的批處理計算工作負載。

AWS Batch

簡單來說就是一個 Producer-Consumer 的異步任務執行系統. 拆解下來有如下幾個部分組成:

  • 任務隊列, 用于存儲異步消息. AWS 上有成熟的 SQS, 開源也有很多實現, 比如 Celery
  • 任務執行程序. 任務執行需要對應的 binary, 為了方便部署, AWS Batch 選擇的是 Docker image, 直接指定 docker image 的 name 便可以從 registry pull 下來.
  • 任務調度 engine. 為了提高資源利用率, AWS Batch 支持指定執行程序所需 cpu memory 等, engine 根據需求充分調度, 提高系統利用率
  • Producer 端任務定義. 也就是后續任務執行程序的輸入. 如果做一個通用的任務執行系統的話, Docker image name 也可以作為任務定義, 傳入消費端.
  • 權限等其他配置. AWS Batch 我猜是基于 AWS ECS 做的, 因此支持指定 Docker image 使用與宿主主機不同的 IAM Role, 更細化控制權限(有關 IAM, 可以參見之前文章 AWS IAM 入門)

拆解完成后, 來看看我們的場景

0x01 業務場景

有一個業務, 每天凌晨需要執行多個批處理任務(任務耗時從幾分鐘到幾個小時不等), 白天基本上沒有任務執行. 遇到的問題就是: 想讓任務盡快執行完成, 又想節省成本.

之前的辦法是, 把任務擠在一個大 instance 上, 調整好并發(最多并發四個執行), 白天空閑.

那么, 如何改造呢?

0x02 可選方案

第一個想法: 上 Yarn 等資源調度

公司現有的資源調度框架, Yarn 是一個選擇, 但想想要寫 Yarn application 我瞬間就放棄了, 不值當.

第二個想法: autoscaling + ec2

當前在 AWS 中國區, 最簡單的方式就是直接使用 ec2 作為獨立執行單元調度了(沒有 ECS), 既然是耗時耗資源(不是簡單的函數執行, 需要幾個 GB 內存的 batch 任務), 直接使用 ec2 對應的 instance type, 也不算浪費. 那么參照 AWS Batch 的拆解, 對應的模塊如何實現?

  • 任務隊列: 可以使用 SQS, 但為了簡化系統, master 節點已經有了 MySQL, 直接使用 MySQL 作為任務隊列更簡單
  • 任務執行程序: 既然有 master 節點, ec2 worker 節點啟動時, 直接從 master 拉取最新的執行程序即可.
  • 任務調度 engine: worker 節點啟動一個 agent, 使用 polling 的方式從 master 節點獲取任務即可.由于任務之間相互獨立, 調度的 engine 就簡單的下發任務即可
  • Producer 端任務定義: 系統僅僅執行一種任務, 下發的任務就是簡單的配置, 作為參數輸入到任務執行程序.
  • 權限等其他配置: 整個集群使用同一個 IAM role 和相同的 security group

系統就變成了這個樣子:


系統結構

0x03 如何"無損" scale in?

由于任務是定時開始的(凌晨), 擴容使用 scheduled action; 但如何在沒有任務執行的時候關閉 ec2 節點而不影響正在執行的任務?

一種方式是根據 SQS 隊列中的任務數量, 可以參見 AWS 官方文檔: Scaling Based on Amazon SQS. 但是我的任務是比較大的批處理任務, 隊列中沒有任務, 很有可能任務正在執行中, 如果直接關閉 ec2 instance 進行 scale in 的話, 會導致我的任務執行到一半就失敗.

那么有沒有其他辦法呢? 翻了翻 AWS autoscaling 文檔, 發現 AWS 的新功能: Instance Protection for Auto Scaling, 試了一下, 發現 autoscaling 會一直重試 scale-in 的操作, 直到你的 ec2 instance 把 scale-in 保護關閉. 正合我意!

0x04 最終實現

事情想清楚了, 行動就顯得簡單了.

首先, 給 worker 節點的 IAM 要加上對應的 autoscaling 權限

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "autoscaling:DescribeAutoScalingInstances",
                "autoscaling:SetInstanceProtection"
            ],
            "Resource": "*"
        }
    ]
}

其次, worker 代碼中的關鍵在于:

  1. 每次從 master 獲取任務前, 必須先打開 scale-in 保護
  2. 強烈建議累計 N 次獲取不到任務時, 才關閉 scale-in 保護, 避免任務隊列中依然有任務, 但 worker 節點在上一個任務執行完畢到獲取到下一個任務的間隙, 被 autoscaling 關閉
# 記錄連續沒有獲取到 task 的次數
task_poll_miss_count = 0
while True:
    # 打開 scale-in 保護
    protect_from_scalein()
    try:
        # 從 master 節點獲取任務
        task = get_task_from_master()
        if task is not None:
            # 如果任務不為空, 則執行任務
            task_poll_miss_count = 0
            execute_task(task)
        else:
            task_poll_miss_count += 1
    finally:    
            if task_poll_miss_count >= 10:
                # 連續 10 次沒有獲取到任務, 應該是系統空閑, 直接關閉 scale-in 保護, 留足夠時間給 autoscaling 關閉該節點
                LOG.info("task poll miss count > 10, unlock scale-in protection")
                no_protect_from_scalein()
                task_poll_miss_count = 0
                time.sleep(random.randint(50, 100))

由于任務執行的周期性, 直接使用 autoscaling 的 schedued action 提前在任務執行前啟動 worker, 預估一個執行時間后直接將整個 autoscaling group 的節點數量設置成 0.

scale in 效果
  • 從下向上看, 前三個都是成功被系統 scale in, 關閉節點
  • 后續節點由于有任務執行, scale-in 會失敗, 但系統會持續重試, 直到 scale-in 保護開關關閉為止.

0x05 總結

使用 autoscaling + scale-in 保護, 輕松實現山寨了一個 "AWS Batch". 雖然簡陋, 但很使用, 優點就是大大提高了批處理任務并行度的同時, 還降低了成本. 但缺點也很明顯:

  • 需要自己處理任務執行失敗后, 失敗的任務需要重新投遞問題
  • 需要固定的執行時間, 以便定時擴容
  • 需要在 worker 節點初始化的時候處理執行程序分發問題, 或者獲取到任務后根據任務中的參數在執行邏輯中添加 docker pull 邏輯
  • 資源利用率以單個 instance 為單位, 不支持一個 worker 并發執行多個任務

總之, 作為一個"山寨的 AWS Batch", 夠用就好. 如果 AWS Batch 中國區再不發布, 我就要考慮一下, 把這個山寨貨更完善一下, 畢竟批處理任務執行系統是剛需.

-- EOF --

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,501評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,673評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,610評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,939評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,668評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,004評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,001評論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,173評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,705評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,426評論 3 359
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,656評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,139評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,833評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,247評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,580評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,371評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,621評論 2 380

推薦閱讀更多精彩內容