面試題
如何保證消息沒有重復(fù)消費(fèi)?或者說(shuō),如何保證消息消費(fèi)的冪等性?
考察緣由
消息消費(fèi),肯定就要考慮到消息是否被重復(fù)消費(fèi)?能不能避免重復(fù)消費(fèi)?或者重復(fù)消費(fèi)了也別造成系統(tǒng)異??梢詥??這個(gè)是 MQ 領(lǐng)域的基本問題,其實(shí)本質(zhì)上還是問你使用消息隊(duì)列如何保證冪等性,這個(gè)是你架構(gòu)里要考慮的一個(gè)問題。
面試題剖析
一、重復(fù)消費(fèi)產(chǎn)生的問題描述
因?yàn)橄l(fā)送是基于網(wǎng)絡(luò)發(fā)送的,假設(shè)網(wǎng)絡(luò)延遲或者網(wǎng)絡(luò)卡頓,消息發(fā)送機(jī)制多次重試,消息重復(fù)發(fā)送的問題不可避免的發(fā)生。要直接避免不重復(fù)發(fā)送基本太難,因?yàn)榫W(wǎng)絡(luò)環(huán)境無(wú)法預(yù)知,還會(huì)使程序復(fù)雜度加大,因此默認(rèn)允許消息重復(fù)發(fā)送。因此無(wú)論是點(diǎn)對(duì)點(diǎn),還是發(fā)布/訂閱模型,都可能出現(xiàn)生產(chǎn)者發(fā)送多條一樣的數(shù)據(jù)到MQ,此時(shí)就會(huì)出現(xiàn)重復(fù)數(shù)據(jù)。
二、如何保證消息不被重復(fù)消費(fèi)
基于以上問題描述, MQ 自己保證發(fā)送的消息不重復(fù),這就需要我們開發(fā)來(lái)保證的。
2.1、ActiveMQ
消費(fèi)者接收到消息時(shí),將消息對(duì)象進(jìn)行MD5加密,作為消息唯一性。如果發(fā)現(xiàn)messageObj(發(fā)送到mq的數(shù)據(jù))已經(jīng)存在,則忽略,進(jìn)而保證消息不被重復(fù)消費(fèi)。
String md5 = MD5.encrypt(t.getMessageObj());
List list =super.query("SELECT * FROM message_mq WHERE MD5=? AND STATUS>=? AND STATUS<=? ",this, md5, MessageMq.MessageStatus.MESSAGE_STATUS_NORMAL, MessageMq.MessageStatus.MESSAGE_STATUS_HANDLE);
if (list !=null && list.size() >0) {
log.info("已經(jīng)有相同消息存在,忽略此消息!!! 【MESSAGE_ID】=" + t.getMessageId() +",【MESSAGE_TYPE】=" + t.getMessageType());
return 0;// 已經(jīng)有相同的消息
}
冪等性:聯(lián)想到之前數(shù)學(xué)學(xué)習(xí)的冪等性,即使公式:f(x)=f(f(x)) 能夠成立的數(shù)學(xué)性質(zhì)。用在編程領(lǐng)域,則意為對(duì)同一個(gè)系統(tǒng),使用同樣的條件,一次請(qǐng)求和重復(fù)的多次請(qǐng)求對(duì)系統(tǒng)資源的影響是一致的。而計(jì)算機(jī)冪等性,直白講就是,就一個(gè)數(shù)據(jù),或者一個(gè)請(qǐng)求,給你重復(fù)來(lái)多次,你得確保對(duì)應(yīng)的數(shù)據(jù)是不會(huì)改變的,不能出錯(cuò)。