一、背景簡介
在系統開發初期,很容易出現這樣一種情況:不同業務線上開發人員,因為技術棧和版本時間的影響,在選型的時候會優先使用自己熟悉的,例如MQ中間件常用的:Kafka、Rocket、Rabbit等,這樣很容易忽略各個項目之間的組件差異問題;
在系統開發中后期,業務相對穩定之后,通常都會對資源占用較高的模塊逐步重構,公共服務進行整合管理,從而使系統更具有整體性,在這個過程中,解決不同項目的中間件差異通常首當其沖,例如常見的緩存中心,MQ消息管理等;
這種情況一般來說很難避免,系統初期為了快速支撐業務,埋下很多坑點,一旦業務可以穩定發展,並且可持續性得到驗證,就會開始適當考慮逐步進行模塊重構,降低成本。
二、重構思路
2.1 初期問題
在某創業公司研發初期,業務線上存在五個項目並行開發的情況,當時對於MQ的使用狀況如下:
- Rocket:核心業務3個項目,版本有差異;
- Kafka:數據權重偏高,1個項目采用;
- Redis:基於Python連接,隊列消息模式;
剛開始因為用的不多,整體還在可控范圍內,后續隨着業務的持續迭代,項目間出現需要通信的情況,就開始混亂難以維護,然后就是被迫開始重構,統一消息組件。
2.2 二次選型
基於業務的綜合考量,對現有幾個項目進行MQ重新設計,形成的整體架構思路如下:
- MQ組件選擇:采用RocketMQ;
- 換掉Redis組件的隊列模式;
- 將基於Python的系統改Java語言;
- 提供消息生產與消費兩個服務;
- MQ的功能由上述服務進行統一維護;
這里在核心業務線上沒有改變組件選擇,換掉kafka的一個原因是涉及大量結算業務,Redis隊列模式棄用,基於Python的管理系統功能不多,這里只是順手換掉,統一業務線的編程語言。這樣設計之后,從整體思路上看就會合理很多。
三、改造過程
3.1 整體思路
涉及核心角色說明,從左向右依次:
- 生產客戶端:需要請求服務端通信的節點,調用生產服務端封裝的消息發送接口即可;
- 生產服務端:封裝消息發送API,並維護路由管理,權限識別等,消息落地存儲等;
- 消息存儲層:主要基於消息中間件進行存儲,數據庫層面用來處理特定情況下的二次調度;
- 消費服務端:封裝消息接收API,並根據路由標識,請求指定的消費端接口,完成通信;
- 消費客戶端:響應消費服務端的請求,封裝消費時具體的業務邏輯;
在整體的技術難度上沒有太多差別,但是引入兩個服務【生產和消費】,用來管理MQ通信流程,適配特定的業務邏輯,引入數據庫做一次落地存儲,在異常流程的處理上更加靈活,這樣整個消息模塊具有很強的可擴展性。
3.2 細節描述
- 組件選型
消息中間件的選擇是比較多的,但是鑒於業務線上開發人員的熟悉程度,以及參考多方提供的測試對比報告,最終確定選用RocketMQ組件,同時RocketMQ相關特點:高性能、高可靠性,以及對分布式事務的支持,也是核心的考慮因素。
- 微服務架構
基於當前微服務的架構模式,把MQ功能本身集成在兩個核心服務中,進行統一管理和迭代,以及組件的版本控制,對於所有生產的消息,進行全局路由控制,以及特定情況下的,通過應用服務層面功能設計,實現消息延時消費,以及失敗消息的二次調度執行,和部分單條消息的手動觸發。
- 數據存儲
對消息實體進行二次存儲,主要還是適配部分特定的功能點,有些消息可以延時處理,例如當MQ隊列出現堆積的時候,或者達到監控的預警線時,可以通過配置手段,干預一部分消息只存儲入庫,不推送MQ,等待服務相對空閑的時候再去發送。
消息中間件作為系統間解耦的穩定支撐,在服務層面管理時,需要具備清晰的設計路線,以及流程關鍵節點的監控和記錄,確保整個鏈路的穩定和容錯。
同系列:分布式概念 | 分布式事務 | Kafka集群 | RocketMQ組件 | Redis集群
四、源代碼地址
GitEE·地址
https://gitee.com/cicadasmile
Wiki·地址
https://gitee.com/cicadasmile/butte-java-note/wikis
閱讀標簽
【Java基礎】【設計模式】【結構與算法】【Linux系統】【數據庫】
【分布式架構】【微服務】【大數據組件】【SpringBoot進階】【Spring&Boot基礎】