消息队列如何保证消息能百分百成功被消费
消息隊(duì)列如何保證消息能百分百成功被消費(fèi)
目前常用的消息隊(duì)列有很多種,如RabbitMQ,ActiveMQ,Kafka...下面以RabbitMQ為例來(lái)講如何保證消息隊(duì)列中的信息能百分百被消費(fèi)掉.
其中消費(fèi)隊(duì)列的工作流程如下:
寫個(gè)偽代碼:
public boolean sendOrderMessage(String orderMessage){
RabbitTemplate rb = new RabbitTemplate();
try{
rb.send(orderMessage);
}catch (Exception e){
return false;
}
return true;
}
那么在訂單服務(wù)發(fā)送完消息的情況下,物流服務(wù)器突然宕機(jī),或者M(jìn)Q服務(wù)器突然宕機(jī)怎么辦?發(fā)送方已經(jīng)將消息發(fā)送,而消費(fèi)方卻沒(méi)有接收到任何需要消費(fèi)的信息,這就會(huì)導(dǎo)致,消息消費(fèi)失敗.
1)消息生產(chǎn)者把消息發(fā)送給MQ,如果接收成功,MQ會(huì)返回一個(gè)ack消息給生產(chǎn)者
2)如果消息接收不成功,MQ會(huì)返回一個(gè)nack消息給生產(chǎn)者
碰到上面的問(wèn)題,我們首先第一會(huì)想到解決方案就是發(fā)送方在消息發(fā)送到MQ之后,將消息給寫到硬盤上,這樣即使MQ服務(wù)器宕機(jī),也不會(huì)導(dǎo)致未消費(fèi)的消息丟失.
那么問(wèn)題又出現(xiàn)了,當(dāng)高并發(fā)場(chǎng)景下這種方式顯而易見是不合理的,因?yàn)榕c磁盤進(jìn)行I/O交互是相對(duì)非常慢的.當(dāng)然這種情況我們可以有解決方案: 可以在緩存中將消息緩存下來(lái),比如當(dāng)消息滿1000條時(shí)就將這些消息一次性寫到磁盤中.
這種方案雖然可以解決I/O交互問(wèn)題.但是還是不能解決宕機(jī)出現(xiàn)的問(wèn)題,假如緩存了900條消息,并且這些消息均為被消費(fèi),此時(shí)宕機(jī)了,同樣會(huì)導(dǎo)致消息的丟失.顯然這種解決方案還需要優(yōu)化.
在上面方案的基礎(chǔ)上.我們可以再增加一個(gè)機(jī)制,增加一個(gè)確認(rèn)機(jī)制,如圖:
流程解釋:
1)訂單服務(wù)生產(chǎn)者再投遞消息之前,先把消息持久化到Redis或DB中,建議redis,高性能。消息的狀態(tài)為發(fā)送中。
2)confirm機(jī)制監(jiān)聽消息是否發(fā)送成功?如ack成功消息,刪除redis中此消息。
3)如果nack不成功的消息,這個(gè)可以根據(jù)自身的業(yè)務(wù)選擇是否重發(fā)此消息。也可以刪除此消息,由自己的業(yè)務(wù)決定。
4)這邊加了個(gè)定時(shí)任務(wù),來(lái)拉取隔一定時(shí)間了,消息狀態(tài)還是為發(fā)送中的,這個(gè)狀態(tài)就表明,訂單服務(wù)是沒(méi)有收到ack成功消息。
5)定時(shí)任務(wù)會(huì)作補(bǔ)償性的投遞消息。這個(gè)時(shí)候如果MQ回調(diào)ack成功接收了,再把redis中此消息刪除
這種方案其實(shí)就是加上一個(gè)補(bǔ)償機(jī)制,不管MQ有沒(méi)有真正的接收到,只要緩存redis中的消息還是發(fā)送中的狀態(tài),就意味著這個(gè)消息沒(méi)有成功的投遞出去,也沒(méi)有被消費(fèi),定時(shí)任務(wù)啟動(dòng)時(shí)就要重新發(fā)送.
當(dāng)然定時(shí)任務(wù)那邊我們還可以加上一個(gè)補(bǔ)償?shù)拇螖?shù),如果大于3次,還是沒(méi)有收到ack消息,那就直接把消息的狀態(tài)設(shè)置為【失敗】,由人工去排查到底是為什么?
不過(guò)這樣的方案,就會(huì)有可能發(fā)送多次相同的消息,很有可能MQ已經(jīng)收到了消息,就是ack消息回調(diào)時(shí)出現(xiàn)網(wǎng)絡(luò)故障,沒(méi)有讓生產(chǎn)者收到。那就要要求消費(fèi)者一定在消費(fèi)的時(shí)候保障冪等性。
總結(jié)
以上是生活随笔為你收集整理的消息队列如何保证消息能百分百成功被消费的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: C/C++基础知识:函数指针和指针函数的
- 下一篇: Vim简本