導語:前端
當一個O2O電商系統到達必定規模以後,就須要考慮系統的可擴展性、鬆耦合和組件化。通常採用的都是基於時下比較流行SpringCloud和Dubbo的分佈式的微服務的架構模式,雖然模塊間可以獨立部署了,可是模塊間的仍是強依賴關係,每次改動都須要從新發版上線,產品迭代速度又快,就形成了每次上線內心都唱忐忑。數據庫
基於上面這個背景,系統須要作重構,須要解耦,所以我增長了消息總線模塊,使用異步消息隊列和標準組件來實現了模塊間的強耦合和快速的開發迭代。後端
通常的消息總線是直接使用MQ來鏈接上下游的模塊。以O2O電商系統爲例,一個訂單支付完成之後須要發送通知下游的積分模塊給用戶送積分,優惠券模塊給用戶送優惠券,微信模塊給用戶推送微信消息,短信模塊給用戶發送短信等。上下游直接經過MQ服務器創建起了消息生產和消費的關係。服務器
1.下游消費端必須增長MQ消息消費處理代碼,代碼會比較複雜,開發者必須掌握MQ消費端開發。微信
2.當下遊有多個消費端時,消費端每一個模塊須要生成一個消息對列,增長了MQ服務器的壓力。網絡
3.當下遊多個消費端執行須要有前後關係時,好比優惠券發完了才能推送微信消息,這樣就大大增長了系統設計的複雜程度。架構
針對以上幾個問題對消息總線系統進行了優化設計,看下圖:
異步
經過這種實現實現了一個下幾個特色:分佈式
1.模塊間實現了鬆耦合的機制,各業務模塊間只跟消息總線系統集成,簡化開發。微服務
2.消息確保必達,消息到達任何一端都要進行確認,出現網絡問題或其餘異常可以重試。
3.保證消息處理的冪等,不能由於重複消息致使重複執行相同的操做。
1.事件消息,以下單事件、註冊事件等,事件有惟一的編號,保證任何系統收到。
2.消費操做,如送積分、送優惠券、微信消息推送、短信發送、PUSH推送等等。
3.執行日誌,記錄每一個消費操做執行的結果,失敗能夠經過定時任務重試。
爲何增長獨立的消息生產模塊?
由於前端業務模塊比較多的時候,只能對消息的內容自己造成一個標準,很容易出現問題,增長一個消息生產模塊對外提供標準的API接口,前端業務調用按照說明添加參數便可,開發人員也不須要掌握MQ的客戶端開發的相關技術。
爲何增長獨立的消息消費模塊?
由於業務需求變化較快,後端消費模塊會常常增長新的模塊或停用已有的模塊,提供標準的消費接口供消費模塊直接實現,可以快速的實現。
消息產生模塊如何保證消息不丟失?
保證必須產生前端模塊發起消息生產的調用,由消息生產組件再發送消息到MQ,這個時候(2)若是未返回成功或網絡超時就重複發送,消息生產模塊與MQ之間的調用也是這樣,(4)未正常返回或者網絡超時(2)是返回未成功,須要從新發送消息。若是(4)返回成功就說明MQ持久化完成了(這裏消息採用持久化方式),到此階段消息發送完成。
消息消費模塊如何保證消息不丟失?
監聽MQ隊列消息,若是有消息來就存儲到db中,並ack給MQ,肯定消息收到了,而後根據數據中配置的模塊調用後端的模塊異步調用後端模塊,每個操做調用都記錄到db中,對於由於網絡或者異常未執行成功的,由定時任務按期檢查db中執行的狀態,未成功的調用的消費操做繼續調用執行,直到消費成功。
在消息生成模塊,由於消息未發送成功重試形成消息的重複,若是消息消費和後端業務不作冪等性設計就會業務數據產生影響,如用戶下單完成可能送屢次積分或者優惠券。
爲了不相同一個事件消息的重複的消費,就須要每條消息都有一個惟一的MSGID,在消息消費模塊保存到db時對消息進行惟一性的驗證,保證事件消息不重複。一樣,後端的業務模塊在實現消費接口時一樣要作冪等處理,保證相同的事件消息不重複執行,若是已執行返回成功。
電商系統中通常在下單多長時間內不支付訂單會自動取消,這是一個典型的延時消息,由於我採用的MQ是ArtemisMQ自己自然攜帶延時消息的功能,因此在這個系統中我採用的是ArtemisMQ的延時消息,到指定時間自動讓消息生效,在消息消費模塊執行。對於已經成功支付的訂單,在支付成功時增長一個刪除延時消息的消費操做,減小系統的調用,刪除使用的就是消息的MSGID。
由於ArtemisMQ自己已經實現了消息的緩衝,在消息消費端經過設定固定的線程數,就能實現消息消費的固定的消費速度,保證消息消費不會受到性能的衝擊。
使用SpringCloud+Dubbo來實現整個架構的搭建,SpringCloud用於外部rest服務的實現,Dubbo用於內部接口的調用的實現。提供消費總線接口模塊,提供公共的接口類和實體類供消費生產模塊和消息消費模塊使用。下圖爲模塊依賴關係圖。
消息生成模塊採用Dubbo實現,前端業務模塊經過Dubbo接口調用消息生成接口便可,根據要求傳遞對應的參數便可完成。
消費操做的實現採用Dubbo的RPC來實現,使用的是Dubbo的能夠動態生成消費者的特色,消息消費模塊接收到消息後會從數據庫中讀取關聯的消費操做列表,而後循環調用每一個消費操做,每一次操做執行都要記錄操做日誌並記錄結果。
經過以上幾點消息總線架構基本上設計並實現完成了!你有什麼好的建議和意見嗎?