MQ消息堆積終極解決方案【RabbitMQ】

如果架構中有用到mq,那就不可避免會遇到消息堆積的問題,因爲我們沒辦法保證自己生產和消費永遠都是正確的。像我們系統就遇到過很多次消息堆積情況,最嚴重的一次直接導致mq內存溢出,服務宕機,導致所有的mq消費全部出現異常,下面我就這個問題和童靴們嘮叨嘮叨。

消息推送校驗模式:

遇到這個問題,第一個想法就是在推送消息的地方做改動,比如要推送mq的時候,先檢查一下mq對應的隊列是否達到上限,如果達到就不推送。

但是如果消息具有時效性,也就是最新推送的消息和mq中已經推送的消息,是不一樣的,這個時候就不能這樣處理,而且如果推送的時候正好mq不穩定,導致獲取隊列消息失敗,就可能導致錯誤的操作,所以這種方案可用性太低。

監聽器消費模式:

後面甚至還想通過監聽器來消費掉這些堆積的消息(該監聽器只用來ack掉消息,不做任何業務處理),但是這樣不僅影響服務器的性能還影響網絡帶寬,所以這種方式也是不可取的。

腳本後臺清理模式:

最終確定下來的方案是通過腳本來刪除,因爲RabbitMq支持命令查詢、修改、清空隊列,基於這種方式,我們可以寫一個腳本,定期獲取需要監控的隊列數據情況,如果達到上限,就通過命令直接刪除,這種方式不僅可靠,而且對應用服務器沒有任何侵入性,可以很方便的實現。

腳本:

#!/bin/bash
##################################################
# vim /etc/crontab
# */30 * * * * root sh /mnt/rabbitmqMonitor/rabbitmq_monitor.cron
##################################################
#rabbitmq的環境變量
export RABBITMQPATH=/usr/lib/rabbitmq/bin
# 定義需要請求的隊列名稱數組
array_queue_name[0]="amz_RealTimeOrder:input"
array_queue_name[1]="amz_advertisement:request"
array_queue_name[2]="amz_advertisement:report"
array_queue_name[3]="mws:report:request_input"
array_queue_name[4]="mws:report:download_input"
array_queue_name[5]="amz_advertisement:info"
# 定義需要隊列所對應的最大值
declare -A queueMsgMaxMap
queueMsgMaxMap["amz_RealTimeOrder:input"]=1
queueMsgMaxMap["amz_advertisement:request"]=10000000000
queueMsgMaxMap["amz_advertisement:report"]=10000000000
queueMsgMaxMap["mws:report:request_input"]=100000000000
queueMsgMaxMap["mws:report:download_input"]=100000000000
queueMsgMaxMap["amz_advertisement:info"]=1000000000000
#獲取所有隊列的名字和每個隊列中的消息數量,存入'queueNum'數組中
queueIndex=0
for QUEUE in $(rabbitmqctl list_queues |grep -v 'Listing queues ...' | awk -F' ' '{print $1}');
do
    for queue_name in ${array_queue_name[*]}
    do
    	if [[ $QUEUE = $queue_name ]]; then
           #統計每個消息隊列的數量
    	   nums=$(rabbitmqctl list_queues |grep -w $QUEUE | awk -F' ' '{print $2}')
    	   echo -e "startPush------------$nums-----------$QUEUE---------set>>>>${queueMsgMaxMap[$QUEUE]}--------"
    	   # -ge  
    	   if [[ $nums -ge ${queueMsgMaxMap[$QUEUE]} ]]; then
              #存key
              queueName[$queueIndex]=$QUEUE
              queueIndex=`expr $queueIndex + 1`
	      echo -e "maxPush------------$num-----------$QUEUE----------------"
    	   fi
    	fi
    done
done 
#如果有異常,發送郵件
exceptionNum=${#queueName[@]}
if [[ $exceptionNum -gt 0 ]]; then
    #有隊列阻塞,exceptionName存放的爲堵塞隊列的名稱,清空隊列
    for name in ${queueName[*]}
    do
       $(rabbitmqctl -p /  purge_queue $name)
       echo -e "purge queue name>>>>>>>>>>>>>>$name"
    done
    echo "###################count at $(date +'%d-%m-%Y %H:%M:%S') ######################"
fi

注意事項:

消息堆積的時候除了要及時清理堆積消息,還要進行必要報警,像我們系統就是通過企業微信報警羣來報警的,一旦消息堆積,開發人員就可以馬上收到相關報警信息,並及時的進行處理。

還要非常重要的一點是,消息必須是無狀態的纔可以清空,不然一旦刪除將會導致數據丟失。我們在設計mq的時候,也要秉持着這種原則,因爲消息並不一定100%可靠,要做好消息丟失的措施。

想要更多幹貨、技術猛料的孩子,快點拿起手機掃碼關注我,我在這裏等你哦~

林老師帶你學編程https://wolzq.com

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章