https://blog.csdn.net/chang384915878/article/details/86742792
面試題
如何解決消息隊(duì)列的延時(shí)以及過期失效問題怎棱?消息隊(duì)列滿了以后該怎么處理?有幾百萬消息持續(xù)積壓幾小時(shí)墩新,說說怎么解決?
面試官心理分析
你看這問法,其實(shí)本質(zhì)針對(duì)的場(chǎng)景,都是說柴罐,可能你的消費(fèi)端出了問題,不消費(fèi)了综芥;或者消費(fèi)的速度極其慢丽蝎。接著就坑爹了猎拨,可能你的消息隊(duì)列集群的磁盤都快寫滿了膀藐,都沒人消費(fèi),這個(gè)時(shí)候怎么辦红省?或者是這整個(gè)就積壓了幾個(gè)小時(shí)额各,你這個(gè)時(shí)候怎么辦?或者是你積壓的時(shí)間太長(zhǎng)了吧恃,導(dǎo)致比如 RabbitMQ 設(shè)置了消息過期時(shí)間后就沒了怎么辦虾啦?
所以就這事兒,其實(shí)線上挺常見的痕寓,一般不出傲醉,一出就是大 case。一般常見于呻率,舉個(gè)例子硬毕,消費(fèi)端每次消費(fèi)之后要寫 mysql,結(jié)果 mysql 掛了礼仗,消費(fèi)端 hang 那兒了吐咳,不動(dòng)了逻悠;或者是消費(fèi)端出了個(gè)什么岔子,導(dǎo)致消費(fèi)速度極其慢韭脊。
面試題剖析
關(guān)于這個(gè)事兒童谒,我們一個(gè)一個(gè)來梳理吧,先假設(shè)一個(gè)場(chǎng)景沪羔,我們現(xiàn)在消費(fèi)端出故障了饥伊,然后大量消息在 mq 里積壓,現(xiàn)在出事故了蔫饰,慌了撵渡。
大量消息在 mq 里積壓了幾個(gè)小時(shí)了還沒解決
幾千萬條數(shù)據(jù)在 MQ 里積壓了七八個(gè)小時(shí),從下午 4 點(diǎn)多死嗦,積壓到了晚上 11 點(diǎn)多趋距。這個(gè)是我們真實(shí)遇到過的一個(gè)場(chǎng)景,確實(shí)是線上故障了越除,這個(gè)時(shí)候要不然就是修復(fù) consumer 的問題节腐,讓它恢復(fù)消費(fèi)速度,然后傻傻的等待幾個(gè)小時(shí)消費(fèi)完畢摘盆。這個(gè)肯定不能在面試的時(shí)候說吧翼雀。
一個(gè)消費(fèi)者一秒是 1000 條,一秒 3 個(gè)消費(fèi)者是 3000 條孩擂,一分鐘就是 18 萬條狼渊。所以如果你積壓了幾百萬到上千萬的數(shù)據(jù),即使消費(fèi)者恢復(fù)了类垦,也需要大概 1 小時(shí)的時(shí)間才能恢復(fù)過來狈邑。
一般這個(gè)時(shí)候,只能臨時(shí)緊急擴(kuò)容了蚤认,具體操作步驟和思路如下:
先修復(fù) consumer 的問題米苹,確保其恢復(fù)消費(fèi)速度,然后將現(xiàn)有 consumer 都停掉砰琢。
新建一個(gè) topic蘸嘶,partition 是原來的 10 倍,臨時(shí)建立好原先 10 倍的 queue 數(shù)量陪汽。
然后寫一個(gè)臨時(shí)的分發(fā)數(shù)據(jù)的 consumer 程序训唱,這個(gè)程序部署上去消費(fèi)積壓的數(shù)據(jù),消費(fèi)之后不做耗時(shí)的處理挚冤,直接均勻輪詢寫入臨時(shí)建立好的 10 倍數(shù)量的 queue况增。
接著臨時(shí)征用 10 倍的機(jī)器來部署 consumer,每一批 consumer 消費(fèi)一個(gè)臨時(shí) queue 的數(shù)據(jù)你辣。這種做法相當(dāng)于是臨時(shí)將 queue 資源和 consumer 資源擴(kuò)大 10 倍巡通,以正常的 10 倍速度來消費(fèi)數(shù)據(jù)尘执。
等快速消費(fèi)完積壓數(shù)據(jù)之后,得恢復(fù)原先部署的架構(gòu)宴凉,重新用原先的 consumer 機(jī)器來消費(fèi)消息誊锭。
mq 中的消息過期失效了
假設(shè)你用的是 RabbitMQ,RabbtiMQ 是可以設(shè)置過期時(shí)間的弥锄,也就是 TTL丧靡。如果消息在 queue 中積壓超過一定的時(shí)間就會(huì)被 RabbitMQ 給清理掉,這個(gè)數(shù)據(jù)就沒了籽暇。那這就是第二個(gè)坑了温治。這就不是說數(shù)據(jù)會(huì)大量積壓在 mq 里,而是大量的數(shù)據(jù)會(huì)直接搞丟戒悠。
這個(gè)情況下熬荆,就不是說要增加 consumer 消費(fèi)積壓的消息,因?yàn)閷?shí)際上沒啥積壓绸狐,而是丟了大量的消息卤恳。我們可以采取一個(gè)方案,就是批量重導(dǎo)寒矿,這個(gè)我們之前線上也有類似的場(chǎng)景干過突琳。就是大量積壓的時(shí)候,我們當(dāng)時(shí)就直接丟棄數(shù)據(jù)了符相,然后等過了高峰期以后拆融,比如大家一起喝咖啡熬夜到晚上12點(diǎn)以后,用戶都睡覺了啊终。這個(gè)時(shí)候我們就開始寫程序镜豹,將丟失的那批數(shù)據(jù),寫個(gè)臨時(shí)程序孕索,一點(diǎn)一點(diǎn)的查出來逛艰,然后重新灌入 mq 里面去躏碳,把白天丟的數(shù)據(jù)給他補(bǔ)回來搞旭。也只能是這樣了。
假設(shè) 1 萬個(gè)訂單積壓在 mq 里面菇绵,沒有處理肄渗,其中 1000 個(gè)訂單都丟了,你只能手動(dòng)寫程序把那 1000 個(gè)訂單給查出來咬最,手動(dòng)發(fā)到 mq 里去再補(bǔ)一次翎嫡。
mq 都快寫滿了
如果消息積壓在 mq 里,你很長(zhǎng)時(shí)間都沒有處理掉永乌,此時(shí)導(dǎo)致 mq 都快寫滿了惑申,咋辦具伍?這個(gè)還有別的辦法嗎?沒有圈驼,誰讓你第一個(gè)方案執(zhí)行的太慢了人芽,你臨時(shí)寫程序,接入數(shù)據(jù)來消費(fèi)绩脆,消費(fèi)一個(gè)丟棄一個(gè)萤厅,都不要了,快速消費(fèi)掉所有的消息靴迫。然后走第二個(gè)方案惕味,到了晚上再補(bǔ)數(shù)據(jù)吧。