同程旅行基於 RocketMQ 高可用架構實踐


頭圖.jpeg

背景介紹

為何選擇 RocketMQ

我們在幾年前決定引入 MQ 時,市場上已經有不少成熟的解決方案,比如 RabbitMQ , ActiveMQ,NSQ,Kafka 等。考慮到穩定性、維護成本、公司技術棧等因素,我們選擇了 RocketMQ :

  • 純 Java 開發,無依賴,使用簡單,出現問題能 hold ;
  • 經過阿里雙十一考驗,性能、穩定性可以保障;
  • 功能實用,發送端:同步、異步、單邊、延時發送;消費端:消息重置,重試隊列,死信隊列;
  • 社區活躍,出問題能及時溝通解決。

使用情況

  • 主要用於削峰、解耦、異步處理;
  • 已在火車票、機票、酒店等核心業務廣泛使用,扛住巨大的微信入口流量;
  • 在支付、訂單、出票、數據同步等核心流程廣泛使用;
  • 每天 1000+ 億條消息周轉。

下圖是 MQ 接入框架圖

由於公司技術棧原因,client sdk 我們提供了 java sdk ;對於其他語言,收斂到 http proxy ,屏蔽語言細節,節約維護成本。按照各大業務線,對后端存儲節點進行了隔離,相互不影響。

1.png

MQ 雙中心改造

之前單機房出現過網絡故障,對業務影響較大。為保障業務高可用,同城雙中心改造提上了日程。

為何做雙中心

  • 單機房故障業務可用;​
  • 保證數據可靠:若所有數據都在一個機房,一旦機房故障,數據有丟失風險;
  • 橫向擴容:單機房容量有限,多機房可分擔流量。

雙中心方案

做雙中心之前,對同城雙中心方案作了些調研,主要有冷(熱)備份、雙活兩種。(當時社區 Dledger 版本還沒出現,Dledger 版本完全可做為雙中心的一種可選方案。)

1)同城冷(熱)備份

兩個獨立的 MQ 集群, 用戶流量寫到一個主集群,數據實時同步到備用集群,社區有成熟的 RocketMQ Replicator 方案,需要定期同步元數據,比如主題,消費組,消費進度等。

2.png

2)同城雙活

兩個獨立 MQ 集群,用戶流量寫到各自機房的 MQ 集群,數據相互不同步。

平時業務寫入各自機房的 MQ 集群,若一個機房掛了,可以將用戶請求流量全部切到另一個機房,消息也會生產到另一個機房。

3.png

對於雙活方案,需要解決 MQ 集群域名。

1)若兩個集群用一個域名,域名可以動態解析到各自機房。此方式要求生產、消費必須在同一個機房。假如生產在 idc1 ,消費在 idc2 ,這樣生產、消費各自連接一個集群,沒法消費數據。

2)若一個集群一個域名,業務方改動較大,我們之前對外服務的集群是單中心部署的,業務方已經大量接入,此方案推廣較困難。

為盡可能減少業務方改動,域名只能繼續使用之前的域名,最終我們采用一個 Global MQ 集群,跨雙機房,無論業務是單中心部署還是雙中心部署都不影響;而且只要升級客戶端即可,無需改動任何代碼。

雙中心訴求

  • 就近原則:生產者在 A 機房,生產的消息存於 A 機房 broker ; 消費者在 A 機房,消費的消息來自 A 機房 broker 。
  • 單機房故障:生產正常,消息不丟。
  • broker 主節點故障:自動選主。

就近原則

簡單說,就是確定兩件事:

  • 節點(客戶端節點,服務端節點)如何判斷自己在哪個 idc;
  • 客戶端節點如何判斷服務端節點在哪個 idc。

如何判斷自己在哪個 idc?

  1. ip 查詢
    節點啟動時可以獲取自身 ip ,通過公司內部的組件查詢所在的機房。

2)環境感知
需要與運維同學一起配合,在節點裝機時,將自身的一些元數據,比如機房信息等寫入本地配置文件,啟動時直接讀寫配置文件即可。

我們采用了第二個方案,無組件依賴,配置文件中 logicIdcUK 的值為機房標志。

修改圖.jpg
客戶端節點如何識別在同一個機房的服務端節點?

客戶端節點可以拿到服務端節點的 ip 以及 broker 名稱的,因此:

  • ip 查詢:通過公司內部組件查詢 ip 所在機房信息;
  • broker 名稱增加機房信息:在配置文件中,將機房信息添加到 broker 名稱上;
  • 協議層增加機房標識:服務端節點向元數據系統注冊時,將自身的機房信息一起注冊。

相對於前兩者,實現起來略復雜,改動了協議層, 我們采用了第二種與第三種結合的方式。

就近生產

基於上述分析,就近生產思路很清晰,默認優先本機房就近生產;

若本機房的服務節點不可用,可以嘗試擴機房生產,業務可以根據實際需要具體配置。
5.png

就近消費

優先本機房消費,默認情況下又要保證所有消息能被消費。

隊列分配算法采用按機房分配隊列

  • 每個機房消息平均分給此機房消費端;
  • 此機房沒消費端,平分給其他機房消費端。

偽代碼如下:

Map<String, Set> mqs = classifyMQByIdc(mqAll);
Map<String, Set> cids = classifyCidByIdc(cidAll);
Set<> result = new HashSet<>;
for(element in mqs){
                     result.add(allocateMQAveragely(element, cids, cid)); //cid為當前客戶端
}

消費場景主要是消費端單邊部署與雙邊部署。

單邊部署時,消費端默認會拉取每個機房的所有消息。
6.png

雙邊部署時,消費端只會消費自己所在機房的消息,要注意每個機房的實際生產量與消費端的數量,防止出現某一個機房消費端過少。
7.png

單機房故障

  • 每組 broker 配置

一主兩從,一主一從在一機房,一從在另一機房;某一從同步完消息,消息即發送成功。

  • 單機房故障

消息生產跨機房;未消費消息在另一機房繼續被消費。

故障切主

在某一組 broker 主節點出現故障時,為保障整個集群的可用性,需要在 slave 中選主並切換。要做到這一點,首先得有個broker 主故障的仲裁系統,即 nameserver(以下簡稱 ns )元數據系統(類似於 redis 中的哨兵)。

ns 元數據系統中的節點位於三個機房(有一個第三方的雲機房,在雲上部署 ns 節點,元數據量不大,延時可以接受),三個機房的 ns 節點通過 raft 協議選一個leader,broker 節點會將元數據同步給 leader, leader 在將元數據同步給 follower 。

客戶端節點獲取元數據時, 從 leader,follower 中均可讀取數據。

8.png

切主流程

  • 若 nameserver leader 監控到 broker 主節點異常, 並要求其他 follower 確認;半數 follower 認為 broker 節點異常,則 leader 通知在 broker 從節點中選主,同步進度大的從節點選為主;
  • 新選舉的 broker 主節點執行切換動作並注冊到元數據系統;
  • 生產端無法向舊 broker 主節點發送消息。

流程圖如下

9.pngimage.png

切中心演練

用戶請求負載到雙中心,下面的操作先將流量切到二中心---回歸雙中心---切到一中心。確保每個中心均可承擔全量用戶請求。

先將用戶流量全部切到二中心

10.png
image.png
流量回歸雙中心,並切到一中心

11.png

回顧

  • 全局 Global 集群
  • 就近原則
  • 一主二從,寫過半消息即及寫入成功
  • 元數據系統 raft 選主
  • broker 主節點故障,自動選主

MQ 平台治理

即使系統高性能、高可用,倘若隨便使用或使用不規范,也會帶來各種各樣的問題,增加了不必要的維護成本,因此必要的治理手段不可或缺。

目的

​讓系統更穩定

  • 及時告警
  • 快速定位、止損

治理哪些方面

主題/消費組治理

  • 申請使用

生產環境 MQ 集群,我們關閉了自動創建主題與消費組,使用前需要先申請並記錄主題與消費組的項目標識與使用人。一旦出現問題,我們能夠立即找到主題與消費組的負責人,了解相關情況。若存在測試,灰度,生產等多套環境,可以一次申請多個集群同時生效的方式,避免逐個集群申請的麻煩。

  • 生產速度

為避免業務疏忽發送大量無用的消息,有必要在服務端對主題生產速度進行流控,避免這個主題擠占其他主題的處理資源。

  • 消息積壓

對消息堆積敏感的消費組,使用方可設置消息堆積數量的閾值以及報警方式,超過這個閾值,立即通知使用方;亦可設置消息堆積時間的閾值,超過一段時間沒被消費,立即通知使用方。

  • 消費節點掉線

消費節點下線或一段時間無響應,需要通知給使用方。

客戶端治理

  • 發送、消費耗時檢測

監控發送/消費一條消息的耗時,檢測出性能過低的應用,通知使用方着手改造以提升性能;同時監控消息體大小,對消息體大小平均超過 10 KB 的項目,推動項目啟用壓縮或消息重構,將消息體控制在 10 KB 以內。

  • 消息鏈路追蹤

一條消息由哪個 ip 、在哪個時間點發送,又由哪些 ip 、在哪個時間點消費,再加上服務端統計的消息接收、消息推送的信息,構成了一條簡單的消息鏈路追蹤,將消息的生命周期串聯起來,使用方可通過查詢msgId或事先設置的 key 查看消息、排查問題。

  • 過低或有隱患版本檢測

隨着功能的不斷迭代,sdk 版本也會升級並可能引入風險。定時上報 sdk 版本,推動使用方升級有問題或過低的版本。

服務端治理

  • 集群健康巡檢

如何判斷一個集群是健康的?定時檢測集群中節點數量、集群寫入 tps 、消費 tps ,並模擬用戶生產、消費消息。

  • 集群性能巡檢

性能指標最終反映在處理消息生產與消費的時間上。服務端統計處理每個生產、消費請求的時間,一個統計周期內,若存在一定比例的消息處理時間過長,則認為這個節點性能有問題;引起性能問題的原因主要是系統物理瓶頸,比如磁盤 io util 使用率過高,cpu load 高等,這些硬件指標通過夜鷹監控系統自動報警。

  • 集群高可用

高可用主要針對 broker 中 master 節點由於軟硬件故障無法正常工作,slave 節點自動被切換為 master ,適合消息順序、集群完整性有要求的場景。

部分后台操作展示

主題與消費組申請

12.png

生產,消費,堆積實時統計

13.png

集群監控
修改圖2.jpg

踩過的坑

社區對 MQ 系統經歷了長時間的改進與沉淀,我們在使用過程中也到過一些問題,要求我們能從深入了解源碼,做到出現問題心不慌,快速止損。

  • 新老消費端並存時,我們實現的隊列分配算法不兼容,做到兼容即可;
  • 主題、消費組數量多,注冊耗時過長,內存 oom ,通過壓縮縮短注冊時間,社區已修復;
  • topic 長度判斷不一致,導致重啟丟消息,社區已修復;
  • centos 6.6 版本中,broker 進程假死,升級 os 版本即可。

MQ 未來展望

目前消息保留時間較短,不方便對問題排查以及數據預測,我們接下來將對歷史消息進行歸檔以及基於此的數據預測。

  • 歷史數據歸檔
  • 底層存儲剝離,計算與存儲分離
  • 基於歷史數據,完成更多數據預測
  • 服務端升級到 Dledger ,確保消息的嚴格一致

了解更多 RocketMQ 信息,可加入社區交流群,下面是釘釘群,歡迎大家加群留言。

15.jpg


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM