rocketmq 發送時異常:system busy 和 broker busy 解決方案(2019-06更新)


  推薦閱讀:https://juejin.im/post/5d996285f265da5bad40523c

  這個文章從源碼上分析了原因,並給出了解決方案。

  文章解決方案一:在broker.config中將transientStorePoolEnable=true。

  文章解決方案二:擴容broker服務器。

  具體解決方案說明,可自行閱讀文章。

------------------------以下為原內容--------------------------------------

  之前寫的解決方案,都是基於測試環境測試的.到生產環境之后,正常使用沒有問題,生產環境壓測時,又出現了system busy異常(簡直崩潰).最后在rocketmq群里大佬指導下,終於解決(希望是徹底解決).

下面直接給出結果:

目前通過生產環境各種參數修改測試得出:

broker busy異常: 可通過增大 waitTimeMillsInSendQueue 解決

system busy異常:可通過增大 osPageCacheBusyTimeOutMills 解決

#發送隊列等待時間
waitTimeMillsInSendQueue=3000
#系統頁面緩存繁忙超時時間(翻譯),默認值 1000
osPageCacheBusyTimeOutMills=5000

 

  個人猜測,出現異常的原因是因為我們同一台服務器部署的多個應用造成的.我們一台服務器上部署了 三個ES、八個redis、一個rocketmq ,壓力測試時這些都在使用,雖然cpu、內存都還有很大剩余,但是磁盤io和內存頻率畢竟只有那么多可能已經占滿,或者還有其他都會有影響。

  之前測試環境測試其他東西時,發現mq和redis同時大量使用時,redis速度會降低三到四倍,由此可見應用分服務器部署的重要性。以前知道會有影響,沒想到影響這么大。

  最終結解決方案:應該給rocketmq單獨部署性能較高的服務器.

下面給下我們完整的配置:

#broker名字,注意此處不同的配置文件填寫的不一樣
brokerClusterName=rocketmqcluster
brokerName=broker-a
#0 表示 Master, >0 表示 Slave
brokerId=0
#nameServer地址,分號分割
namesrvAddr=rocketmq-nameserver1:9876;rocketmq-nameserver2:9876
#這個配置可解決雙網卡,發送消息走外網的問題,這里配上內網ip就可以了
brokerIP1=10.30.51.149

#在發送消息時,自動創建服務器不存在的topic,默認創建的隊列數
defaultTopicQueueNums=8
#是否允許 Broker 自動創建Topic,建議線下開啟,線上關閉
autoCreateTopicEnable=false
#是否允許 Broker 自動創建訂閱組,建議線下開啟,線上關閉
autoCreateSubscriptionGroup=true
#Broker 對外服務的監聽端口
listenPort=10911
#刪除文件時間點,默認凌晨 0點
deleteWhen=03
#文件保留時間,默認 48 小時
fileReservedTime=48
#commitLog每個文件的大小默認1G
mapedFileSizeCommitLog=1073741824
#ConsumeQueue每個文件默認存30W條,根據業務情況調整
mapedFileSizeConsumeQueue=1000000
destroyMapedFileIntervalForcibly=120000
redeleteHangedFileInterval=120000
#檢測物理文件磁盤空間
diskMaxUsedSpaceRatio=88
#存儲路徑
storePathRootDir=/app/data/rocketmq/data
#commitLog 存儲路徑
storePathCommitLog=/app/data/rocketmq/data/commitlog
#消費隊列存儲路徑存儲路徑
storePathConsumeQueue=/app/data/rocketmq/data/consumerqueue
#消息索引存儲路徑
storePathIndex=/app/data/rocketmq/data/index
#checkpoint 文件存儲路徑
storeCheckpoint=/app/data/rocketmq/data/checkpoint
#abort 文件存儲路徑
abortFile=/app/data/rocketmq/data/abort
#限制的消息大小 修改為16M
maxMessageSize=‭16777216‬
#發送隊列等待時間
waitTimeMillsInSendQueue=3000
osPageCacheBusyTimeOutMills=5000
flushCommitLogLeastPages=12
flushConsumeQueueLeastPages=6
flushCommitLogThoroughInterval=30000
flushConsumeQueueThoroughInterval=180000
#Broker 的角色
#- ASYNC_MASTER 異步復制Master
#- SYNC_MASTER 同步雙寫Master
#- SLAVE
brokerRole=ASYNC_MASTER
#刷盤方式
#- ASYNC_FLUSH 異步刷盤
#- SYNC_FLUSH 同步刷盤
flushDiskType=ASYNC_FLUSH
#checkTransactionMessageEnable=false
#發消息線程池數量
sendMessageThreadPoolNums=80
#拉消息線程池數量
pullMessageThreadPoolNums=128
useReentrantLockWhenPutMessage=true

  

↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ 上面是最新更新 2019-06-13 ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑

記一次 rocketmq 使用時的異常。

  這里就不說什么rocketmq 源碼啥的了,因為沒看過。網上一搜這兩個異常 大部分都是什么源碼解讀,也沒說出現后的解決辦法(藍瘦香菇)。

大量測試發現:

1、system busy , start flow control for a while

  該異常會造成 消息丟失。

2、broker busy , start flow control for a while

  該異常不會造成消息丟失。(這是最坑的,都異常了消息竟然是正常發送了的。)

 

解決過程:

1、最開始時候 ,測試發現在性能好的服務器上 只會出現system busy,也就是說出現異常就會消息丟失。

  所以:業務代碼進行處理,出現異常就會重發到當前topic的 bak隊列,當時想的是既然這個topic busy了,就換到另外的topic去發,總不能都 busy吧。

也算是臨時解決了。

2、運行一年后,可能是服務器上運行的東西多了,或者其他原因。發現有消息重復的現象。不用想肯定是報broker busy異常,重發到topic的 bak隊列了。又因為broker busy可能不會造成消息丟失,所以消息重復就出現了。

3、無奈,找新的解決方法。本來想的是判斷異常,如果是broker busy就不重發了。

報着試一試的態度,又去百度了一下,還是搜出來一堆源碼解讀。搭上梯子,google一下,還真找到了。

https://stackoverflow.com/questions/47749906/rocketmq-throw-exception-timeout-clean-queuebroker-busy-start-flow-control-f

https://www.cnblogs.com/cs99lzzs/p/9181555.html

想到不知道在哪看的的一句話,在stackoverflow上能找到和你一樣的問題,那問題已經解決了百分之90了。這他喵的真實至理名言啊。

==============吐槽完=================

又經過大量測試驗證:

解決方案:

修改rocketmq配置文件:

方案一:sendMessageThreadPoolNums 改成 1 ,沒有的話新增一行。

  sendMessageThreadPoolNums=1

方案二(推薦):useReentrantLockWhenPutMessage改成true,沒有的話新增一行。

  sendMessageThreadPoolNums=32

  useReentrantLockWhenPutMessage=true

 

說明:

  sendMessageThreadPoolNums這個屬性是發送線程池大小, rocketmq4.1版本之后默認為 1,之前版本默認什么不知道但是肯定大於1。這個屬性改成1的話,就不用管useReentrantLockWhenPutMessage這個屬性了;

  如果改成大於1,就需要將useReentrantLockWhenPutMessage這個屬性設置為 true;

  目前測試 未發現這兩個方案有什么區別,sendMessageThreadPoolNums=1 時也支持多線程發送,發送速度感覺和 sendMessageThreadPoolNums大於1沒有區別,都能跑滿100M的網卡。

  感覺如果useReentrantLockWhenPutMessage=true的時候,就是打開鎖(屬性名翻譯一下也大概是這個意思),然后關鍵代碼其實還是單線程處理;

  有閑功夫的話去翻翻源碼看看去。

  最后 我是選擇的方案二,畢竟看着好看點。


免責聲明!

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



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