鄭昀 基於朱傳志的設計文檔 最後更新於2014/11/11
關鍵詞:
異步消息
、訂閱者集羣、可伸縮、Push模式、Pull模式
電商系統爲何須要 NotifyServer?
如子柳所說,電商系統『
須要兩種中間件系統,一種是實時調用的中間件(淘寶的HSF,高性能服務框架)、一種是異步消息通知的中間件(淘寶的Notify)』。那麼用傳統的 ActiveMQ/RabbitMQ 來實現 異步消息發佈和訂閱 不行嗎?
2013年以前咱們確實用的是 ActiveMQ,固然主要是訂閱者 Pull 模式,選 MySQL 作消息持久化存儲,SA 還爲此反覆測試了各類高可用方案,以下圖所示,ActiveMQ 5.8,mq主從+mysql互爲主從+MMM。
它有三個問題。
第一,它對上游發佈者要求可能不是那麼高,
但要求下游實現消息訂閱時要健壯,好比訂閱者把消息讀走了後它掛了也得不丟棄消息繼續處理,好比很是重要的消息不能只有一個單點訂閱者,必須有訂閱者集羣,但又不能重複處理消息。我在《#研發中間件介紹#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-