掃二維碼與項(xiàng)目經(jīng)理溝通
我們在微信上24小時期待你的聲音
解答本文疑問/技術(shù)咨詢/運(yùn)營咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流
當(dāng)我們構(gòu)建一個應(yīng)用,總是希望它是響應(yīng)迅速,成本低廉的。而在實(shí)際中,我們的系統(tǒng)卻面臨各種各樣的挑戰(zhàn),例如不可預(yù)測的流量高峰,依賴的下游服務(wù)變得緩慢,少量請求卻消耗大量 CPU/內(nèi)存資源。這些因素常常導(dǎo)致整個系統(tǒng)被拖慢,甚至不能響應(yīng)請求。為了讓應(yīng)用服務(wù)總是響應(yīng)迅速,很多時候不得不預(yù)留更多的計算資源,但大部分時候,這些計算資源都是閑置的。一種更好的做法是將耗時緩慢,或者需要消耗大量資源的處理邏輯從請求處理主邏輯中剝離出來,交給更具資源彈性的系統(tǒng)異步執(zhí)行,不但讓請求能夠被迅速處理返回給用戶,也節(jié)省了成本。

讓客戶滿意是我們工作的目標(biāo),不斷超越客戶的期望值來自于我們對這個行業(yè)的熱愛。我們立志把好的技術(shù)通過有效、簡單的方式提供給客戶,將通過不懈努力成為客戶在信息化領(lǐng)域值得信任、有價值的長期合作伙伴,公司提供的服務(wù)項(xiàng)目有:主機(jī)域名、虛擬主機(jī)、營銷軟件、網(wǎng)站建設(shè)、臨翔網(wǎng)站維護(hù)、網(wǎng)站推廣。
一般來說,長耗時,消耗大量資源,或者容易出錯的邏輯,非常適合從請求主流程中剝離出來,異步執(zhí)行。例如新用戶注冊,注冊成功后,系統(tǒng)通常會發(fā)送一封歡迎郵件。發(fā)送歡迎郵件的動作就可以從注冊流程中剝離出來。另一個例子是用戶上傳圖片,圖片上傳后通常需要生成不同大小的縮略圖。但圖片處理的過程不必包含在圖片上傳處理流程中,用戶上傳圖片成功后就可以結(jié)束流程,生成縮略圖等處理邏輯可以作為異步任務(wù)執(zhí)行。這樣應(yīng)用服務(wù)器避免被圖片處理等計算密集型任務(wù)壓垮,用戶也能更快的得到響應(yīng)。常見的異步執(zhí)行任務(wù)包括:
Slack,Pinterest,F(xiàn)acebook 等公司都廣泛的使用異步任務(wù),實(shí)現(xiàn)更好的服務(wù)可用性,更低的成本。根據(jù)Dropbox 統(tǒng)計,他們的業(yè)務(wù)場景中一共有超過100種不同類型的異步任務(wù)。一個功能完備的異步任務(wù)處理系統(tǒng)能帶來顯著的收益:
任務(wù)處理系統(tǒng)通常包括三部分:任務(wù) API 和可觀測,任務(wù)分發(fā)和任務(wù)執(zhí)行。我們首先介紹這三個子系統(tǒng)的功能,然后再討論整個系統(tǒng)面臨的技術(shù)挑戰(zhàn)和解決方案。
該子系統(tǒng)提供一組任務(wù)相關(guān)的 API,包括任務(wù)創(chuàng)建、查詢、刪除等等。用戶通過 GUI,命令行工具,后者直接調(diào)用 API 的方式使用系統(tǒng)功能。以 Dashboard 等方式呈現(xiàn)的可觀測能力也非常重要。好的任務(wù)處理系統(tǒng)應(yīng)當(dāng)包括以下可觀測能力:
任務(wù)分發(fā)負(fù)責(zé)任務(wù)的調(diào)度分發(fā)。一個能應(yīng)用于生產(chǎn)環(huán)境的任務(wù)分發(fā)系統(tǒng)通常要具備以下功能:
任務(wù)分發(fā)的架構(gòu)可分為拉模式和推模式。拉模式通過任務(wù)隊(duì)列分發(fā)任務(wù)。執(zhí)行任務(wù)的實(shí)例主動從任務(wù)隊(duì)列中拉取任務(wù),處理完畢后再拉取新任務(wù)。相對于拉模式,推模式增加了一個分配器的角色。分配器從任務(wù)隊(duì)列中讀取任務(wù),進(jìn)行調(diào)度,推送給合適的任務(wù)執(zhí)行實(shí)例。
拉模式的架構(gòu)清晰,基于 Redis 等流行軟件可以快速搭建任務(wù)分發(fā)系統(tǒng),在簡單任務(wù)場景下表現(xiàn)良好。但如果要支持任務(wù)去重,任務(wù)優(yōu)先級,批量暫?;騽h除,彈性的資源擴(kuò)縮容等復(fù)雜業(yè)務(wù)場景需要的功能,拉模式的實(shí)現(xiàn)復(fù)雜度會迅速增加。實(shí)踐中,拉模式面臨以下一些主要的挑戰(zhàn):
推模式的核心思想是將任務(wù)隊(duì)列和任務(wù)執(zhí)行實(shí)例解耦,平臺側(cè)和用戶的邊界更加清晰。用戶只需要專注于任務(wù)處理邏輯的實(shí)現(xiàn),而任務(wù)隊(duì)列,任務(wù)執(zhí)行節(jié)點(diǎn)資源池的管理都由平臺負(fù)責(zé)。推模式的解耦也讓任務(wù)執(zhí)行節(jié)點(diǎn)的擴(kuò)容不再受任務(wù)隊(duì)列的連接資源等方面的限制,能夠?qū)崿F(xiàn)更高的彈性。但推模式也引入了很多的復(fù)雜度,任務(wù)的優(yōu)先級管理,負(fù)載均衡,調(diào)度分發(fā),流控等都由分配器負(fù)責(zé),分配器需要和上下游系統(tǒng)聯(lián)動。
總的來說,當(dāng)任務(wù)場景變得復(fù)雜后,無論拉還是推模式,系統(tǒng)復(fù)雜度都不低。但推模式讓平臺和用戶的邊界更清晰,簡化了用戶的使用復(fù)雜度,因此有較強(qiáng)技術(shù)實(shí)力的團(tuán)隊(duì),實(shí)現(xiàn)平臺級的任務(wù)處理系統(tǒng)時,通常會選擇推模式。
任務(wù)執(zhí)行子系統(tǒng)管理一批執(zhí)行任務(wù)的 worker 節(jié)點(diǎn),以彈性、可靠的方式執(zhí)行任務(wù)。典型的任務(wù)執(zhí)行子系統(tǒng)需具備如下功能:
任務(wù)執(zhí)行子系統(tǒng)通常使用 K8s 管理的容器集群作為資源池。K8s 能夠管理節(jié)點(diǎn),將執(zhí)行任務(wù)的容器實(shí)例調(diào)度到合適的節(jié)點(diǎn)上。K8s 也內(nèi)置了作業(yè)(Jobs)和定時作業(yè)(Cron Jobs)的支持,簡化了用戶使用 Job 負(fù)載的難度。K8s 有助于實(shí)現(xiàn)共享資源池管理,任務(wù)資源隔離等功能。但 K8s 主要能力還是在POD/實(shí)例管理上,很多時候需要開發(fā)更多的功能來滿足異步任務(wù)場景的需求。例如:
注意:K8s 中的作業(yè)(Job)和本文討論的任務(wù)(task)有一些區(qū)別。K8s 的 Job 通常包含處理一個或者多個任務(wù)。本文的任務(wù)是一個原子的概念,單個任務(wù)只在一個實(shí)例上執(zhí)行。執(zhí)行時長從幾十毫秒到數(shù)小時不等。
接下來,筆者以阿里云函數(shù)計算的異步任務(wù)處理系統(tǒng)為例,探討大規(guī)模多租戶異步任務(wù)處理系統(tǒng)的一些技術(shù)挑戰(zhàn)和應(yīng)對策略。在阿里云函數(shù)計算平臺上,用戶只需要創(chuàng)建任務(wù)處理函數(shù),然后提交任務(wù)即可。整個異步任務(wù)的處理是彈性、高可用的,具備完整的可觀測能力。在實(shí)踐中,我們采用了多種策略來實(shí)現(xiàn)多租戶環(huán)境的隔離、伸縮、負(fù)載均衡和流控,平滑處理海量用戶的高度動態(tài)變化的負(fù)載。
如前所述,異步任務(wù)系統(tǒng)通常需要隊(duì)列實(shí)現(xiàn)任務(wù)的分發(fā)。當(dāng)任務(wù)處理中臺對應(yīng)很多業(yè)務(wù)方,那么為每一個應(yīng)用/函數(shù),甚至每一個用戶都分配單獨(dú)的隊(duì)列資源就不再可行。因?yàn)榻^大多數(shù)應(yīng)用都是長尾的,調(diào)用低頻,會造成大量隊(duì)列,連接資源的浪費(fèi)。并且輪詢大量隊(duì)列也降低了系統(tǒng)的可擴(kuò)展性。
但如果所有用戶都共享同一批隊(duì)列資源,則會面臨多租戶場景中經(jīng)典的“noisy neighbor”問題,A 應(yīng)用突發(fā)式的負(fù)載擠占隊(duì)列的處理能力,影響其他應(yīng)用。
實(shí)踐中,函數(shù)計算構(gòu)建了動態(tài)隊(duì)列資源池。一開始資源池內(nèi)會預(yù)置一些隊(duì)列資源,并將應(yīng)用哈希映射到部分隊(duì)列上。如果某些應(yīng)用的流量快速增長時,系統(tǒng)會采取多種策略:
在一個多租環(huán)境中,防止“破壞者”對系統(tǒng)造成災(zāi)難性的破壞是系統(tǒng)設(shè)計的最大挑戰(zhàn)。破壞者可能是被 DDoS 攻擊的用戶,或者在某些 corner case 下正好觸發(fā)了系統(tǒng) bug 的負(fù)載。下圖展示了一種非常流行的架構(gòu),所有用戶的流量以 round-robin 的方式均勻的發(fā)送給多臺服務(wù)器。當(dāng)所有用戶的流量符合預(yù)期時,系統(tǒng)工作得很好,每臺服務(wù)器的負(fù)載均勻,而且部分服務(wù)器宕機(jī)也不影響整體服務(wù)的可用性。但當(dāng)出現(xiàn)“破壞者”后,系統(tǒng)的可用性將出現(xiàn)很大的風(fēng)險。
如下圖所示,假設(shè)紅色的用戶被 DDoS 攻擊或者他的某些請求可能觸發(fā)服務(wù)器宕機(jī)的 bug,那么他的負(fù)載將可能打垮所有的服務(wù)器,造成整個服務(wù)不可用。
上述問題的本質(zhì)是任何用戶的流量都會被路由到所有服務(wù)器上,這種沒有任何負(fù)載隔離能力的模式在面臨“破壞者”時相當(dāng)脆弱。對于任何一個用戶,如果他的負(fù)載只會被路由到部分服務(wù)器上,能不能解決這個問題?如下圖所示,任何用戶的流量最多路由到2臺服務(wù)器上,即使造成兩臺服務(wù)器宕機(jī),綠色用戶的請求仍然不受影響。這種將用戶的負(fù)載映射到部分而非全部服務(wù)器的負(fù)載分片模式,能夠很好的實(shí)現(xiàn)負(fù)載隔離,降低服務(wù)不可用的風(fēng)險。代價則是系統(tǒng)需要準(zhǔn)備更多的冗余資源。
接下來,讓我們調(diào)整下用戶負(fù)載的映射方式。如下圖所示,每個用戶的負(fù)載均勻的映射到兩臺服務(wù)器上。不但負(fù)載更加均衡,更棒的是,即使兩臺服務(wù)器宕機(jī),除紅色之外的用戶負(fù)載都不受影響。如果我們把分區(qū)的大小設(shè)為2,那么從3臺服務(wù)器中選擇2臺服務(wù)器的組合方式有 C_{3}^{2}=3 種,即3種可能的分區(qū)方式。通過隨機(jī)算法,我們將負(fù)載均勻的映射到分區(qū)上,那么任意一個分區(qū)不可服務(wù),則最多影響1/3的負(fù)載。假設(shè)我們有100臺服務(wù)器,分區(qū)的大小仍然是2,那么分區(qū)的方式有C_{100}{2}=4950種,單個分區(qū)不可用只會影響1/4950=0.2%的負(fù)載。隨著服務(wù)器的增多,隨機(jī)分區(qū)的效果越明顯。對負(fù)載隨機(jī)分區(qū)是一個非常簡潔卻強(qiáng)大的模式,在保障多租系統(tǒng)的可用性中起到了關(guān)鍵的作用。
函數(shù)計算的任務(wù)分發(fā)采用了推模式,這樣用戶只需要專注于任務(wù)處理邏輯的開發(fā),平臺和用戶的邊界也很清晰。在推模式中,有一個任務(wù)分配器的角色,負(fù)責(zé)從任務(wù)隊(duì)列拉取任務(wù)并分配到下游的任務(wù)處理實(shí)例上。任務(wù)分配器要能根據(jù)下游處理能力,自適應(yīng)的調(diào)整任務(wù)分發(fā)速度。當(dāng)用戶的隊(duì)列產(chǎn)生積壓時,我們希望不斷增加 dispatch worker pool 的任務(wù)分發(fā)能力;當(dāng)達(dá)到下游處理能力的上限后,worker pool 要能感知到該狀態(tài),保持相對穩(wěn)定的分發(fā)速度;當(dāng)任務(wù)處理完畢后,work pool 要縮容,將分發(fā)能力釋放給其他任務(wù)處理函數(shù)。
在實(shí)踐中,我們借鑒了 tcp 擁塞控制算法的思想,對 worker pool 的擴(kuò)縮容采取 AIMD 算法(Additive Increase Multiplicative Decrease,和性增長,乘性降低)。當(dāng)用戶短時間內(nèi)提交大量任務(wù)時,分配器不會立即向下游發(fā)送大量任務(wù),而是按照“和性增長”策略,線性增加分發(fā)速度,避免對下游服務(wù)的沖擊。當(dāng)收到下游服務(wù)的流控錯誤后,采用“乘性減少”的策略來,按照一定的比例來縮容 worker pool。其中流控錯誤需要滿足錯誤率和錯誤數(shù)的閾值后才觸發(fā)縮容,避免 worker pool 的頻繁擴(kuò)縮容。
如果任務(wù)的處理能力長期落后于任務(wù)的生產(chǎn)能力,隊(duì)列中積壓的任務(wù)會越來越多,雖然可以使用多個隊(duì)列并進(jìn)行流量路由來減小租戶之間的相互影響。但任務(wù)積壓超過一定閾值后,應(yīng)當(dāng)更積極的向上游的任務(wù)生產(chǎn)方反饋這種壓力,例如開始流控任務(wù)提交的請求。在多租共享資源的場景下,背壓的實(shí)施會更加有挑戰(zhàn)。例如A,B應(yīng)用共享任務(wù)分發(fā)系統(tǒng)的資源,如果A應(yīng)用的任務(wù)積壓,如何做到:
如何在多租場景中識別到需要流控的對象很有挑戰(zhàn),我們在實(shí)踐中借鑒了Sample and Hold算法,取得了較好的效果。感興趣的讀者可以參考相關(guān)論文。
根據(jù)前述對異步任務(wù)處理系統(tǒng)的架構(gòu)和功能的分析,我們將異步任務(wù)處理系統(tǒng)的能力分為以下三層:
|
Level 1 |
Level 2 |
Level 3 |
|
|
任務(wù)的可靠分發(fā) |
支持 |
支持 |
支持 |
|
任務(wù)定時/延時發(fā)送 |
取決于選擇的消息隊(duì)列能力。一般支持定時任務(wù),但不支持延時任務(wù) |
支持 |
支持 |
|
任務(wù)去重 |
不支持 |
支持 |
支持 |
|
任務(wù)錯誤自動重試 |
有限支持。一般依賴于 K8s Jobs 內(nèi)置的重試策略。對于未使用 K8s Jobs 的任務(wù),則需用戶在任務(wù)處理邏輯中自行實(shí)現(xiàn) |
有限支持。一般依賴于 K8s Jobs 內(nèi)置的重試策略。對于未使用 K8s Jobs 的任務(wù),則需用戶在任務(wù)處理邏輯中自行實(shí)現(xiàn) |
支持。平臺和用戶界限清晰,根據(jù)用戶設(shè)定的策略重試 |
|
任務(wù)負(fù)載均衡 |
有限支持。在任務(wù)執(zhí)行實(shí)例規(guī)模小的情況下通過消息隊(duì)列實(shí)現(xiàn) |
有限支持。在任務(wù)執(zhí)行實(shí)例規(guī)模小的情況下通過消息隊(duì)列實(shí)現(xiàn) |
支持。系統(tǒng)具備大規(guī)模節(jié)點(diǎn)的負(fù)載均衡能力 |
|
任務(wù)優(yōu)先級 |
不支持 |
有限支持。允許用戶為高優(yōu)先級任務(wù)預(yù)留資源,或者限制低優(yōu)先級任務(wù)的資源使用 |
支持。高優(yōu)先級任務(wù)可搶占低優(yōu)先級任務(wù)資源,同時系統(tǒng)會兼顧公平,避免低優(yōu)先級任務(wù)被餓死 |
|
任務(wù)流控 |
不支持 |
不支持。一般是為不同任務(wù)類型或者業(yè)務(wù)方配置獨(dú)立的隊(duì)列和計算資源 |
在系統(tǒng)的每個環(huán)節(jié)具備流控能力,系統(tǒng)不會因?yàn)槿蝿?wù)爆發(fā)式提交雪崩 |
|
任務(wù)批量暫停/刪除 |
不支持 |
有限支持。取決于是否為不同任務(wù)類型或者業(yè)務(wù)方配置獨(dú)立的隊(duì)列和計算資源 |
支持 |
|
共享資源池 |
有限支持。依賴 K8s 的調(diào)度能力。一般是為各個業(yè)務(wù)方搭建不同的集群 |
有限支持。依賴 K8s 的調(diào)度能力。一般是為各個業(yè)務(wù)方搭建不同的集群 |
支持。不同類型的任務(wù),不同業(yè)務(wù)場景共享同一個資源池 |
|
資源彈性伸縮 |
不支持。K8s 的 HPA 通常難以滿足任務(wù)場景下的伸縮要求 |
不支持。K8s 的 HPA 通常難以滿足任務(wù)場景下的伸縮要求 |
支持。根據(jù)排隊(duì)任務(wù)數(shù),節(jié)點(diǎn)資源利用率等多維度實(shí)時伸縮 |
|
任務(wù)資源隔離 |
支持。依賴容器的資源隔離能力 |
支持。依賴容器的資源隔離能力 |
支持。依賴容器的資源隔離能力 |
|
任務(wù)資源配額 |
不支持 |
支持 |
支持 |
|
簡化任務(wù)處理邏輯編碼 |
不支持。任務(wù)處理邏輯需要自行拉取任務(wù),執(zhí)行任務(wù) |
不支持。任務(wù)處理邏輯需要自行拉取任務(wù),執(zhí)行任務(wù) |
支持 |
|
系統(tǒng)平滑升級 |
不支持 |
不支持 |
支持 |
|
執(zhí)行結(jié)果通知 |
不支持 |
不支持 |
支持 |
|
可觀測性 |
依賴 K8s,消息隊(duì)列等開源軟件自身的可觀測能力。具備基本的任務(wù)狀態(tài)查詢 |
依賴 K8s,消息隊(duì)列等開源軟件自身的可觀測能力。具備基本的任務(wù)狀態(tài)查詢 |
具備從任務(wù)到系統(tǒng)各個層面的完整可觀測能力 |
異步任務(wù)是構(gòu)建彈性、高可用,響應(yīng)迅速應(yīng)用的重要手段。本文對異步任務(wù)的適用場景和收益進(jìn)行了介紹,并討論了典型異步任務(wù)系統(tǒng)的架構(gòu)、功能和工程實(shí)踐。要實(shí)現(xiàn)一個能夠滿足多種業(yè)務(wù)場景需求,彈性可擴(kuò)展的異步任務(wù)處理平臺具有較高的復(fù)雜度。而阿里云函數(shù)計算 FC 為用戶提供了開箱即用的,接近于Level ?3能力的異步任務(wù)處理服務(wù)。用戶只需要創(chuàng)建任務(wù)處理函數(shù),通過控制臺,命令行工具,API/SDK,事件觸發(fā)等多種方式提交任務(wù),就可以彈性、可靠、可觀測完備的方式處理任務(wù)。函數(shù)計算異步任務(wù)覆蓋任務(wù)處理時長從毫秒到24小時的場景,被阿里云數(shù)據(jù)庫自制服務(wù) DAS,支付寶小程序壓測平臺,網(wǎng)易云音樂,新東方,分眾傳媒,米連等集團(tuán)內(nèi)外客戶廣泛應(yīng)用。
1.函數(shù)計算異步任務(wù)和 K8S Jobs 的能力對比。
|
對比項(xiàng) |
函數(shù)計算異步任務(wù) |
K8S Jobs |
|
適用場景 |
適合任務(wù)執(zhí)行時長數(shù)十毫秒的實(shí)時任務(wù)和任務(wù)執(zhí)行時長幾十小時的離線任務(wù) |
適合任務(wù)提交速度要求不高,任務(wù)負(fù)載比較固定,任務(wù)實(shí)時性要求不高的離線任務(wù) |
|
任務(wù)可觀測能力 |
支持。提供日志,任務(wù)排隊(duì)數(shù)等指標(biāo),任務(wù)鏈路耗時,任務(wù)狀態(tài)查詢等豐富可觀測能力 |
自行整合開源軟件實(shí)現(xiàn)。 |
|
任務(wù)實(shí)例自動擴(kuò)縮容 |
支持。根據(jù)任務(wù)排隊(duì)數(shù),實(shí)例資源使用率自動擴(kuò)縮容 |
不支持。一般通過任務(wù)隊(duì)列,自行實(shí)現(xiàn)自動擴(kuò)縮容和實(shí)例負(fù)載均衡,復(fù)雜度高 |
|
任務(wù)實(shí)例伸縮速度 |
毫秒級 |
分鐘級 |
|
任務(wù)實(shí)例資源利用率 |
用戶只需要選擇合適的實(shí)例規(guī)格,實(shí)例自動伸縮,按實(shí)際處理任務(wù)的時長計量,資源利用率高 |
需在作業(yè)(Job)提交時確定實(shí)例的規(guī)格和數(shù)目。實(shí)例難以自動伸縮和負(fù)載均衡,資源利用率低 |
|
任務(wù)提交速度 |
單個用戶支持每秒提交數(shù)萬任務(wù) |
整個集群每秒最多啟動數(shù)百作業(yè)(Jobs) |
|
任務(wù)定時/延時提交 |
支持 |
支持定時任務(wù),不支持延時任務(wù) |
|
任務(wù)去重 |
支持 |
不支持 |
|
暫停/恢復(fù)任務(wù)執(zhí)行 |
支持 |
Alpha 狀態(tài)(K8S v1.21) |
|
終止指定任務(wù) |
支持 |
有限支持。通過終止任務(wù)實(shí)例間接實(shí)現(xiàn) |
|
任務(wù)流控 |
支持??稍谟脩?,任務(wù)處理函數(shù)等不同粒度進(jìn)行流控 |
不支持 |
|
任務(wù)結(jié)果自動回調(diào) |
支持 |
不支持 |
|
開發(fā)運(yùn)維成本 |
只需要實(shí)現(xiàn)任務(wù)的處理邏輯 |
需維護(hù)K8S集群 |
2.網(wǎng)易云音樂 Serverless Jobs 實(shí)踐,音頻處理算法業(yè)務(wù)落地速度10x提升
3.其他異步任務(wù)案例

我們在微信上24小時期待你的聲音
解答本文疑問/技術(shù)咨詢/運(yùn)營咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流