騰訊云分布式高可靠消息隊列CMQ架構最佳實踐

目錄

  1. 消息隊列的使用場景、價值

  2. CMQ底層架構剖析

  3. CMQ對比開源rabbitMQ壓測

  4. CMQ案例最佳實踐

01|消息隊列的使用場景

  • 消息的收發解耦 :發送方和接收方不需要了解彼此,甚至不需要知道對方的存在;

  • 屏蔽不同平臺之間的差異 :不同平臺之間通過消息來實現交互,僅僅關心消息的發送和讀取;

  • 削峰填谷,提高系統應對突發能力 :發送消息端永遠不會堵塞,突發消息緩存在CMQ SERVER 端,消費者按照實際能力讀取消息;

  • 一次生產多次消費 :一條消息可以被多鐘類型消費者訂閱,生產著僅需生產一次即可;

  • 跨IDC/WAN傳輸 :CMQ支持消息在不同IDC、城市進行生產、消費,自動就近接入,對業務透明;

02|CMQ底層架構剖析

在分布式大行其道的今天,我們在系統內部、平臺之間廣泛運用消息中間件進行數據交換及解耦。CMQ是騰訊云內部自研基于的高可靠、強一致、可擴展分布式消息隊列,在騰訊內部包括微信手機QQ業務紅包、騰訊話費充值、廣告訂單等都有廣泛使用。目前已上線騰訊云對外開放,本文對CMQ 核心技術原理進行分享介紹。

按照使用場景可以將消息中間件粗略分為:高可靠和高性能兩大類。CMQ主要適用于金融、交易、訂單等對可靠性、可用性有較高要求的業務場景。

如圖1以騰訊充值系統為例,該充值系統通過CMQ 對交易模塊、發貨部分、結算系統進行異步解耦、削峰填谷,一方面大大降低了模塊間耦合度,另一方面減輕了大量突發請求對后端系統的沖擊。在月初充值該系統一天經過CMQ轉發的消息超過十億條,每秒峰值超過10w,最高時有數億條消息通過CMQ的堆積能力緩沖了對后端消費模塊的壓力。

圖1-某充值系統結構

CMQ整體結構如圖2所示,本文重點介紹后端broker set實現原理。通常情況下一個set由3個節點組成,通過多副本保證消息的可靠性、多節點提高系統可用性。當然,可以根據業務的實際需求通過增加set內節點個數來進一步提高可靠性和可用性,CMQ set 內部結構如圖3所示。

圖2-CMQ整體架構圖

圖3-brokerse t 內部結構圖

下面分別中數據高可靠、強一致,系統可用性,可擴展、消息全路徑追蹤方面分別介紹。

高可靠保證

在可靠性保證方面主要包括以下三方面:生產可靠、存儲(堆積)可靠、消費可靠:

  • 生產可靠

如上圖3所示,客戶端生產的消息在set 中超過半數的broker 刷盤成功后會返回確認消息告知生產消息成功。如果在一定時間之內客戶端沒有收到確認信息需要重試來確保消息發送成功。

可靠生產帶來的一個問題就是消息的重復,在網絡異常等情況下很可能CMQ broker已經存儲消息成功只是確認包在網絡上丟失了,這樣客戶端重試生產后,在broker上存在兩條重復的消息。考慮到消息去重開銷較大,目前消息的冪等性需要業務邏輯來保證。

  • 存儲可靠

CMQSET中一個節點為leader 其他節點為follower,leader 負責所有消息的生產消費。當生產消息到達leader 節點后,通過raft 一致性模塊將請求順序寫raft log 并同步刷盤,同時將構造好的raft log 按順序通過網絡發送到其他follower節點,follower節點同步刷盤并返回成功。當leader 收到過半數的節點同步成功信息后將此條請求提交到mq 處理狀態機,由mq 狀態機將請求應用到相應queue。大致邏輯圖4所示。

圖4-數據存儲原理示意圖

由此可見,對于返回客戶端成功的消息至少是分別在兩個節點磁盤上存儲成功的,這就將磁盤故障引起的數據丟失大大降低。另外數據在磁盤上存儲時會將檢驗結果一同記下來,消費者在消費數據之前CMQ broker 會進行比較,確保消息是完整有效的。

  • 消費可靠

消費者拉取消息時會指定當前消息的隱藏時間,在隱藏時間內消費者比較顯式的對消息進行確認刪除,如果超過隱藏時間沒有主動刪除,此條消息將重新對外可見,可以繼續消費。

顯式確認刪除消息是為了防止消息在投遞、處理過程中異常而導致的消息丟失。

對于消息的確認信息 CMQ broker的處理邏輯和生產消息過程類似,也是一個寫入的過程,不同的是此時寫入的數據的內容是msgid 和消息狀態。

強 一致實現

假如一個set中有3個節點(A, B, C),A為leader,B  C 是follower。如上圖所示,對于返回客戶端成功的請求數據在CMQ 中至少在兩個節點上存在,假設為A B,此時如果leader A故障,B C 兩個follower 會自動選舉出一個新leader,CMQ 使用的raft 算法可以保證這個leader 一定是擁有最全量log 信息中的一個,在此必定是B。此時B繼續對外服務,B 和A 擁有相同的已經返回確認給用戶的全量數據視圖,數據是強一致的。

對于A 和 B C 所在的網絡發生分區的情況(如圖5),由于leader A得不到set 中過半節點的回復所以不能處理請求,B C在選舉超時后會選舉出一個新的leader ,CMQ的接入層會自動進行切換。Raft 算法保證新leader 同樣具有完成的數據視圖。

可用性保證

如上文所述,master 負責所有消息的生產消費,當master 故障時SET中其他follower節點會自動選舉出一個新leader,客戶端請求會自動重定向到leader節點,RTO和配置的選舉超時時間有關,目前是在5s左右。大致過程如上圖6所示,具體選舉算法請參考raft 論文。

CMQ單個set 在CAP理論中優先保證了CP,當SET中過半數節點都正常工作時,才能進行消息的生產消費。對于SET多個節點同時故障的不可用情況,CMQ強大的監控調度能力能夠快速對queue進行調度遷移恢復服務,將不可用時間降到最低。

橫向擴展,無限堆積

圖7橫向擴展

上文中SET的概念對用戶來說是透明無感知的,CMQ controller server 根據set的負載情況實時對queue進行調度搬遷。如果某個queue的請求量超過當前set的服務閾值,controller server 可以將queue 路由分布到多個set 上來提高并發量,對于需要海量堆積的服務來說可以通過路由調度來提升堆積上限,理論上可以達到無限堆積。

目前CMQ只能保證特定情況下消息的嚴格有序,例如需要保證單個生產進程、單個消費進程,或者queue的消費窗口設定為1等條件。

全路徑消息trace

CMQ系統中,一條消息的完整路徑包含生產者、broker、消費者三個角色,每個角色處理消息的過程中都會在trace 路徑中增加相關的信息,將這些信息匯聚即可獲取任意一條消息的狀態和當前經過的完整路徑,從而為生產環境中的問題排查提供強有力的數據支持。大大降低了業務定位問題的難度。

小結

CMQ是基于raft 算法來保證數據高可靠、強一致的分布式消息隊列,主要服務于訂單、交易類業務場景。消息的冪等性需業務側來保證,在特定情況下可以保證消息嚴格有序。

對于更側重高性能、高吞吐量業務需求,騰訊云由另外一個消息引擎來提供服務,在協議上同時兼容kafka,很好的滿足了大數據場景,具體原理請留意后續文章介紹。

03|CMQ對比開源rabbitMQ壓測

RabbitMQ 是具有代表性的開源消息中間件,當前較多地應用于企業系統內,用于對數據一致性、穩定性和可靠性要求較高的場景中。

CMQ也是強調高可靠的消息傳遞,那騰訊云的CMQ,對比rabbitMQ有哪些優勢?

  • 功能升級

除了生產、消費確認機制,CMQ還提供了消費回溯功能。

用戶指定CMQ保存生產消息一定天數,隨后將消費回溯到該時間段內某一時間點,從該點開始重新消費。在用戶業務邏輯異常時,以時間為起點的消息重放功能對業務恢復非常有幫助。

  • 性能優化

網絡IO:CMQ能夠批量生產/消費消息,RabbitMQ則不支持批量生產。在大量小消息場景中,CMQ具有更少的請求數和更低的平均延遲。

文件IO:CMQ生產/消費消息是順序寫單個文件,并周期落盤存儲,充分利用文件系統緩存。RabbitMQ持久化消息先入內存隊列進行狀態轉換,然后寫日志緩存,最后寫消息文件和索引文件(索引文件為順序寫、消息文件為隨機寫),涉及三次IO操作,性能較差。

CPU:RabbitMQ的日志緩存和狀態轉換運算較復雜,大量耗用CPU。

  • 可用性提升

CMQ和RabbitMQ都能夠使用多臺機器進行熱備,提高可用性。CMQ基于Raft算法實現,簡單易維護。RabbitMQ使用自創的GM算法(Guaranteed Multicast),學習難度高。

Raft協議中,Log復制只要大多數節點向Leader返回成功,Leader就可以應用該請求,向客戶端返回成功。

GM可靠多播將集群中所有節點組成一個環。Log復制依次從Leader向后繼節點傳播,當Leader再次收到該請求時,發出確認消息在環中傳播,直至Leader再次收到該確認消息,表明Log在環中所有節點同步完成。

GM算法要求Log在集群所有節點同步之后才能向客戶端返回成功;Raft算法則只要求大多數節點同步完成。Raft算法在同步路徑上比GM算法減少了一半的等待時間。

  • 壓測結果

經內部嚴格壓測,在同等網絡、CPU內存環境下,CMQ在保證可靠傳遞的前提下,QPS表現是rabbitMQ的4倍以上。

04|CMQ15年微信春晚紅包案例

春晚紅包活動涉及四個大型系統的聯動,包括微信、微信支付、紅包系統和財付通系統。以下簡單介紹各個系統:

紅包系統:個人紅包的發、搶、拆和列表查看;

財付通系統:包括支付訂單、異步入賬流水的高性能存儲,用戶余額和賬單的實時展示;

微信接入:確保微信用戶公網接入的質量;

微信支付:在線交易的入口。

類似紅包系統的分布式事務是關注的熱點。舉一個典型的例子,“用戶A給用戶B發了10元的紅包”,有以下步驟:

  1. 從A帳號中把余額讀出來

  2. 對A帳號做減法操作(減10元)

  3. 把結果寫回A帳號中(一次確認)

  4. 從B帳號中把余額讀出來

  5. 拆開A發送給B的紅包,讀出數值

  6. 對B帳號做加法操作(加10元)

  7. 把結果寫到B帳號中

為了保證數據的一致性,上述步驟只有兩種結果:都成功完成或者都不成功執行回滾。而且這個操作的過程中,對A、B帳號還需引入分布式鎖機制來避免臟數據的問題。在微信紅包這個龐大的分布式集群內,事情將變的異常復雜。

微信紅包系統引入了騰訊云 CMQ 以避免分布式事務增加對系統的開銷。同樣A用戶給B用戶發10元紅包的場景,下面介紹引入CMQ 后的新策略。

在上述案例中的第七步,B 用戶拆開了紅包,紅包里有 10 塊錢。在做最后的入賬操作時由于當天并發壓力大,常出現入賬失敗的情況。

紅包團隊把入帳失敗的請求,全部轉入CMQ。當B用戶更新賬戶余額失敗時,手機客戶端顯示等待狀態。隨后入賬系統將不斷從 CMQ 重新拉取重試此更新操作。CMQ 保證了這 10 元的入賬消息永遠不丟,直至它被取出。

在除夕當天,用戶紅包的發、拆、入賬等動作,轉化為了十億級別的海量請求。若使用傳統的事務方式,會放大并發壓力使系統崩潰。

CMQ消息隊列保證了紅包消息的可靠存儲、傳遞,實時寫三份保證數據不丟。資金入賬失敗時,入賬系統可異步的多次重試,從CMQ拉數據,直到成功,起削峰填谷的作用。避免失敗回滾和頻繁輪詢數據庫等傳統方式的弊端。

Q&A

Q1: 創業公司怎么選擇消息隊列?

A1:開源的消息隊列有很多,實現機制復雜,運維成本也很高,對于創業企業來說,選擇云服務商提供的消息隊列無疑是最省事的,按需使用,成本非常低。

Q2: CMQ生產的消息,如果未被消費保存多久?

A2:消息在隊列中最長的存活時間,從發送到該隊列開始經過此參數指定的時間后,不論消息是否被取出過都將被刪除;單位為秒,有效值范圍60-1296000秒,也即1分鐘到15天。

Q3: 相比kafka有什么優勢?

A3:跟kafka相比,各有側重點,kafka更強調吞吐性能。CMQ強調是可靠傳遞,不丟。 CMQ的Kafka版本也即將推出,敬請期待。

Q4: CMQ消費方式是push還是pull?還是兩者結合?

A4:當前queue的模式我們采取的是pull的方式。 后續的topic的模式會有push,可以支持push到http端,短信,郵件,和queue。

Q5: 哪些隊列支持pubsub?

A5: 其實CMQ支持兩種產品形態:queue和topic, 對于queue來說沒有pubsub功能,topic有pubsub的能力也能把topic和queue串聯起來使用,queue可以作為topic其中的一個sub方。


 

 

 

 

來自:http://mp.weixin.qq.com/s?__biz=MzI5MDAzODY5OQ==&mid=2653095328&idx=1&sn=f05a8765ad4694ee1c8c9748ba39fbd8&chksm=f7f25364c085da7269832c931a48e2550c9bfcaf6df9adcfa1c3b010031b697c79894ae99410&scene=0#wechat_redirect

 

 本文由用戶 Eugene 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!