導讀:
微服務架構已成為了網際網路的熱門話題之一,而這也是網際網路技術發展的必然階段。然而,微服務概念的提出者 Martin Fowler 卻強調:分散式呼叫的第一原則就是不要分散式。
縱觀微服務實施過程中的弊端,可以推斷出作者的意圖,就是希望系統架構者能夠謹慎地對待分散式呼叫,這是分散式系統自身存在的缺陷所致。但無論是 RPC 框架,還是 REST 框架,都因為駐留在不同程式空間的分散式元件,而引入了額外的複雜度。因而可能對系統的效率、可靠性、可預測性等諸多方面帶來負面影響。
信用算力自2016年開始實施微服務改造,通過訊息佇列(Message Queue),後文簡稱MQ,來規避微服務存在的缺陷,實現金融級資料服務。以下是一些使用場景和心得。
為什麼需要 MQ
一、案例介紹
先來看一個當前的真實業務場景。
對於通過資訊流獲客的企業而言,當使用者註冊時,因業務需求會呼叫使用者服務,然後執行一系列操作,註冊 -> 初始化賬戶資訊 -> 邀友獎勵發放 -> 發放優惠券 -> ... -> 資訊流資料上報。
使用者服務的開發人員壓力非常大,因為需要呼叫非常多的服務,業務耦合嚴重。如果當時賬戶服務正在執行發版操作,那麼初始化賬戶動作會失敗。然而平臺經過不斷的迭代更新,後續又新增了一個簽到業務,新註冊使用者預設簽到一次。這就需要修改使用者服務,增加呼叫簽到服務的介面。每當遇到此種情況,開發使用者服務的同學就非常不爽了,為什麼總是我?新增簽到業務和使用者服務又有什麼關係?
為解決此類重度依賴的問題,我們在架構層面引入了 MQ,用來規避微服務之間重度耦合呼叫的弊端。新架構如下圖:
使用者完成註冊動作後,只需要往 MQ 傳送一個使用者註冊的通知訊息,下游業務如需要依賴註冊相關的資料,訂閱註冊訊息的 topic 即可,從而實現了業務的解耦。
看完上述真實的案例後,大家可能產生疑惑,到底什麼是 MQ,使用 MQ 又有什麼好處?適合使用 MQ 的場景和不適合使用 MQ 的場景有哪些不同?
二、什麼是 MQ?
簡單來說,MQ(MessageQueue)是一種跨程式的通訊機制,用於上下游傳遞訊息。
適合使用 MQ 的場景有:
1、上游不關心下游執行結果,例如上述案例中使用者註冊後,我們並不關心賬戶是否初始化,是否上報了資訊流等;
2、非同步返回執行時間長:例如上述案例中,當邀友獎勵發放,需要經歷很多風控規則,執行時間比較長,但是使用者並不關注獎勵何時發放。
不適合使用MQ場景
呼叫方實時關注執行結果,例如使用者發起註冊動作後,需要立刻知道,註冊結果是成功還是失敗,這種需要實時知道最終執行結果的場景,就不適合使用MQ。
三、使用MQ的好處:
1、解耦
2、可靠投遞
3、廣播
4、最終一致性
5、流量削峰
6、訊息投遞保證
7、非同步通訊(支援同步)
8、提高系統吞吐、健壯性
MQ 的技術選型
目前業內比較主流的 MQ 包括 RocketMQ、ActiveMQ、RabbitMQ、Kafka等,關於效能、儲存、社群活躍度等各方面的技術對比已經很多,本文不再重複。
但我們發現通過簡單的選型對比,很難抉擇到底選擇哪款MQ產品。因為金融行業對於資料一致性以及服務可用性的要求非常高,所以任何關於技術的選項都顯得尤為重要。
經調研,如微眾銀行、民生銀行、平安銀行等國內知名的網際網路銀行和直銷銀行代表,都在使用 RocketMQ,且 RocketMQ 出生在阿里系,經受過各種生產壓力的考驗,非常穩定。並且,目前此項技術已經捐增給 Apache 社群,社群活躍度非常高。另外 RocketMQ 開發語言是Java,開發同學遇到解決不了的問題點,或者不清楚的概念,可以直接 Debug 原始碼。經過多方面的比較,我們選擇 RocketMQ 作為規避微服務弊端的利器。
MQ 在微服務下的使用場景
MQ 是一種跨程式的通訊機制,用於上下游傳遞訊息,目前信用算力將 RocketMQ 應用於解耦、流量削峰、分散式事務的處理等幾個場景。
一、解耦
通常解耦的做法是生產者傳送訊息到 MQ,下游訂閱 MQ 的特定 topic,當下遊接收到訊息後開始處理業務邏輯。
那麼,訊息傳送方到底應該是由誰來承擔?是服務提供者在處理完RPC請求後,根據業務需求開始傳送訊息嗎?但此刻開發人員就會抱怨為什麼總是我?為什麼處理完業務後需要傳送 MQ?
為此,在解耦的過程中通過訂閱資料庫的 BinLog 日誌,開發了一套 BinLog 日誌解析模組,專門解析日誌,然後生成 JSON 字串後傳送訊息到 MQ,下游訂閱 MQ 即可。流程如下:
目前所有需要依賴下游服務的業務線,其資料變動都採用此方案。
方案優缺點:
優點:
1、服務之間依賴完全解耦,任何基於註冊行為的業務變更,都無需依賴上游,只需訂閱MQ即可;
2、系統的穩定性和吞吐量增加了,使用者註冊的響應時間縮短了;
缺點:
1、引入MQ後系統複雜性增加,維護成本增加;
2、從註冊開始到全部資料初始化結束的整體時間增加了;
二、流量削峰
每逢遇到會員日的時候,平臺會傳送大量的會員福利活動通知,以簡訊、站內信、PUSH 訊息的方式通知註冊使用者。所有的訊息會在很短的時間全部推送到訊息中心,同時正常的業務通知任然有大量業務訊息推送到訊息中心。為保障平臺的穩定性和可靠性,在訊息中心前置了多種 topic,如簡訊、推送、站內提醒。訊息中心接收到訊息後會全部寫入不同 topic 的 MQ,多個消費者來消費並把資訊推送給終端使用者。
三、分散式事務
使用者在平臺上支付他訂購某種業務的時候,需要涉及到支付服務、賬戶服務、優惠券服務、積分服務,在單體模式下這種業務非常容易實現,通過事務即可完成,虛擬碼如下:
然而,在微服務的情況下,原本通過簡單事務處理的卻變得非常複雜,若引入兩階段提交(2PC)或者補償事務(TCC)方案,則系統的複雜程度會增加。
信用算力的做法是通過本地事務 + MQ 訊息的方式來解決, 雖然 RocketMQ 也支援事務訊息,但是其他主流 MQ 並沒有此項功能,所以綜合考慮採用如下方案:
- 訊息上游:需要額外建一個tc_message表,並記錄訊息傳送狀態。訊息表和業務資料在同一個資料庫裡面,而且要在一個事務裡提交。然後訊息會經過MQ傳送到訊息的消費方。如果訊息傳送失敗,會進行重試傳送;
- 訊息上游:開啟定時任務掃描tc_message表,如果超過設定的時間內狀態沒有變更,會再次傳送訊息到MQ,如重試次數達到上限則發起告警操作;
- 訊息下游:需要處理這個訊息,並完成自己的業務邏輯。此時如果本地事務處理成功,表明已經處理完成了,需要發起業務回撥通知業務方;
方案優缺點:
優點:
1、用最小的代價實現分散式事物,以達到資料最終一致性;
2、方案非常靈活,任何環節都可以人為控制;
缺點:
1、複雜性增加了,業務操作的時候需要寫入 tc_message 表以及傳送 MQ,同時還需要考慮狀態超時未變更的補發機制以及告警處理機制;
2、使用者看到的資料,存在有短暫不一致的情況;
心得體會
使用 RocketMQ 3年多了,總體來說執行的非常穩定,基本上沒有發生過生產事故,下面說說這幾年使用下來的心得體會:
1、一個應用盡可能用一個 Topic,訊息子型別用 tags 來標識。Topic 名稱和 Tags 名稱可以自行設定。Producer,Consumer都需要規範,要做到見名知意。傳送訊息時候必須攜帶 Tags,消費方在訂閱訊息時,才可以利用 Tags 在 Broker 做訊息過濾。
2、每條訊息在業務層面有唯一標識碼,方便在系統出現異常的情況,可以通過業務維度查詢。舉個栗子,當使用者在平臺註冊成功後,會以 Topic 和 UserID 作為唯一標識碼(topic_user_10011),伺服器會為每個訊息建立索引,該訊息會持久化入庫,以防將來定位訊息丟失等問題。下游收到訊息後會以 Topic+Key 方式來記錄消費行為,包括訊息日期、當前機器IP地址、處理結果等;也可以通過 Topic+Key 的方式來查詢這條訊息內容,包括訊息被誰消費,以及這條 MQ 在每個環節的處理狀態。
3、訊息傳送成功或者失敗,都需要記錄 log 日誌,且必須列印 sendresult、MsgID、唯一標識碼。
4、由於上游會做訊息重試機制,所以下游訊息必須要做冪等處理。
5、需要封裝 MQ 的 API 在封裝後,API 需遮蔽底層 MQ 的特性,開發人員無需關注到底是用的哪個 MQ 來支援本地分散式事物、MQ 訊息自動入庫、自動列印日誌,減少開發人員操作成本。
總的來說,MQ 是一個網際網路架構中常見的解耦利器,在這3年中,信用算力在微服務中一直使用 MQ 來為金融客戶提供高質量的資料服務。雖然 MQ 不是唯一方案,但是從目前階段來看,的確是一種非常不錯的解決方案。
本文為雲棲社群原創內容,未經允許不得轉載。