高速飛機上換引擎,MQ如何實現平滑遷移?

前幾天,楊紫瓊同學在知識星球提問,說公司要切換MQ,從一個舊的服務商升級為新的服務商,問有沒有什么好方案。
這個需求估計還挺普遍的,這里分享一些經驗。
一、MQ架構簡述
如上圖,使用MQ異步通信,一般分為三層:消息發送方:使用MQ客戶端生成消息。
- MQ-client::SendMsg(topic, msg);
MQ服務:中轉消息。 消息接收方:使用MQ客戶端消費消息。
- MQ-client::RecvMsg(topic, msg, CALLBACK_FUNC);
這是一個典型的pub-sub架構,如果要替換MQ供應商,至少三個地方要替換:
- 發送方mq-client
- MQ-server
- 接收方mq-client
如何平滑遷移,是今天要討論的話題。
二、平滑遷移方案
平滑遷移的目標是:不停服,平滑升級。 如果有很多主題,需要一個一個主題的遷移,每個主題的遷移,分為三個步驟。
步驟一:消費方雙向訂閱
如上圖所示,不妨設:
- 粉色是舊MQ體系
- 藍色是新MQ體系
平滑遷移最終目的,是“發布-服務-訂閱”三層全由粉色升級為藍色。 第一步升級消費方,同一個主題,既要訂閱舊MQ,又要訂閱新MQ。
此時,“新服務-新訂閱”之間雖然有TCP連接,但“新發布”沒有上線,實際上不會有消息發送過來(上圖虛線),消息仍走的是舊MQ(上圖實線)。
步驟二:生產方升級為新發布
第二步升級生產方,由舊MQ發布,升級為新MQ發布。
此時,“新發布-新服務-新訂閱”之間會建立TCP連接,消息會轉移到新通道(上圖實線),“舊服務-舊訂閱”之間雖然有TCP連接,但實際不會有消息發送過來(上圖虛線)。
步驟三:消費方下線舊訂閱
第三步升級消費方,將舊訂閱下線,整個MQ的遷移完成。
三、架構啟示
MQ更換服務商,螞蟻搬家,一步步平滑遷移,成本其實還挺高的。
之所以這么麻煩,不能統一升級,本質是業務與底層基礎設施細節(即,具體使用哪個MQ)的耦合。如果公司在早期技術體系規劃的時候,能夠“淺淺的封裝一層”,便能隔離“業務代碼”與“底層基礎設施細節”。
舉個更通俗的例子。
假如沒有封裝一層,業務代碼是:
- ActiveMQ-client::SendMsg(topic, msg);
- ActiveMQ-client::RecvMsg(topic, msg, CALLBACK_FUNC);
即,業務方需要關心ActiveMQ,如果基礎設施升級為RabbitMQ,業務代碼需要升級。 假如有一層淺淺的封裝:
- ShenJianMQ::SendMsg(topic, msg){
- ActiveMQ-client::SendMsg(topic,msg);
- }
- ShenJianMQ::RecvMsg(topic, msg,CALLBACK_FUNC)
- ActiveMQ-client::RecvMsg(topic,msg, CALLBACK_FUNC);
- }
業務方不需要關心底層是什么MQ,而只需要依賴基礎組件ShenJianMQ。
此時如果基礎設施升級為RabbitMQ,只需要基礎組件ShenJianMQ升級。
第一步:RecvMsg升級為雙向訂閱。
- ShenJianMQ::RecvMsg(topic, msg,CALLBACK_FUNC)
- ActiveMQ-client::RecvMsg(topic, msg, CALLBACK_FUNC);
- RabbitMQ-client::RecvMsg(topic, msg, CALLBACK_FUNC);
- }
第二步:SendMsg升級為新發布。
- ShenJianMQ::SendMsg(topic, msg){
- RabbitMQ-client::SendMsg(topic, msg);
- }
第三步:RecvMsg下線舊訂閱。
- ShenJianMQ::RecvMsg(topic, msg,CALLBACK_FUNC)
- RabbitMQ-client::RecvMsg(topic, msg, CALLBACK_FUNC);
- }
會發現,除了升級依賴新版的ShenJianMQ基礎組件,業務代碼不需要修改代碼。
不僅MQ,緩存與數據庫的客戶端,淺淺封裝一層也能實現業務代碼與基礎組件的解耦,在基礎組建替換,或者基礎組建升級的時候,業務代碼不需要升級。
畫外音:淺淺封裝一層之后,監控/告警/數據收集等工作都更容易統一實現了。
關于MQ平滑遷移的問題,先聊這么多,希望能解答楊紫瓊同學的問題。
【本文為51CTO專欄作者“58沈劍”原創稿件,轉載請聯系原作者】