#研發中間件介紹#異步消息可靠推送Notify

鄭昀 基於朱傳志的設計文檔 最後更新於2014/11/11
關鍵詞: 異步消息 、訂閱者集羣、可伸縮、Push模式、Pull模式

本文檔適用人員:研發
 
電商系統爲何須要 NotifyServer?
  如子柳所說,電商系統『 須要兩種中間件系統,一種是實時調用的中間件(淘寶的HSF,高性能服務框架)、一種是異步消息通知的中間件(淘寶的Notify)』。那麼用傳統的 ActiveMQ/RabbitMQ 來實現 異步消息發佈和訂閱 不行嗎?
 
  2013年以前咱們確實用的是 ActiveMQ,固然主要是訂閱者 Pull 模式,選 MySQL 作消息持久化存儲,SA 還爲此反覆測試了各類高可用方案,以下圖所示,ActiveMQ 5.8,mq主從+mysql互爲主從+MMM。
圖1 mq 高可用
  它有三個問題。
  第一,它對上游發佈者要求可能不是那麼高, 但要求下游實現消息訂閱時要健壯,好比訂閱者把消息讀走了後它掛了也得不丟棄消息繼續處理,好比很是重要的消息不能只有一個單點訂閱者,必須有訂閱者集羣,但又不能重複處理消息。我在《#研發中間件介紹#JobCenter》中說過,對每一位開發者維護者提出高要求,這不是咱們的解題思路。我在《職場培訓第五期:職場的真相》中給出瞭解題思路:『 要摒棄單純依靠員工之間互相提醒、依靠我的認真細緻來規避相同錯誤的固有思路,鐵打營盤流水兵,靠 人終歸是靠不住的,最好靠遵循規則的機器』。是的,異步消息的可靠推送(Push),應該是消息中間件的職責。
  第二, ActiveMQ 的高可用方案在可伸縮上不那麼靈活, 不適合電商業務。譬如說,我一開始用一組 [(mq1+mysql1(master角色)),(mq2+mysql2)] 來支撐全部業務的異步消息,但忽然七夕節一個銷售驗證高峯即將到來,須要儘可能平滑地把某些消息隊列轉移出去,用另外一組支撐;或者我看某個消息隊列的消息量 比較大,想追加一個 mysql 節點單獨存儲它的消息。總之就是線上儘可能平滑地擴容 mq server和 database,這事兒還得我們本身從頭搞才順手。
  最後一個問題是全部開源系統的典型問題, 伴隨着開源系統以及各類 Driver 的版本升級,咱們會一路踏入它埋下的每個大大小小的坑。固然,不是說咱們本身寫的中間件就沒有 Bug,但  ActiveMQ 確實讓人攤手,以下面的 RCA 案例所示。
  • RCA:ActiveMQ 的生產者流量控制致使訂單中心大量線程掛起;
  • RCA:PHP連MQ超時致使主庫鏈接被打滿,引起衆多應用數據不一致——緣由在於 PHP::Stomp 包的默認重試次數和默認超時時間;
  • RCA:調小 ActiveMQ之持久化 MySQL 的 wait_timeout 致使發送 MQ 消息頻頻失敗。
 
  最終咱們仍是選擇本身來面對以下場景,採用 Push 模式(NotifyServer 主動向下游 Push 消息):
圖2 一個異步消息須要不少訂閱者集羣分頭處理
 
淘寶是怎麼考慮這些問題的?
  • 可靠性:
    • 消息的投遞分爲兩個階段 
      • 發佈者向Broker發送消息 
      • Broker向訂閱者投遞消息 
    • 所以,消息有可能在三個地方丟失 
      • 發佈者到Broker之間 
      • Broker自己 
      • 從Broker到訂閱者
  • 穩定性 
    • 監視 
      • Broker內存使用 
      • 消息收發功能 
      • 消息堆積狀況 
      • 存儲的插入速度 
      • 各個任務隊列長度 
      • 其餘各項即時統計數據等 
    • 控制
      • 自動移除失效存儲節點 
      • 優雅降級的控制 
      • 添加新存儲節點 
      • 添加新Broker
  • 限制
    • 有可能產生重複消息
    • 對訂閱者的要求
      • 冪等性 f(f(x)) = f(x)
      • 重複調用屢次產生的業務結果與調用一次產生的業務結果相同
  它內部兩個消息中間件產品的區別爲:
圖3 消息中間件對比
  以上資料出自於《消息中間件-Notify的概念和原理.pdf》。
 
窩窩如何實現 NotifyServer 的?
  2013年2月,通過幾輪的討論,技術選型初步肯定,研發2部傳志開始構建 NotifyServer。
  他設計了以下概念:
圖4 notifyserver 的幾個角色概念
  技術模型能夠描述爲:
  • 模塊關係 
    • 各個模塊(隊列、生產者、交換中心、DB、消息體緩存、隊列緩存、日誌緩存、分配中心、消費者)存在必定的對應關係,經過這些對應關係可以更好路由和分流消息,動態擴展系統,改善系統瓶頸。 
    • 這些對應關係都存儲在控制中心關係數據庫中,經過控制檯界面來進行配置,各模塊在啓動和定時到控制中心來更新這些關係,用於消息的分配。 
    • 這些關係都遵照必定規則,添加更改不會影響系統的穩定性,如:一個隊列必須對應兩個以上的交換中心來處理消息,若是DB中還有消息沒有消費完畢不容許直接刪除,等等。 
  • 模塊監控 
    • 控制檯按期測試各個模塊的健康情況。 
    • 各個模塊會按期向控制中心發送一些監控數據,報告本身的運行狀態。 
    • 控制檯收集監控數據,以圖表、拓撲圖等形式向管理人員展現或報警。 
  • 消息跟蹤 
    • 每一條消息在進入系統後都會被分配一個惟一標識。 
    • 各模塊在處理消息時都會產生特定的日誌信息,日誌信息實時的傳送到日誌系統。 
    • 惟一標識+日誌+各模塊信息和關係能夠容易的跟蹤每一條消息的執行狀況。 
 
  那麼最簡單的消息消費泳道圖以下所示:
圖5 消息消費
  分配中心主導的慢速/重試Push,它會盡可能從緩存(Redis)中拿消息體,儘可能減小對 DB 的訪問,尤爲是消息體特別大的時候,效果會比較明顯,以下圖所示。
圖6 重試的泳道圖
 
  對於可伸縮、高可用,他是這麼考慮的:
  • 吞吐量:
    • 交換中心、分配中心都採用平行結構。 
    • 隊列使用持久化方式緩存,使用緩存減小對DB的操做。 
    • 交換中心與分配中心分離,性能互不影響。 
    • 動態改變網絡拓撲結構,分流系統瓶頸。 
    • 動態控制吞吐量參數,調整系統性能。 
  • 擴展性 
    • 交換中心、分配中心、DB、緩存能夠動態添加或刪除。 
    • 隊列路由路徑能夠動態改變。 
  • 可用性 
    • 交換中心、分配中心採用平行方式提升可用性。 
    • DB採用 master-master 方式提升可用性。 
    • 緩存採用多點讀寫方式提過可用性。 
  • 一致性 
    • 消息狀態持久化在DB,未分配或消費失敗的會再次被提取。 
    • 分配中心採用快慢兩種方式接收消息處理消息。 
  • 等冪性 
    • 緩存保存正在處理的消息,防止重複分配。 
 
  與 JobCenter 同樣,NotifyServer 也歸入在咱們的 idcenter 體系下,這樣能夠共用一套賬號體系(LDAP),共用一個統一的權限分配:
 
圖7 notifyserver 的入口
圖8 notifyserver 的主界面
 
圖9 notifyserver 系統隊列(主要是配置信息)界面
 
圖10 notifyserver 監控隊列(主要是運行時情況)界面
  2013年中旬,通過積分業務的試用後,傳志的 NotifyServer 開始在內部推廣,各類異步消息發佈和訂閱一點一點地搬進來,ActiveMQ 方案下線。
 
-over-
相關文章
相關標籤/搜索