最近在使用RabbitMQ時發(fā)現(xiàn)總有一些消息隊列中存在大量的處于unacked
狀態(tài)的消息账磺,一般來說食拜,如果隊列中ready
狀態(tài)的消息數(shù)比較多枉昏,可以認(rèn)為是消費者的處理能力不足绪氛,可以通過增加消費者來解決,而unacked
消息存在基本是有以下兩點原因:
- 消費者取走消息后沒有及時做消息確認(rèn)名斟,對于開啟手動確認(rèn)機(jī)制的脑慧,不進(jìn)行ack則消息會一直以
unacked
狀態(tài)留在隊列中。 - 消費者處理能力不足砰盐。生產(chǎn)者投放消息的速度較快闷袒,當(dāng)消費者按照
prefetch_count
設(shè)置的值取走相應(yīng)數(shù)量的消息時,這些消息都會暫時處于unacked
狀態(tài)岩梳。
我司目前對RabbitMQ的使用是基于Celery的囊骤,Celery對消息確認(rèn)采用的是early ack
晃择,即在消費者執(zhí)行task之前,就已經(jīng)向RabbitMQ發(fā)送確認(rèn)消息了也物,哪怕task產(chǎn)生異常也不會受到任何影響宫屠。所以隊列中unacked
的消息不是自定義task異常產(chǎn)生的。若是消費者處理能力不足滑蚯,則ready
狀態(tài)的消息應(yīng)該會有一定的堆積浪蹂,但是也沒有觀察到這點,所以不能判定為消費者能力的限制告材。
有沒有可能是消費者掛掉導(dǎo)致的呢坤次?消費者掛掉后,unacked
的消息會變成ready
狀態(tài)的消息重新放在隊列中斥赋,待下次消費者啟動后可以直接讀取浙踢,所以也不會是這個原因。
通過以上分析灿渴,并沒有發(fā)現(xiàn)消費者有何問題,只能嘗試從生產(chǎn)者來分析了胰舆。Celery有兩種生產(chǎn)消息的方式骚露,delay
和apply_async
。
-
delay
直接向隊列中投遞消息缚窿,消費者立時可取棘幸,任務(wù)立即可執(zhí)行 -
apply_async
投遞的定時消息,消費者立時可取倦零,任務(wù)定時執(zhí)行
任務(wù)定時執(zhí)行是Celery的功能误续,原理是amqp消息的header中存放了任務(wù)的執(zhí)行時間,Celery會根據(jù)這個時間來執(zhí)行任務(wù)扫茅,哪怕消費者掛掉了蹋嵌,當(dāng)再次啟動時,定時任務(wù)仍然能夠正常執(zhí)行葫隙。
但是栽烂,定時任務(wù)的ack消息并不是在消費者取走消息后就發(fā)送的,只有在任務(wù)真正執(zhí)行前才會發(fā)送恋脚。這也是為什么clock_queue
中存在這么多unacked
消息的原因腺办,不是真的除了什么問題,而是有這么多任務(wù)等待被執(zhí)行呢糟描。