消息隊列設計精要(2)

錯峰與流控試想上下游對於事情的處理能力是不同的。比如,Web前端每秒承受上千萬的請求,並不是什麼神奇的事情,只需要加多一點機器,再搭建一些LVS負載均衡設備和Nginx等即可。但數據庫的處理能力卻十分有限,即使使用SSD加分庫分表,單機的處理能力仍然在萬級。由於成本的考慮,我們不能奢求數據庫的機器數量追上前端。 這種問題同樣存在於系統和系統之間,如短信系統可能由於短板效應,速度卡在網關上(每秒幾百次請求),跟前端的併發量不是一個數量級。但用戶晚上個半分鐘左右收到短信,一般是不會有太大問題的。如果沒有消息隊列,兩個系統之間通過協商、滑動窗口等複雜的方案也不是說不能實現。但系統複雜性指數級增長,勢必在上游或者下游做存儲,並且要處理定時、擁塞等一系列問題。而且每當有處理能力有差距的時候,都需要單獨開發一套邏輯來維護這套邏輯。所以,利用中間系統轉儲兩個系統的通信內容,並在下游系統有能力處理這些消息的時候,再處理這些消息,是一套相對較通用的方式。 總而言之,消息隊列不是萬能的。對於需要強事務保證而且延遲敏感的,RPC是優於消息隊列的。 對於一些無關痛癢,或者對於別人非常重要但是對於自己不是那麼關心的事情,可以利用消息隊列去做。 支持最終一致性的消息隊列,能夠用來處理延遲不那麼敏感的“分佈式事務”場景,而且相對於笨重的分佈式事務,可能是更優的處理方式。 當上下游系統處理能力存在差距的時候,利用消息隊列做一個通用的“漏斗”。在下游有能力處理的時候,再進行分發。 如果下游有很多系統關心你的系統發出的通知的時候,果斷地使用消息隊列吧。 如何設計一個消息隊列綜述我們現在明確了消息隊列的使用場景,下一步就是如何設計實現一個消息隊列了。 基於消息的系統模型,不一定需要broker(消息隊列服務端)。市面上的的Akka(actor模型)、ZeroMQ等,其實都是基於消息的系統設計範式,但是沒有broker。 我們之所以要設計一個消息隊列,並且配備broker,無外乎要做兩件事情:

  • 消息的轉儲,在更合適的時間點投遞,或者通過一系列手段輔助消息最終能送達消費機。
  • 規範一種範式和通用的模式,以滿足解耦、最終一致性、錯峰等需求。
    掰開了揉碎了看,最簡單的消息隊列可以做成一個消息轉發器,把一次RPC做成兩次RPC。發送者把消息投遞到服務端(以下簡稱broker),服務端再將消息轉發一手到接收端,就是這麼簡單。

一般來講,設計消息隊列的整體思路是先build一個整體的數據流,例如producer發送給broker,broker發送給consumer,consumer回覆消費確認,broker刪除/備份消息等。 利用RPC將數據流串起來。然後考慮RPC的高可用性,儘量做到無狀態,方便水平擴展。 之後考慮如何承載消息堆積,然後在合適的時機投遞消息,而處理堆積的最佳方式,就是存儲,存儲的選型需要綜合考慮性能/可靠性和開發維護成本等諸多因素。 為了實現廣播功能,我們必須要維護消費關係,可以利用zk/config server等保存消費關係。 在完成了上述幾個功能後,消息隊列基本就實現了。然後我們可以考慮一些高級特性,如可靠投遞,事務特性,性能優化等。 下面我們會以設計消息隊列時重點考慮的模塊為主線,穿插灌輸一些消息隊列的特性實現方法,來具體分析設計實現一個消息隊列時的方方面面。


分享到:


相關文章: