"山寨"一個 AWS Batch

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

0x00 AWS Batch 拆解

什么是 AWS Batch? 官方介紹:

AWS Batch 讓開發(fā)人員、科學(xué)家和工程師能夠輕松高效地在 AWS 上運行成千上萬項批處理計算任務(wù)佳遂。AWS Batch 可根據(jù)提交的批處理任務(wù)的數(shù)量和特定資源要求奔浅,動態(tài)預(yù)置計算資源 (CPU 或 內(nèi)存優(yōu)化型實例) 的最佳數(shù)量和類型崎逃。借助 AWS Batch,您無需安裝和管理運行您的任務(wù)所使用的批處理計算軟件或服務(wù)器群集邪驮,從而使您能夠?qū)W⒂诜治鼋Y(jié)果和解決問題妥箕。AWS Batch 可以跨多種 AWS 計算服務(wù)和功能 (如 Amazon EC2 和競價型實例) 計劃、安排和執(zhí)行您的批處理計算工作負載剩岳。

AWS Batch

簡單來說就是一個 Producer-Consumer 的異步任務(wù)執(zhí)行系統(tǒng). 拆解下來有如下幾個部分組成:

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

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

0x01 業(yè)務(wù)場景

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

之前的辦法是, 把任務(wù)擠在一個大 instance 上, 調(diào)整好并發(fā)(最多并發(fā)四個執(zhí)行), 白天空閑.

那么, 如何改造呢?

0x02 可選方案

第一個想法: 上 Yarn 等資源調(diào)度

公司現(xiàn)有的資源調(diào)度框架, Yarn 是一個選擇, 但想想要寫 Yarn application 我瞬間就放棄了, 不值當(dāng).

第二個想法: autoscaling + ec2

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

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

系統(tǒng)就變成了這個樣子:


系統(tǒng)結(jié)構(gòu)

0x03 如何"無損" scale in?

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

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

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

0x04 最終實現(xiàn)

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

首先, 給 worker 節(jié)點的 IAM 要加上對應(yīng)的 autoscaling 權(quán)限

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

其次, worker 代碼中的關(guān)鍵在于:

  1. 每次從 master 獲取任務(wù)前, 必須先打開 scale-in 保護
  2. 強烈建議累計 N 次獲取不到任務(wù)時, 才關(guān)閉 scale-in 保護, 避免任務(wù)隊列中依然有任務(wù), 但 worker 節(jié)點在上一個任務(wù)執(zhí)行完畢到獲取到下一個任務(wù)的間隙, 被 autoscaling 關(guān)閉
# 記錄連續(xù)沒有獲取到 task 的次數(shù)
task_poll_miss_count = 0
while True:
    # 打開 scale-in 保護
    protect_from_scalein()
    try:
        # 從 master 節(jié)點獲取任務(wù)
        task = get_task_from_master()
        if task is not None:
            # 如果任務(wù)不為空, 則執(zhí)行任務(wù)
            task_poll_miss_count = 0
            execute_task(task)
        else:
            task_poll_miss_count += 1
    finally:    
            if task_poll_miss_count >= 10:
                # 連續(xù) 10 次沒有獲取到任務(wù), 應(yīng)該是系統(tǒng)空閑, 直接關(guān)閉 scale-in 保護, 留足夠時間給 autoscaling 關(guān)閉該節(jié)點
                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))

由于任務(wù)執(zhí)行的周期性, 直接使用 autoscaling 的 schedued action 提前在任務(wù)執(zhí)行前啟動 worker, 預(yù)估一個執(zhí)行時間后直接將整個 autoscaling group 的節(jié)點數(shù)量設(shè)置成 0.

scale in 效果
  • 從下向上看, 前三個都是成功被系統(tǒng) scale in, 關(guān)閉節(jié)點
  • 后續(xù)節(jié)點由于有任務(wù)執(zhí)行, scale-in 會失敗, 但系統(tǒng)會持續(xù)重試, 直到 scale-in 保護開關(guān)關(guān)閉為止.

0x05 總結(jié)

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

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

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

-- EOF --

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市入热,隨后出現(xiàn)的幾起案子拍棕,更是在濱河造成了極大的恐慌,老刑警劉巖才顿,帶你破解...
    沈念sama閱讀 221,548評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件莫湘,死亡現(xiàn)場離奇詭異,居然都是意外死亡郑气,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,497評論 3 399
  • 文/潘曉璐 我一進店門腰池,熙熙樓的掌柜王于貴愁眉苦臉地迎上來尾组,“玉大人,你說我怎么就攤上這事示弓』淝龋” “怎么了?”我有些...
    開封第一講書人閱讀 167,990評論 0 360
  • 文/不壞的土叔 我叫張陵奏属,是天一觀的道長跨跨。 經(jīng)常有香客問我,道長囱皿,這世上最難降的妖魔是什么勇婴? 我笑而不...
    開封第一講書人閱讀 59,618評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮嘱腥,結(jié)果婚禮上耕渴,老公的妹妹穿的比我還像新娘。我一直安慰自己齿兔,他們只是感情好橱脸,可當(dāng)我...
    茶點故事閱讀 68,618評論 6 397
  • 文/花漫 我一把揭開白布础米。 她就那樣靜靜地躺著,像睡著了一般添诉。 火紅的嫁衣襯著肌膚如雪屁桑。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,246評論 1 308
  • 那天栏赴,我揣著相機與錄音掏颊,去河邊找鬼。 笑死艾帐,一個胖子當(dāng)著我的面吹牛乌叶,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播柒爸,決...
    沈念sama閱讀 40,819評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼准浴,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了捎稚?” 一聲冷哼從身側(cè)響起乐横,我...
    開封第一講書人閱讀 39,725評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎今野,沒想到半個月后葡公,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,268評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡条霜,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,356評論 3 340
  • 正文 我和宋清朗相戀三年催什,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片宰睡。...
    茶點故事閱讀 40,488評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡蒲凶,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出拆内,到底是詐尸還是另有隱情旋圆,我是刑警寧澤,帶...
    沈念sama閱讀 36,181評論 5 350
  • 正文 年R本政府宣布麸恍,位于F島的核電站灵巧,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏抹沪。R本人自食惡果不足惜刻肄,卻給世界環(huán)境...
    茶點故事閱讀 41,862評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望采够。 院中可真熱鬧肄方,春花似錦、人聲如沸蹬癌。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,331評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至隅要,卻和暖如春蝴罪,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背步清。 一陣腳步聲響...
    開封第一講書人閱讀 33,445評論 1 272
  • 我被黑心中介騙來泰國打工要门, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人廓啊。 一個月前我還...
    沈念sama閱讀 48,897評論 3 376
  • 正文 我出身青樓欢搜,卻偏偏與公主長得像,于是被迫代替她去往敵國和親谴轮。 傳聞我的和親對象是個殘疾皇子炒瘟,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,500評論 2 359

推薦閱讀更多精彩內(nèi)容