MQ 平滑遷移都不會(huì),還做什么架構(gòu)師?
繼《MySQL如何不停服平滑遷移?》之后,有童鞋問我說,切換MQ,從一個(gè)舊的服務(wù)商升級(jí)為新的服務(wù)商,能否平滑遷移?今天和大家聊聊這個(gè)問題。

一、MQ架構(gòu)簡(jiǎn)述

如上圖,使用MQ異步通信,一般分為三層:
- 消息發(fā)送方:使用MQ客戶端生成消息。
MQ-client::SendMsg(topic, msg);- MQ服務(wù):中轉(zhuǎn)消息。
- 消息接收方:使用MQ客戶端消費(fèi)消息。
MQ-client::RecvMsg(topic, msg, CALLBACK_FUNC);這是一個(gè)典型的pub-sub架構(gòu),如果要替換MQ供應(yīng)商,至少三個(gè)地方要替換:
- 發(fā)送方mq-client;
- MQ-server;
- 接收方mq-client。
二、平滑遷移方案
平滑遷移的目標(biāo)是:不停服,平滑升級(jí)。
如果有很多主題,需要一個(gè)一個(gè)主題的遷移,每個(gè)主題的遷移,分為三個(gè)步驟。
步驟一:消費(fèi)方雙向訂閱

如上圖所示,不妨設(shè):
- 粉色是舊MQ體系;
- 藍(lán)色是新MQ體系;
平滑遷移最終目的,是“發(fā)布-服務(wù)-訂閱”三層全由粉色升級(jí)為藍(lán)色。
第一步升級(jí)消費(fèi)方,同一個(gè)主題,既要訂閱舊MQ,又要訂閱新MQ。
此時(shí),“新服務(wù)-新訂閱”之間雖然有TCP連接,但“新發(fā)布”沒有上線,實(shí)際上不會(huì)有消息發(fā)送過來(上圖虛線),消息仍走的是舊MQ(上圖實(shí)線)。
步驟二:生產(chǎn)方升級(jí)為新發(fā)布

第二步升級(jí)生產(chǎn)方,由舊MQ發(fā)布,升級(jí)為新MQ發(fā)布。
此時(shí),“新發(fā)布-新服務(wù)-新訂閱”之間會(huì)建立TCP連接,消息會(huì)轉(zhuǎn)移到新通道(上圖實(shí)線),“舊服務(wù)-舊訂閱”之間雖然有TCP連接,但實(shí)際不會(huì)有消息發(fā)送過來(上圖虛線)。
步驟三:消費(fèi)方下線舊訂閱

第三步升級(jí)消費(fèi)方,將舊訂閱下線,整個(gè)MQ的遷移完成。
三、架構(gòu)啟示
MQ更換服務(wù)商,螞蟻搬家,一步步平滑遷移,成本其實(shí)還挺高的。
之所以這么麻煩,不能統(tǒng)一升級(jí),本質(zhì)是業(yè)務(wù)與底層基礎(chǔ)設(shè)施細(xì)節(jié)(即,具體使用哪個(gè)MQ)的耦合。如果公司在早期技術(shù)體系規(guī)劃的時(shí)候,能夠“淺淺的封裝一層”,便能隔離“業(yè)務(wù)代碼”與“底層基礎(chǔ)設(shè)施細(xì)節(jié)”。
舉個(gè)更通俗的例子。
假如沒有封裝一層,業(yè)務(wù)代碼是:
ActiveMQ-client::SendMsg(topic, msg);
ActiveMQ-client::RecvMsg(topic, msg, CALLBACK_FUNC);即,業(yè)務(wù)方需要關(guān)心ActiveMQ,如果基礎(chǔ)設(shè)施升級(jí)為RabbitMQ,業(yè)務(wù)代碼需要升級(jí)。
假如有一層淺淺的封裝:
ShenJianMQ::SendMsg(topic, msg){
ActiveMQ-client::SendMsg(topic,msg);
}
ShenJianMQ::RecvMsg(topic, msg,CALLBACK_FUNC)
ActiveMQ-client::RecvMsg(topic,msg, CALLBACK_FUNC);
}業(yè)務(wù)方不需要關(guān)心底層是什么MQ,而只需要依賴基礎(chǔ)組件ShenJianMQ。
此時(shí)如果基礎(chǔ)設(shè)施升級(jí)為RabbitMQ,只需要基礎(chǔ)組件ShenJianMQ升級(jí)。
第一步:RecvMsg升級(jí)為雙向訂閱。
ShenJianMQ::RecvMsg(topic, msg,CALLBACK_FUNC)
ActiveMQ-client::RecvMsg(topic, msg, CALLBACK_FUNC);
RabbitMQ-client::RecvMsg(topic, msg, CALLBACK_FUNC);
}第二步:SendMsg升級(jí)為新發(fā)布。
ShenJianMQ::SendMsg(topic, msg){
RabbitMQ-client::SendMsg(topic, msg);
}第三步:RecvMsg下線舊訂閱。
ShenJianMQ::RecvMsg(topic, msg,CALLBACK_FUNC)
RabbitMQ-client::RecvMsg(topic, msg, CALLBACK_FUNC);
}會(huì)發(fā)現(xiàn),除了升級(jí)依賴新版的ShenJianMQ基礎(chǔ)組件,業(yè)務(wù)代碼不需要修改代碼。
不僅MQ,緩存與數(shù)據(jù)庫(kù)的客戶端,淺淺封裝一層也能實(shí)現(xiàn)業(yè)務(wù)代碼與基礎(chǔ)組件的解耦,在基礎(chǔ)組建替換,或者基礎(chǔ)組建升級(jí)的時(shí)候,業(yè)務(wù)代碼不需要升級(jí)。
MQ平滑遷移,你學(xué)廢了嗎?
知其然,知其所以然。
思路比結(jié)論更重要。



























