ActiveMQ筆記整理

孫小程發表於2020-12-08

一,應用場景:

1,非同步:不要求實時結果或者交易耗時長只能選擇非同步返回結果;

2,解耦:生產者不需要強依賴消費者。比如E動訪問核心系統出單,需要阻塞等待核心繫統返回投保結果才能進行後續操作,核心系統異常會導致E動報錯。核心要推送投保單狀態給E動,如果採用同步介面,則E動服務異常會導致投保單狀態無法正常傳送過去,並且核心會接收到異常。所以想一些實時性不高的如投保單狀態同步、費用狀態同步選擇通過MQ來實現解耦。

3,削峰:如果同時有高併發請求同時訪問某個系統,可能導致該系統服務崩潰,使用MQ作為一個緩衝,能起到削峰作用,保護後端服務正常。

二,佇列模式、主題模式:

佇列模式,就是我們的訊息訊息生產者(Producer)向一個目的地(Desitinate)存放我們的訊息,如果是多個消費者我們可以它們會分別消費這些訊息,每個訊息只能供一個消費者使用。

主題模式,訊息釋出者(生產者)向目的放傳送訊息後,多個訂閱者(消費者)可以同時接收到該訊息。可以用微信公眾號來類比記憶,所有訂閱某公眾號的微信使用者都能接收到微信公眾號推送的訊息。

主題模式還有一個持久訂閱者的概念,因為佇列模式在訊息的消費者服務掛掉時,會把訊息保留在MQ服務中(一般使用持久化訊息,該訊息即使MQ重啟也不會丟失),而主題模式如果不使用持久訂閱,則在訂閱者服務掛掉期間,

訊息釋出者釋出的訊息無法正常推送給訂閱者。此種問題的解決方法就是使用持久訂閱者的方式,在使用持久訂閱後,MQ本身會根據持久訂閱者的clientId保留該訂閱者服務掛掉期間新發布的訊息,該clientId的訂閱者上線後,訊息重新推送給該訂閱者。也可以用微信公眾號來類比記憶,我們手機斷網期間無法收到的公眾號訊息,會在我們手機聯網後接收到斷網期間訊息釋出者釋出的訊息。

三,程式碼demo(demo中是原生程式碼,實際開發過程中一般與Spring整合)

佇列訊息生產者程式碼demo:

QueueProducer.java

訊息訊息消費者程式碼demo:

QueueConsumer.java

四,幾個常見問題:

1,訊息堆積。檢查消費者服務是否線上,可通過MQ控制檯檢視consumer數量。如果消費者線上,需要檢視消費者訊息處理是否正常。如果正常,需要考慮訊息傳送速度和訊息消費速度的平衡,是否應當新增消費者節點。

2,多消費節點獲取到訊息數量差距很大,導致有的節點很忙有點節點很閒無法發揮並行優勢。需要檢視控制檯介面的prefetch數量,極端情況下,消費數量很少,但是單個訊息處理很慢,那麼可以調整prefetch數量為1,以保證多個消費節點都能拿到訊息消費。如果訊息數量很大,並且單個訊息處理很快,可以使用預設值1000。

3,死信訊息處理。預設MQ所有死信訊息會傳送到同一個DLQ佇列,不方便定位具體問題,可以考慮給每個容易出現死信訊息的佇列配置自己的死信訊息佇列,以區分處理。

4,丟訊息問題。生產者使用事務的session,保證訊息傳送成功。消費者使用client_acknowledge,保證訊息處理完成後再傳送ack給MQ的broker。訊息使用持久化機制(磁碟或者資料庫,資料庫也是磁碟持久化),保證訊息暫存於MQ時,不會因為MQ服務故障記憶體易失性問題導致訊息丟失。

5,為保證MQ服務的高可用、高效能。需要綜合MQ叢集和主備的特性,不僅有通過共享檔案實現的主備,還有使用network connector實現的多節點叢集。

6,根據實際場景選擇P2P的佇列模式或者一對多的主題模式。主題模式類似微信公眾號,可以一個消費分發給多個訂閱者,不過一般需要設定為持久訂閱者,以保證訂閱者故障恢復時仍然能接受到故障期間釋出的新訊息。

7,ActiveMQ訊息中介軟體本身目前沒有人維護,開發團隊已經轉移工作重心到新的產品上。可以考慮使用社群更為活躍的RabbitMQ、RocketMQ、Kafka。目前核心繫統在引入kafka,一個更適合分散式、大資料量的訊息中介軟體系統,kafka可以實現分散式、多分割槽、冗餘備份、釋出訂閱模式,kafka本身概念較多,並且依賴Zookeeper,還有就是kafka是用scale語言(也是執行於JVM上的語言)編寫,這些都對開發運維人員有更高的要求。
後面的是生產使用過程中遇到的問題

8,

電銷測試服務錯誤訂閱了生產叢集16MQ上主題topic.cbs.notifyBusiness.autoPrintPaperPolicy2tbs,並且設定的是持久訂閱者。昨天電銷把該測試服務關閉了,但是MQ本身會維護持久訂閱者,預設情況下持久訂閱者下線後MQ還會維護著該訂閱者,等該訂閱者上線後下線期間的訊息還能收到。
這樣就導致類似誤訂閱的訂閱者服務真的不用之後,MQ本身還維護著該訂閱者,有新訊息釋出到主題上後,會在記憶體中維護一份放在MQ的JVM記憶體中,訊息增多可能導致MQ的記憶體吃緊,過多可能導致MQ服務OOM。
為了解決該問題,可以配置一個下線持久訂閱者超時時間offlineDurableSubscriberTimeout=“1800”。不過這樣就有個問題時,如果正確的訂閱者服務突然當機超過設定的超時時間,那重新啟動服務後當機期間的訊息就丟失了,所以該配置只能臨時用來解決誤訂閱的持久訂閱者,等誤訂閱的持久訂閱者從MQ中清理後,再去掉該配置。

9,

MQ的每個佇列消費者、主題訂閱者服務都是MQ的一個連線connection,需要有一個唯一標識來區分(MQ服務級別),可通過控制檯檢視消費者的Connection ID。如果多個相同ID的監聽連線同一個MQ服務,則會報錯:

javax.jms.InvalidClientIDException: Broker: south-uat - Client: sun-consumer already connected from tcp://IP:PORT

相關文章