之前寫的解決方案,都是基于測試環境測試的.到生產環境之后,正常使用沒有問題,生產環境壓測時,又出現了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
記一次 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的時候,就是打開鎖(屬性名翻譯一下也大概是這個意思),然后關鍵代碼其實還是單線程處理;
有閑功夫的話去翻翻源碼看看去。
最后 我是選擇的方案二,畢竟看著好看點。