activeMQ消費消息時網絡流量異常大的問題


     公司有一個應用,多個線程從activeMQ中取消息,隨着業務的擴大,該機器占用的網絡帶寬越來越高。

仔細分析發現,mq入隊時並沒有異常高的網絡流量,僅僅在出隊時會產生很高的網絡流量。

最終發現是spring的jmsTemplate與activemq的prefetch機制配合導致的問題。

研究源碼發現jmsTemplate實現機制是:每次調用receive()時都會創建一個新的consumer對象,用完即銷毀。

正常情況下僅僅會浪費重復創建consumer的資源代價,並不至於產生正常情況十倍百倍的網絡流量。

但是activeMQ有一個提高性能的機制prefetch,此時就會有嚴重的問題。

prefetch機制:
每次consumer連接至MQ時,MQ預先存放許多message到消費者(前提是MQ中存在大量消息),預先存放message的數量取決於prefetchSize(默認為1000)。此機制的目的很顯然,是想讓客戶端代碼用一個consumer反復進行receive操作,這樣能夠大量提高出隊性能。

此機制與jmsTemplate配合時就會產生嚴重的問題,每次jmsTemplate.receive(),都會產生1000個消息的網絡流量,但是因為jmsTemplae並不會重用consumer,導致后面999個消息都被廢棄。反復jmsTemplate.receive()時,表面上看不出任何問題,其實網絡帶寬會造成大量的浪費。


解決方案:

1、若堅持使用jmsTemplate,需要設置prefetch值為1,相當於禁用了activeMQ的prefetch機制,此時感覺最健壯,就算多線程,反復調用jmsTemplate.receive()也不會有任何問題。但是會有資源浪費,因為要反復創建consumer並頻繁與服務器進行數據通信,但在性能要求不高的應用中也不算什么問題。

2、不使用jmsTemplate,手工創建一個consumer,並單線程反復使用它來receive(),此時可以充分利用prefetch機制。配合多線程的方式每個線程擁有自己的一個consumer,此時能夠充分發揮MQ在大吞吐量時的速度優勢。

切記避免多線程使用一個consumer造成的消息混亂。大吞吐量的應用推薦使用方案2,能夠充分利用prefetch機制提高系MQ的吞吐性能。

參考文檔:

介紹了acrive mq的prefetch機制,每次消費者讀取消息時, mq會預先塞給消費者prefetchSize個消息
而jmsTemplate取消息的實現方式為:創建consumer -> 取一個消息 -> 銷毀consumer,並沒有為consumer做池。
缺省設置時, prefetchSize為1000,prefetch機制取得的后999個消息都白取了。所以必須設置prefetch值為1。
 
active mq的spring支持,文章后半段Working with Spring's JmsTemplate 部分介紹了jmsTemplate
jms連接池只對connection、session、producer組池,而不對consumer做池。
因為prefetch機制的存在,如果對consumer做池,會造成池內的consumer預讀取的消息很可能無法被及時處理。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM