微信後臺非同步訊息佇列的優化升級實踐分享

IT技術精選文摘發表於2018-05-13

1、引言


MQ 非同步訊息佇列是微信後臺自研的重要元件,廣泛應用在各種業務場景中,為業務提供解耦、緩衝、非同步化等能力。本文分享了該元件2.0版本的功能特點及優化實踐,希望能為類似業務(比如移動端IM系統等)的訊息佇列設計提供一定的參考。

2、背景介紹


微信後臺給件 MQ 1.0 釋出之初,基本滿足了一般業務場景的非同步化需求,實現了單機下高效能的任務持久化和消費排程。

MQ 1.0 的基本框架如下圖所示:

可以看到,其主要分為 MQ 和 Worker 兩部分。MQ 是任務的持久化和排程框架,Worker 是任務的處理框架。

下面對各個優化點詳細講解。

3、需要實現更優的任務排程


1現狀分析


iOS訊息通知功能,是MQ元件的一個典型應用場景。微信的後臺具有多IDC分佈的特點,不同IDC與蘋果推送服務(APNs)之間的網路質量參差不齊,部分鏈路故障頻發。

由於MQ 1.0 的任務只能本機消費,網路質量的下降將直接導致 Worker 消費能力的下降,進而產生積壓,最終使訊息服務質量受損。

為此,我們提出了跨機消費模式。其目標是實現一個去中心化、自適應的彈性消費網路,以解決系統中出現的區域性積壓問題。

2任務排程是跨機消費的核心問題

下面逐一進行討論。

3拉任務還是推任務


MQ 1.0 下,MQ 可以準確觀察到本機 Worker 的負載狀態,並由其將任務推送給空閒的 Worker 進行處理。推送的方式可以將任務的處理延時做到極低。

擴充套件到跨機消費後,Worker 可以消費任意 MQ 的任務。對 MQ 而言,已經難以精確地維護全網每個 Worker 的狀態了。若繼續沿用推任務的方式,很可能會出現 Worker 接收到超過其處理能力的任務量,從而產生積壓。

4Worker 如何感知 MQ 的積壓


前面提到,系統應該在任務出現積壓時,才產生跨機消費。因此,MQ 在產生積壓時,應該要能以某種形式通知 Worker。

同時,積壓量的變化是很快的,通知的方式應該做到以下幾方面的高效:

  • 速度:儘可能地快;

  • 精度:儘可能少地傳送通知,減少無效通知的傳送。


為此,我們實現了廣播模式,將 MQ 產生的積壓量資訊作為一個訊息,廣播給 多個Worker。

它在實現上如何滿足高效的積壓通知要求呢?

  • 速度:使用長連線將積壓量資訊推送到 Worker 端;

  • 精度:通過靈活的訂閱過濾器,實現對本機、跨機、跨IDC的分級的廣播。


通過廣播模式,我們高效地解決了 MQ 積壓的感知問題。

5Worker 如何消除 MQ 的積壓


通過廣播模式,每個Worker 都可以觀察到所有它感興趣的 MQ 的積壓情況,並以此構建出整個系統的積壓分佈統計。拿到這些資訊後,Worker 如何決定拉取哪個 MQ 的任務呢?

還是回到我們的原始訴求,儘量做到本機消費。所以我們的策略是說,Worker 應該優先消除本機的積壓,當它有餘力的時候,才去幫助其它Worker。

通過分優先順序地拉取,既可在佇列系統正常時大量降低跨機消費,同時也可以在故障發生時,有效地消除區域性積壓。

6負載均衡分析


跨機消費模式,從整個系統角度來看,是完全去中心化的,任意一個 MQ 和 Worker 個體都可以獨立、自由地加入或退出系統。

在這個競爭式的消費系統裡,根據具體的部署情況、不同機型消費能力不同等因素,無法達到完全的負載均衡狀態。但在系統產生區域性過載時,則可以自適應調節,達到相對的均衡。

6小結

4、需要實現更高效的任務處理


1現狀分析


微信釋出已有6年多的時間,後臺的業務邏輯演化至今,往往是非常的複雜,我們來看一個比較極端的例子 —— 群聊批量並行化投遞

上圖是群訊息投遞業務的簡化流程示意。隨著微信群訊息體量的高速膨脹,其帶來的成本壓力越來越大,業務同學提出了批量並行化的優化方式。簡單來說,就是將每個步驟中產生的 RPC 訪問按實際訪問機器聚合成一系列的批量操作,然後並行化執行。

通常來說,單次的批量並行化並不難寫,一般而言,業務同學可能會選擇裸寫。但如果涉及多次的批量並行化,其中還存在巢狀的話,事情就不那麼簡單了。最終程式碼將變得異常複雜,業務開發的同學苦不堪言。MQ 能否從框架上解決這類問題?

2類 MapReduce 任務處理框架


其實,深入分析群訊息投遞的優化需求,可以看到:

  • 一次批量並行化操作本質上是一次 MapReduce 過程;

  • 整個群訊息投遞的處理過程是多次 MapReduce 過程的串聯和並聯。


所以,為了從根本上解決這一類問題,MQ 為業務提供了類 MapReduce 任務處理框架。

該框架提供封裝了通用的 MapReduce 過程,以及併發的排程過程,同時提供併發池隔離能力,解決了併發池餓死的問題。讓業務同學可以從冗繁的程式碼中解放出來,將更多的精力投入到實際業務中。

3流式任務處理框架


除了批量並行化的需求,業務經常提到的一個需求是,任務處理時會產生一些新的任務需要加到佇列中。一般來說是走一次 RPC 來執行任務入隊。在 MQ 2.0 下,流式任務可以幫忙完成這個事情。

所謂流式任務,就是在任務處理結束時,除了返回任務結果,還可以返回一系列新的任務。這些任務通過 MQ 內部框架流轉入隊,更輕量,事務性更強。

相比常規的同步處理模型,它提供了一種輕量的邏輯非同步化模型。一個冗長的邏輯可以切分為很多小的功能塊進行串聯和複用,每一級之間都有 MQ 去充當緩衝和排程。雖然這種處理模式並不適用於所有邏輯,但作為元件功能的一部分,它提供了一種新的解決問題的能力。

4小結


MQ 2.0 提供的類 MapReduce任務處理框架和流式任務處理框架,為業務的實現提供了便利的支援。

5、需要實現更強的過載保護


1現狀分析


MQ的重要作用是充當系統中的緩衝節點,流量控制的能力是非常關鍵的。在 MQ 1.0 下,只能通過配置佇列的任務出隊速度來實現流量控制。

其問題有幾個:

  • 配置需要人工調整,難以估算對後端的實際訪問;

  • 後端處於過載狀態時無法自適應調整;

  • 自己處於過載狀態時無法自適應調整。


2問題分析


從需求來看,MQ 的過載保護需求有兩個方面,一是保護自己不過載,二是保護後端不過載。


下面分別討論兩種策略。

3前向限速


基於 CPU 使用率的流控:
該限速策略很好理解,就是在 CPU 使用率過高時,降低任務處理速度,以將 CPU 資源優先用於保證佇列的快取能力。

基於任務成功率的流控:
後端模組故障時,往往會導致佇列任務出現大量的失敗和重試,這些重試的量級往往會遠超該後端模組設計的有效輸出,給故障恢復帶來很大的困難。該流控策略的通過收集任務執行的成功率資訊,評估後端的有效輸出,並通過反饋計算限制任務重試的速度。

4後向限速


MQ 實現了通用的後向限速能力,業務通過特定介面往 MQ 回傳控制量,達到速度調控的目的。

基於後端 RPC 訪問量的流控:
我們經常會遇到一些業務在處理任務時,存在不同程度的對後端的擴散訪問。僅對任務處理速度進行限制,無法準確限制對後端產生的實際呼叫量。該策略通過收集業務對後端產生的實際呼叫量,反向調節任務處理的速度。

5小結


MQ 2.0 通過分析流控需求,在前向和後向分別提供了有效的流控手段,並且為後續更精細的流控策略預留了擴充的能力,增強了過載保護的能力。

6、本文總結


微信的佇列元件,與業界其他佇列相比,其突出的特點是更貼近實際業務場景,極大地解放了業務同學的生產力。

後續,將在任務持久化容災和排程效能上,對該元件進行持續的優化。

公眾號推薦:


相關文章