消息規模超千億,同程藝龍的消息系統建設實踐

小結:前端

一、算法

/1/退訂請求入庫--->消息隊列異步--->調用供應商對接系統數據庫

調用後端

  成功--->標識數據庫安全

  失敗--->補償腳本--->從新調用架構

咱們引入RocketMQ將同步改成異步,當前端用戶發出退訂需求,退訂系統接收到請求後就會記錄到退訂系統的數據庫裏面,表示這個用戶正在退訂,同時經過消息引擎把這條退訂消息發送到和供應商對接的系統,去調用供應商的接口。異步

若是調用成功,就會把數據庫進行標識,表示已經退訂成功。同時,加了一個補償的腳本,去數據庫撈那些未退訂成功的消息,從新退訂,避免消息丟失引發的退訂失敗的狀況。性能

二、
同一Group和同一Topic下,一個是消費Tag1的數據,另外一個是消費Tag2的數據。
正常狀況下,啓動應該是沒問題的,可是有一天咱們發現一個應用起不來了,另一個應用,由於他只消費Tag2的數據,可是由於RocketMQ的機制會把Tag1的數據拿過來,拿過來事後會把Tag1的數據丟棄。spa

三、
對於大量老數據讀取的改進方式是
- > 對於新消費組,默認從LAST_OFFSET消費而不是初始默認的0;
- > Broker中單Topic堆積超過1000萬時,禁止消費,需聯繫管理員開啓消費;.net

 

https://mp.weixin.qq.com/s/Uj0lirsq0zyCIb8AlEoNBg

消息規模超千億,同程藝龍的消息系統建設實踐

導讀:

同程藝龍的機票、火車票、汽車票、酒店相關業務已經接入了RocketMQ,用於流量高峯時候的削峯,以減小後端的壓力。同時,對常規的系統進行解耦,將一些同步處理改爲異步處理,天天處理的數據達1500億條。

 

在近期的Apache RockeMQ Meetup上,同程藝龍機票事業部架構師查江,分享了同程藝龍的消息系統如何應對天天1500億條的數據處理,經過此文,您將瞭解到:

 

  • 同程藝龍在消息方面的使用狀況;

  • 消息在同程藝龍的應用場景;

  • 技術上踩過哪些坑;

  • 基於RocketMQ,作了哪些改進;

同程藝龍在消息方面的使用狀況

 

慮性能,另外一個考慮安全性。 在純數據的Broker分紅不少組,每一個組裏面分爲Master和Slave。目前,咱們的機票、火車票、汽車票、酒店相關業務已經接入了RocketMQ,用於流量高峯時候的削峯,以減小後端的壓力。同時,對常規的系統進行解耦,將一些同步處理改爲異步處理,天天處理的數據達1500億條。

 

選擇RocketMQ的緣由是:

  • 接入簡單,引入的Java包比較少;

  • 純Java開發,設計邏輯比較清晰;

  • 總體性能比較穩定的,Topic數量大的狀況下,能夠保持性能;

 

 

消息在同程藝龍的應用場景

退訂系統 

這個是咱們退訂系統中的一個應用場景。用戶點擊前端的退訂按鈕,系統調用退訂接口,再去調用供應商的退訂接口,從而完成一個退訂功能。

若是供應商的系統接口不可靠,就會致使用戶退訂失敗,若是系統設置爲同步操做,會致使用戶須要再去點一次。因此,咱們引入RocketMQ將同步改成異步,當前端用戶發出退訂需求,退訂系統接收到請求後就會記錄到退訂系統的數據庫裏面,表示這個用戶正在退訂,同時經過消息引擎把這條退訂消息發送到和供應商對接的系統,去調用供應商的接口。

 

若是調用成功,就會把數據庫進行標識,表示已經退訂成功。同時,加了一個補償的腳本,去數據庫撈那些未退訂成功的消息,從新退訂,避免消息丟失引發的退訂失敗的狀況。

 

房倉系統 

第二個應用場景是咱們的房倉系統。這是一個比較常規的消息使用場景,咱們從供應商處採集一些酒店的基本信息數據和詳情數據,而後接入到消息系統,由後端的分銷系統、最小价系統和庫存系統來進行計算。同時當供應商有變價的時候,變價事件也會經過消息系統傳遞給咱們的後端業務系統,來保證數據的實時性和準確性。

 

 

供應庫的訂閱系統 

數據庫的訂閱系統也用到了消息的應用。通常狀況下作數據庫同步,都是經過binlog去讀裏面的數據,而後搬運到數據庫。搬運過程當中咱們最關注的是數據的順序性,所以在數據庫row模式的基礎上,新增了一個功能,以確保每個Queue裏面的順序是惟一的。

 

 咱們踩過哪些坑

供應商系統的場景 

 

上圖中,一個MQ對應有兩個消費者,他們是在同一個Group1中,起初你們都只有Topic1,這時候是正常消費的。但若是在第一個消費者裏面加入一個Topic2,這時候是沒法消費或消費不正常了。這是RocketMQ自己的機制引發的問題,須要在第二個消費者裏面加入Topic2才能正常消費。 

 

支付交易系統的場景 

 

另一個是支付交易系統,這個場景下也是有兩個應用,他們都是在同一Group和同一Topic下,一個是消費Tag1的數據,另外一個是消費Tag2的數據。正常狀況下,啓動應該是沒問題的,可是有一天咱們發現一個應用起不來了,另一個應用,由於他只消費Tag2的數據,可是由於RocketMQ的機制會把Tag1的數據拿過來,拿過來事後會把Tag1的數據丟棄。這會致使用戶在支付過程當中出現支付失敗的狀況。

 

對此,咱們把Tag2放到Group2裏面,兩個Group就不會消費相同的消息了。我的建議RocketMQ可以實現一個機制,即只接受本身的Tag消息,非相關的Tag不去接收。

 

大量老數據讀取的場景

在火車票消費的場景中,咱們發現有200億條老數據沒有被消費。當咱們消費啓動的時候,RocketMQ會默認從第0個數據開始讀,這時候磁盤IO飆升到100%,從而影響到其餘消費端數據的讀取,但這些老數據被加載後後,並無實際做用。所以,對於大量老數據讀取的改進方式是:

 

- > 對於新消費組,默認從LAST_OFFSET消費;

- > Broker中單Topic堆積超過1000萬時,禁止消費,需聯繫管理員開啓消費;

- > 監控要到位,磁盤IO飆升時,能馬上聯繫到消費方處理。

 

服務端的場景 

CentOS 6.6中 Futex Kernel bug, 致使Name Server, Broker進程常常掛起,沒法正常工做;

- > 升級到6.7

 

服務端2個線程會建立相同CommitLog放入List,致使計算消息offset錯誤,解析消息失敗,沒法消費,重啓無法解決問題。

- >  線程安全問題,改成單線程

 

Pull模式下重置消費進度,致使服務端填充大量數據到Map中,broker cpu使用率飆升100%。

- >  Map局部變量場景用不到,刪除

 

Master建議客戶端到Slave消費時,若數據還沒同步到Slave, 會重置pullOffset, 致使大量重複消費。

- >  不重置offset

 

同步沒有MagicCode,安全組掃描同步端口時,Master解析錯誤,致使一些問題。

- >  同步時添加magicCode校驗

基於RocketMQ,咱們作了哪些改進

新增客戶端 

新增.net客戶端,基於Java源代碼原生開發;

新增HTTP客戶端,實現部分功能,並經過Netty Server鏈接RocketMQ;

 

 

 

新增消息限流功能 

若是客戶端代碼寫錯產生死循環,就會產生大量的重複數據,這時候會把生產線程打滿,致使隊列溢出,嚴重影響咱們MQ集羣的穩定性,從而影響其餘業務。

上圖是限流的模型圖,咱們把限流功能加在Topic以前。經過限流功能能夠設置rate limit和size limit等。其中rate limit是經過令牌桶算法來實現的,即每秒往桶裏放多少個令牌,每秒就消費多少速度,或者是往Topic裏寫多少數據。以上的兩個配置是支持動態修改的。

 

後臺監控 

咱們還作了一個監控後臺,用於監控消息的全鏈路過程,包括:

 

  • 消息全鏈路追蹤,覆蓋消息產生、消費、過時整個生命週期;

  • 消息生產、消費曲線;

  • 消息生產異常報警;

  • 消息堆積報警,通知哪一個IP消費過慢。

 

其餘功能 

  • HTTP方式生產,消費消息;

  • Topic消費權限設置,Topic只能被指定Group消費,防止線上錯亂訂閱;

  • 支持新消費組從最新位置消費 (默認是從第一條開始消費);

  • 廣播模式消費進度同步 (服務端顯示進度)。

 

以上即是同程藝龍在消息系統建設方面的實踐。

相關文章
相關標籤/搜索