作者 | 不瞋
當我們構建一個應用,總是希望它是響應迅速,成本低廉的。而在實際中,我們的系統卻面臨各種各樣的挑戰,例如不可預測的流量高峰,依賴的下游服務變得緩慢,少量請求卻消耗大量 CPU/內存資源。這些因素常常導致整個系統被拖慢,甚至不能響應請求。為了讓應用服務總是響應迅速,很多時候不得不預留更多的計算資源,但大部分時候,這些計算資源都是閑置的。一種更好的做法是將耗時緩慢,或者需要消耗大量資源的處理邏輯從請求處理主邏輯中剝離出來,交給更具資源彈性的系統異步執行,不但讓請求能夠被迅速處理返回給用戶,也節省了成本。
一般來說,長耗時,消耗大量資源,或者容易出錯的邏輯,非常適合從請求主流程中剝離出來,異步執行。例如新用戶注冊,注冊成功后,系統通常會發送一封歡迎郵件。發送歡迎郵件的動作就可以從注冊流程中剝離出來。另一個例子是用戶上傳圖片,圖片上傳后通常需要生成不同大小的縮略圖。但圖片處理的過程不必包含在圖片上傳處理流程中,用戶上傳圖片成功后就可以結束流程,生成縮略圖等處理邏輯可以作為異步任務執行。這樣應用服務器避免被圖片處理等計算密集型任務壓垮,用戶也能更快的得到響應。常見的異步執行任務包括:
- 發送電子郵件/即時消息
- 檢查垃圾郵件
- 文檔處理(轉換格式,導出,……)
- 音視頻,圖片處理(生成縮略圖,加水印,鑒黃,轉碼,……)
- 調用外部的三方服務
- 重建搜索索引
- 導入/導出大量數據
- 網頁爬蟲
- 數據清洗
- ……
Slack,Pinterest,Facebook 等公司都廣泛的使用異步任務,實現更好的服務可用性,更低的成本。根據Dropbox 統計,他們的業務場景中一共有超過100種不同類型的異步任務。一個功能完備的異步任務處理系統能帶來顯著的收益:
- 更快的系統響應時間。將長耗時的,重資源消耗的邏輯從請求處理流程中剝離,在別的地方異步執行,能有效的降低請求響應延時,帶來更好的用戶體驗。
- 更好的處理大量突發性請求。在電商等很多場景下,常常有大量突發性請求對系統造成沖擊。同樣的,如果將重資源消耗邏輯從請求處理流程中剝離,在別的地方異步執行,那么相同資源容量的系統能響應更大峰值的請求流量。
- 更低的成本。異步任務的執行時長通常在數百毫秒到數小時之間,根據不同的任務類型,合理的選擇任務執行時間和更彈性的使用資源,就能實現更低的成本。
- 更完善的重試策略和錯誤處理能力。任務保證被可靠的執行(at-least-once),并且按照配置的重試策略進行重試,從而實現更好的容錯能力。例如調用第三方的下游服務,如果能變成異步任務,設置合理的重試策略,即使下游服務偶爾不穩定,也不影響任務的成功率。
- 更快的完成任務處理。多個任務的執行是高度并行化的。通過伸縮異步任務處理系統的資源,海量的任務能夠在合理的成本內更快的完成。
- 更好的任務優先級管理和流控。任務根據類型,通常按照不同的優先級處理。異步任務管理系統能幫助用戶更好的隔離不同優先級的任務,既讓高優先級任務能更快的被處理,又讓低優先級任務不至于被餓死。
- 更多樣化的任務觸發方式。任務的觸發方式是多種多樣的,例如通過 API 直接提交任務,或是通過事件觸發,或是定時執行等等。
- 更好的可觀測性。異步任務處理系統通常會提供任務日志,指標,狀態查詢,鏈路追蹤等能力,讓異步任務更好的被觀測、更容易診斷問題。
- 更高的研發效率。用戶專注于任務處理邏輯的實現,任務調度,資源擴縮容,高可用,流控,任務優先級等功能都由任務處理系統完成,研發效率大幅提高。
一、任務處理系統架構
任務處理系統通常包括三部分:任務 API 和可觀測,任務分發和任務執行。我們首先介紹這三個子系統的功能,然后再討論整個系統面臨的技術挑戰和解決方案。
1.任務 API/Dashboard
該子系統提供一組任務相關的 API,包括任務創建、查詢、刪除等等。用戶通過 GUI,命令行工具,后者直接調用 API 的方式使用系統功能。以 Dashboard 等方式呈現的可觀測能力也非常重要。好的任務處理系統應當包括以下可觀測能力:
- 日志:能夠收集和展示任務日志,用戶能夠快速查詢指定任務的日志。
- 指標:系統需要提供排隊任務數等關鍵指標,幫助用戶快速判斷任務的執行情況。
- 鏈路追蹤:任務從提交到執行過程中,各個環節的耗時。比如在隊列中排隊的時間,實際執行的時間等等。下圖展示了 Netflix Cosmos 平臺的 tracing 能力。
2.任務分發
任務分發負責任務的調度分發。一個能應用于生產環境的任務分發系統通常要具備以下功能:
- 任務的可靠分發:任務一旦提交成功后,無論遇到任何情況,系統都應當保證該任務被調度執行。
- 任務的定時/延時分發:很多類型的任務,希望在指定的時間執行,例如定時發送郵件/消息,或者定時生成數據報表。另一種情況是任務可以延時較長一段時間執行也沒問題,例如下班前提交的數據分析任務在第二天上班前完成即可,這類任務可以放到凌晨資源消耗低峰的時候執行,通過錯峰執行降低成本。
- 任務去重:我們總是不希望任務被重復執行。除了造成資源浪費,任務重復執行可能造成更嚴重的后果。比如一個計量任務因為重復執行算錯了賬單。要做到任務只執行一次(exactly-once),需要在任務提交,分發,執行全鏈路上的每個環節都做到,包括用戶在實現任務處理代碼時也要在執行成功,執行失敗等各種情況下,做到 exactly-once。如何實現完整的 exactly-once 比較復雜,超出了本文的討論范圍。很多時候,系統提供一個簡化的語義也很有價值,即任務只成功執行一次。任務去重需要用戶在提交任務時指定任務 ID,系統通過 ID來判斷該任務是否已經被提交和成功執行過。
- 任務錯誤重試:合理的任務重試策略對高效、可靠的完成任務非常關鍵。任務的重試要考慮幾個因素:1)要匹配下游任務執行系統的處理能力。比如收到下游任務執行系統的流控錯誤,或者感知到任務執行成為瓶頸,需要指數退避重試。不能因為重試反而加大了下游系統的壓力,壓垮下游;2)重試的策略要簡單清晰,易于用戶理解和配置。首先要對錯誤進行分類,區分不可重試錯誤,可重試錯誤,流控錯誤。不可重試錯誤是指確定性失敗的錯誤,重試沒有意義,比如參數錯誤,權限問題等等??芍卦囧e誤是指導致任務失敗的因素具有偶然性,通過重試任務最終會成功,比如網絡超時等系統內部錯誤。流控錯誤是一種比較特殊的可重試錯誤,通常意味著下游已經滿負荷,重試需要采用退避模式,控制發送給下游的請求量。
- 任務的負載均衡:任務的執行時間變化很大,短的幾百毫秒,長的數十小時。簡單的 round-robin 。 方式分發任務,會導致執行節點負載不均。實踐中常見的模式是將任務放置到隊列中,執行節點根據自身任務執行情況主動拉取任務。使用隊列保存任務,讓根據節點的負載把任務分發到合適的節點上,讓節點的負載均衡。任務負載均衡通常需要分發系統和執行子系統配合實現。
- 任務按優先級分發:任務處理系統通常對接很多的業務場景,他們的任務類型和優先級各不相同。位于業務核心體驗相關的任務執行優先級要高于邊緣任務。即使同樣是消息通知,淘寶上買家收到一個商品評論通知的重要性肯定低于新冠疫情中的核酸檢測通知。但另一方面,系統也要保持一定程度的公平,不要讓高優先級任務總是搶占資源,而餓死低優先級任務。
- 任務流控:任務流控典型的使用場景是削峰填谷,比如用戶一次性提交數十萬的任務,期望在幾個小時內慢慢處理。因此系統需要限制任務的分發速率,匹配下游任務執行的能力。任務流控也是保證系統可靠性的重要手段,某類任務提交量突然爆發式增長,系統要通過流控限制其對系統的沖擊,減小對其他任務的影響。
- 批量暫停和刪除任務:在實際生產環境,提供任務批量暫停和刪除非常重要。用戶總是會出現各種狀況,比如任務的執行出現了某些問題,最好能暫停后續任務的執行,人工檢查沒有問題后,再恢復執行;或者臨時暫停低優先級任務,釋放計算資源用于執行更高優先級的任務。另一種情況是提交的任務有問題,執行沒有意義。因此系統要能讓用戶非常方便的刪除正在執行和排隊中的任務。任務的暫停和刪除需要分發和執行子系統配合實現。
任務分發的架構可分為拉模式和推模式。拉模式通過任務隊列分發任務。執行任務的實例主動從任務隊列中拉取任務,處理完畢后再拉取新任務。相對于拉模式,推模式增加了一個分配器的角色。分配器從任務隊列中讀取任務,進行調度,推送給合適的任務執行實例。
拉模式的架構清晰,基于 Redis 等流行軟件可以快速搭建任務分發系統,在簡單任務場景下表現良好。但如果要支持任務去重,任務優先級,批量暫?;騽h除,彈性的資源擴縮容等復雜業務場景需要的功能,拉模式的實現復雜度會迅速增加。實踐中,拉模式面臨以下一些主要的挑戰:
- 資源自動伸縮和負載均衡復雜。任務執行實例和任務隊列建立連接,拉取任務。當任務執行實例規模較大時,對任務隊列的連接資源會造成很大的壓力。因此需要一層映射和分配,任務實例只和對應的任務隊列連接。下圖是 Slack 公司的異步任務處理系統架構。Worker 節點只和部分 Redis 實例相連。這解決了 worker 節點大規模擴展的能力,但是增加了調度和負載均衡的復雜度。
- 從支持任務優先級,隔離和流控等需求的角度考慮,最好能使用不同的隊列。但隊列過多,又增加了管理和連接資源消耗,如何平衡很有挑戰。
- 任務去重,任務批量暫?;蛘邉h除等功能依賴消息隊列功能,但很少有消息類產品能滿足所有需求,常常需要自行開發。例如從可擴展性的角度,通常做不到每一類任務都對應單獨的任務隊列。當任務隊列中包含多種類型的任務時,要批量暫停或者刪除其中某一類的任務,是比較復雜的。
- 任務隊列的任務類型和任務處理邏輯耦合。如果任務隊列中包含多種類型的任務,要求任務處理邏輯也要實現相應的處理邏輯,對用戶不友好。在實踐中,A 用戶的任務處理邏輯不會預期接收到別的用戶任務,因此任務隊列通常由用戶自行管理,進一步增加了用戶的負擔。
推模式的核心思想是將任務隊列和任務執行實例解耦,平臺側和用戶的邊界更加清晰。用戶只需要專注于任務處理邏輯的實現,而任務隊列,任務執行節點資源池的管理都由平臺負責。推模式的解耦也讓任務執行節點的擴容不再受任務隊列的連接資源等方面的限制,能夠實現更高的彈性。但推模式也引入了很多的復雜度,任務的優先級管理,負載均衡,調度分發,流控等都由分配器負責,分配器需要和上下游系統聯動。
總的來說,當任務場景變得復雜后,無論拉還是推模式,系統復雜度都不低。但推模式讓平臺和用戶的邊界更清晰,簡化了用戶的使用復雜度,因此有較強技術實力的團隊,實現平臺級的任務處理系統時,通常會選擇推模式。
3.任務執行
任務執行子系統管理一批執行任務的 worker 節點,以彈性、可靠的方式執行任務。典型的任務執行子系統需具備如下功能:
- 任務的可靠執行。任務一旦提交成功,無論任何情況,系統應當保證任務被執行。例如執行任務的節點宕機,任務應當調度到其他的節點執行。任務的可靠執行通常是任務分發和任務執行子系統共同配合實現。
- 共享資源池。不同類型的任務處理資源共享統一的資源池,這樣才能削峰填谷,提高資源利用效率,降低成本。例如把計算密集,io密集等不同類型的任務調度到同一臺 worker 節點上,就能更充分的利用節點上的CPU,內存,網絡等多個維度的資源。共享資源池對容量管理,任務資源配額管理,任務優先級管理,資源隔離提出了更高的要求。
- 資源彈性伸縮。系統能根據負載的執行情況伸縮執行節點資源,降低成本。伸縮的時機和數量非常關鍵。常見的根據任務執行節點的 CPU,內存等資源水位情況伸縮,時間較長,不能滿足實時性要求高的場景。很多系統也使用排隊任務數等指標進行伸縮。另一個值得關注的點是執行節點的擴容需要匹配上下游系統的能力。例如當任務分發子系統使用隊列來分發任務時,worker 節點的擴容要匹配隊列的連接能力。
- 任務資源隔離。在 worker 節點上執行多個不同的任務時,資源是相互隔離的。通常使用容器的隔離機制實現。
- 任務資源配額。用戶的使用場景多樣,常常包含多種任務類型和優先級。系統要支持用戶為不同優先級的任務或者處理函數設置資源配額,為高優先級任務預留資源,或者限制低優先級任務能使用的資源。
- 簡化任務處理邏輯的編碼。好的任務處理系統,能夠讓用戶專注于實現單個任務處理邏輯,系統自動并行、彈性、可靠的執行任務。
- 平滑升級。底層系統的升級不要中斷長時任務的執行。
- 執行結果通知。實時通知任務執行狀態和結果。對于執行失敗的任務,任務的輸入被保存到死信隊列中,方便用戶隨時手動重試。
任務執行子系統通常使用 K8s 管理的容器集群作為資源池。K8s 能夠管理節點,將執行任務的容器實例調度到合適的節點上。K8s 也內置了作業(Jobs)和定時作業(Cron Jobs)的支持,簡化了用戶使用 Job 負載的難度。K8s 有助于實現共享資源池管理,任務資源隔離等功能。但 K8s 主要能力還是在POD/實例管理上,很多時候需要開發更多的功能來滿足異步任務場景的需求。例如:
- K8s 的 HPA 一般難以滿足任務場景下的自動伸縮。Keda 等開源項目提供了按排隊任務數等指標伸縮的模式。AWS 也結合 CloudWatch 提供了類似的解決方案。
- K8s 一般需要配合隊列來實現異步任務,隊列資源的管理需要用戶自行負責。
- K8s 原生的作業調度和啟動時間比較慢,而且提交作業的 tps 一般小于 200,所以不適合高 tps,短延時的任務。
注意:K8s 中的作業(Job)和本文討論的任務(task)有一些區別。K8s 的 Job 通常包含處理一個或者多個任務。本文的任務是一個原子的概念,單個任務只在一個實例上執行。執行時長從幾十毫秒到數小時不等。
二、大規模多租戶異步任務處理系統實踐
接下來,筆者以阿里云函數計算的異步任務處理系統為例,探討大規模多租戶異步任務處理系統的一些技術挑戰和應對策略。在阿里云函數計算平臺上,用戶只需要創建任務處理函數,然后提交任務即可。整個異步任務的處理是彈性、高可用的,具備完整的可觀測能力。在實踐中,我們采用了多種策略來實現多租戶環境的隔離、伸縮、負載均衡和流控,平滑處理海量用戶的高度動態變化的負載。
1.動態隊列資源伸縮和流量路由
如前所述,異步任務系統通常需要隊列實現任務的分發。當任務處理中臺對應很多業務方,那么為每一個應用/函數,甚至每一個用戶都分配單獨的隊列資源就不再可行。因為絕大多數應用都是長尾的,調用低頻,會造成大量隊列,連接資源的浪費。并且輪詢大量隊列也降低了系統的可擴展性。
但如果所有用戶都共享同一批隊列資源,則會面臨多租戶場景中經典的“noisy neighbor”問題,A 應用突發式的負載擠占隊列的處理能力,影響其他應用。
實踐中,函數計算構建了動態隊列資源池。一開始資源池內會預置一些隊列資源,并將應用哈希映射到部分隊列上。如果某些應用的流量快速增長時,系統會采取多種策略:
- 如果應用的流量持續保持高位,導致隊列積壓,系統將為他們自動創建單獨的隊列,并將流量分流到新的隊列上。
- 將一些延時敏感,或者優先級高的應用流量遷移到其他隊列上,避免被高流量應用產生的隊列積壓影響。
- 允許用戶設置任務的過期時間,對于有實時性要求的任務,在發生積壓時快速丟棄過期任務,確保新任務能更快的處理。
2.負載隨機分片
在一個多租環境中,防止“破壞者”對系統造成災難性的破壞是系統設計的最大挑戰。破壞者可能是被 DDoS 攻擊的用戶,或者在某些 corner case 下正好觸發了系統 bug 的負載。下圖展示了一種非常流行的架構,所有用戶的流量以 round-robin 的方式均勻的發送給多臺服務器。當所有用戶的流量符合預期時,系統工作得很好,每臺服務器的負載均勻,而且部分服務器宕機也不影響整體服務的可用性。但當出現“破壞者”后,系統的可用性將出現很大的風險。
如下圖所示,假設紅色的用戶被 DDoS 攻擊或者他的某些請求可能觸發服務器宕機的 bug,那么他的負載將可能打垮所有的服務器,造成整個服務不可用。
上述問題的本質是任何用戶的流量都會被路由到所有服務器上,這種沒有任何負載隔離能力的模式在面臨“破壞者”時相當脆弱。對于任何一個用戶,如果他的負載只會被路由到部分服務器上,能不能解決這個問題?如下圖所示,任何用戶的流量最多路由到2臺服務器上,即使造成兩臺服務器宕機,綠色用戶的請求仍然不受影響。這種將用戶的負載映射到部分而非全部服務器的負載分片模式,能夠很好的實現負載隔離,降低服務不可用的風險。代價則是系統需要準備更多的冗余資源。
接下來,讓我們調整下用戶負載的映射方式。如下圖所示,每個用戶的負載均勻的映射到兩臺服務器上。不但負載更加均衡,更棒的是,即使兩臺服務器宕機,除紅色之外的用戶負載都不受影響。如果我們把分區的大小設為2,那么從3臺服務器中選擇2臺服務器的組合方式有 C_{3}^{2}=3 種,即3種可能的分區方式。通過隨機算法,我們將負載均勻的映射到分區上,那么任意一個分區不可服務,則最多影響1/3的負載。假設我們有100臺服務器,分區的大小仍然是2,那么分區的方式有C_{100}{2}=4950種,單個分區不可用只會影響1/4950=0.2%的負載。隨著服務器的增多,隨機分區的效果越明顯。對負載隨機分區是一個非常簡潔卻強大的模式,在保障多租系統的可用性中起到了關鍵的作用。
3.自適應下游處理能力的任務分發
函數計算的任務分發采用了推模式,這樣用戶只需要專注于任務處理邏輯的開發,平臺和用戶的邊界也很清晰。在推模式中,有一個任務分配器的角色,負責從任務隊列拉取任務并分配到下游的任務處理實例上。任務分配器要能根據下游處理能力,自適應的調整任務分發速度。當用戶的隊列產生積壓時,我們希望不斷增加 dispatch worker pool 的任務分發能力;當達到下游處理能力的上限后,worker pool 要能感知到該狀態,保持相對穩定的分發速度;當任務處理完畢后,work pool 要縮容,將分發能力釋放給其他任務處理函數。
在實踐中,我們借鑒了 tcp 擁塞控制算法的思想,對 worker pool 的擴縮容采取 AIMD 算法(Additive Increase Multiplicative Decrease,和性增長,乘性降低)。當用戶短時間內提交大量任務時,分配器不會立即向下游發送大量任務,而是按照“和性增長”策略,線性增加分發速度,避免對下游服務的沖擊。當收到下游服務的流控錯誤后,采用“乘性減少”的策略來,按照一定的比例來縮容 worker pool。其中流控錯誤需要滿足錯誤率和錯誤數的閾值后才觸發縮容,避免 worker pool 的頻繁擴縮容。
4.向上游的任務生產方發送背壓(back pressure)
如果任務的處理能力長期落后于任務的生產能力,隊列中積壓的任務會越來越多,雖然可以使用多個隊列并進行流量路由來減小租戶之間的相互影響。但任務積壓超過一定閾值后,應當更積極的向上游的任務生產方反饋這種壓力,例如開始流控任務提交的請求。在多租共享資源的場景下,背壓的實施會更加有挑戰。例如A,B應用共享任務分發系統的資源,如果A應用的任務積壓,如何做到:
- 公平。盡可能流控A而不是B應用。流控本質是一個概率問題,為每一個對象計算流控概率,概率越準確,流控越公平。
- 及時。背壓要傳遞到系統最外層,例如在任務提交時就對A應用流控,這樣對系統的沖擊最小。
如何在多租場景中識別到需要流控的對象很有挑戰,我們在實踐中借鑒了Sample and Hold算法,取得了較好的效果。感興趣的讀者可以參考相關論文。
三、異步任務處理系統的能力分層
根據前述對異步任務處理系統的架構和功能的分析,我們將異步任務處理系統的能力分為以下三層:
- Level 1:一般需 1-5 人研發團隊,系統是通過整合 K8s 和消息隊列等開源軟件/云服務的能力搭建的。系統的能力受限于依賴的開源軟件/云服務,難以根據業務需求進行定制。資源的使用偏靜態,不具備資源伸縮,負載均衡的能力。能夠承載的業務規模有限,隨著業務規模和復雜度增長,系統開發和維護的代價會迅速增加。
- Level 2:一般需 5-10人研發團隊,在開源軟件/云服務的基礎之上,具備一定的自主研發能力,滿足常見的業務需求。不具備完整的任務優先級、隔離、流控的能力,通常是為不同的業務方配置不同的隊列和計算資源。資源的管理比較粗放,缺少實時資源伸縮和容量管理能力。系統缺乏可擴展性,資源精細化管理能力,難以支撐大規模復雜業務場景。
- Level 3:一般需 10+ 人研發團隊,能夠打造平臺級的系統。具備支撐大規模,復雜業務場景的能力。采用共享資源池,在任務調度,隔離流控,負載均衡,資源伸縮等方面能力完備。平臺和用戶界限清晰,業務方只需要專注于任務處理邏輯的開發。具備完整的可觀測能力。
Level 1 | Level 2 | Level 3 | |
任務的可靠分發 | 支持 | 支持 | 支持 |
任務定時/延時發送 | 取決于選擇的消息隊列能力。一般支持定時任務,但不支持延時任務 | 支持 | 支持 |
任務去重 | 不支持 | 支持 | 支持 |
任務錯誤自動重試 | 有限支持。一般依賴于 K8s Jobs 內置的重試策略。對于未使用 K8s Jobs 的任務,則需用戶在任務處理邏輯中自行實現 | 有限支持。一般依賴于 K8s Jobs 內置的重試策略。對于未使用 K8s Jobs 的任務,則需用戶在任務處理邏輯中自行實現 | 支持。平臺和用戶界限清晰,根據用戶設定的策略重試 |
任務負載均衡 | 有限支持。在任務執行實例規模小的情況下通過消息隊列實現 | 有限支持。在任務執行實例規模小的情況下通過消息隊列實現 | 支持。系統具備大規模節點的負載均衡能力 |
任務優先級 | 不支持 | 有限支持。允許用戶為高優先級任務預留資源,或者限制低優先級任務的資源使用 | 支持。高優先級任務可搶占低優先級任務資源,同時系統會兼顧公平,避免低優先級任務被餓死 |
任務流控 | 不支持 | 不支持。一般是為不同任務類型或者業務方配置獨立的隊列和計算資源 | 在系統的每個環節具備流控能力,系統不會因為任務爆發式提交雪崩 |
任務批量暫停/刪除 | 不支持 | 有限支持。取決于是否為不同任務類型或者業務方配置獨立的隊列和計算資源 | 支持 |
共享資源池 | 有限支持。依賴 K8s 的調度能力。一般是為各個業務方搭建不同的集群 | 有限支持。依賴 K8s 的調度能力。一般是為各個業務方搭建不同的集群 | 支持。不同類型的任務,不同業務場景共享同一個資源池 |
資源彈性伸縮 | 不支持。K8s 的 HPA 通常難以滿足任務場景下的伸縮要求 | 不支持。K8s 的 HPA 通常難以滿足任務場景下的伸縮要求 | 支持。根據排隊任務數,節點資源利用率等多維度實時伸縮 |
任務資源隔離 | 支持。依賴容器的資源隔離能力 | 支持。依賴容器的資源隔離能力 | 支持。依賴容器的資源隔離能力 |
任務資源配額 | 不支持 | 支持 | 支持 |
簡化任務處理邏輯編碼 | 不支持。任務處理邏輯需要自行拉取任務,執行任務 | 不支持。任務處理邏輯需要自行拉取任務,執行任務 | 支持 |
系統平滑升級 | 不支持 | 不支持 | 支持 |
執行結果通知 | 不支持 | 不支持 | 支持 |
可觀測性 | 依賴 K8s,消息隊列等開源軟件自身的可觀測能力。具備基本的任務狀態查詢 | 依賴 K8s,消息隊列等開源軟件自身的可觀測能力。具備基本的任務狀態查詢 | 具備從任務到系統各個層面的完整可觀測能力 |
四、結論
異步任務是構建彈性、高可用,響應迅速應用的重要手段。本文對異步任務的適用場景和收益進行了介紹,并討論了典型異步任務系統的架構、功能和工程實踐。要實現一個能夠滿足多種業務場景需求,彈性可擴展的異步任務處理平臺具有較高的復雜度。而阿里云函數計算 FC 為用戶提供了開箱即用的,接近于Level ?3能力的異步任務處理服務。用戶只需要創建任務處理函數,通過控制臺,命令行工具,API/SDK,事件觸發等多種方式提交任務,就可以彈性、可靠、可觀測完備的方式處理任務。函數計算異步任務覆蓋任務處理時長從毫秒到24小時的場景,被阿里云數據庫自制服務 DAS,支付寶小程序壓測平臺,網易云音樂,新東方,分眾傳媒,米連等集團內外客戶廣泛應用。
附錄
1.函數計算異步任務和 K8S Jobs 的能力對比。
對比項 | 函數計算異步任務 | K8S Jobs |
適用場景 | 適合任務執行時長數十毫秒的實時任務和任務執行時長幾十小時的離線任務 | 適合任務提交速度要求不高,任務負載比較固定,任務實時性要求不高的離線任務 |
任務可觀測能力 | 支持。提供日志,任務排隊數等指標,任務鏈路耗時,任務狀態查詢等豐富可觀測能力 | 自行整合開源軟件實現。 |
任務實例自動擴縮容 | 支持。根據任務排隊數,實例資源使用率自動擴縮容 | 不支持。一般通過任務隊列,自行實現自動擴縮容和實例負載均衡,復雜度高 |
任務實例伸縮速度 | 毫秒級 | 分鐘級 |
任務實例資源利用率 | 用戶只需要選擇合適的實例規格,實例自動伸縮,按實際處理任務的時長計量,資源利用率高 | 需在作業(Job)提交時確定實例的規格和數目。實例難以自動伸縮和負載均衡,資源利用率低 |
任務提交速度 | 單個用戶支持每秒提交數萬任務 | 整個集群每秒最多啟動數百作業(Jobs) |
任務定時/延時提交 | 支持 | 支持定時任務,不支持延時任務 |
任務去重 | 支持 | 不支持 |
暫停/恢復任務執行 | 支持 | Alpha 狀態(K8S v1.21) |
終止指定任務 | 支持 | 有限支持。通過終止任務實例間接實現 |
任務流控 | 支持??稍谟脩?,任務處理函數等不同粒度進行流控 | 不支持 |
任務結果自動回調 | 支持 | 不支持 |
開發運維成本 | 只需要實現任務的處理邏輯 | 需維護K8S集群 |
2.網易云音樂 Serverless Jobs 實踐,音頻處理算法業務落地速度10x提升
3.其他異步任務案例
參考鏈接:
[1] slack engineering:https://slack.engineering/scaling-slacks-job-queue/
[2] Facebook:https://engineering.fb.com/2020/08/17/production-engineering/async/
[3] Dropbox 統計:https://dropbox.tech/infrastructure/asynchronous-task-scheduling-at-dropbox
[4] Netflix Cosmos 平臺:https://netflixtechblog.com/the-netflix-cosmos-platform-35c14d9351ad
[5] keda:https://keda.sh/
[6] Autoscaling Asynchronous Job Queues :https://d1.awsstatic.com/architecture-diagrams/ArchitectureDiagrams/autoscaling-asynchronous-job-queues.pdf
[7] 異步任務:https://help.aliyun.com/document_detail/372531.html
[8] Sample and Hold 算法:https://dl.acm.org/doi/10.1145/633025.633056
[9] 網易云音樂音視頻算法的 Serverless 探索之路: https://developer.aliyun.com/article/801501
[10] 其它異步任務案例:https://developer.aliyun.com/article/815182