消息發(fā)送成功后,接收端接收到了消息。然后進(jìn)行處理蚀乔,但是可能由于某種原因崔步,高并發(fā)也好,IO阻塞也好娱俺,反正這條消息在接收端處理失敗了稍味。而點(diǎn)對(duì)點(diǎn)的特性是一條消息,只會(huì)被一個(gè)接收端給接收荠卷,只要接收端A接收成功了模庐,接收端B,就不可能接收到這條消息油宜,如果是一些普通的消息還好掂碱,但是如果是一些很重要的消息怜姿,比如說用戶的支付訂單,用戶的退款疼燥,這些與金錢相關(guān)的沧卢,是必須保證成功的,那么這個(gè)時(shí)候要怎么處理呢醉者?必須要保證消息的可靠性但狭,除了消息的持久化,還包括兩個(gè)方面湃交,一是生產(chǎn)者發(fā)送的消息可以被ActiveMQ收到熟空,二是消費(fèi)者收到了ActiveMQ發(fā)送的消息。
生產(chǎn)者
send方法
在生產(chǎn)者端息罗,我們會(huì)使用send() 方法向ActiveMQ發(fā)送消息,默認(rèn)情況下才沧,持久化消息以同步方式發(fā)送迈喉,send() 方法會(huì)被阻塞温圆,直到 broker 發(fā)送一個(gè)確認(rèn)消息給生產(chǎn)者岁歉,這個(gè)確認(rèn)消息表示broker已經(jīng)成功接收到消息锅移,并且持久化消息已經(jīng)把消息保存到二級(jí)存儲(chǔ)中非剃。
事務(wù)消息
事務(wù)中消息(無論是否持久化),會(huì)進(jìn)行異步發(fā)送备绽,send() 方法不會(huì)被阻塞券坞。但是commit 方法會(huì)被阻塞,直到收到確認(rèn)消息肺素,表示broker已經(jīng)成功接收到消息恨锚,并且持久化消息已經(jīng)把消息保存到二級(jí)存儲(chǔ)中。
總結(jié)
非持久化又不在事務(wù)中的消息倍靡,可能會(huì)有消息的丟失眠冈。為保證消息可以被ActiveMQ收到,我們應(yīng)該采用事務(wù)消息或持久化消息。
消費(fèi)者
對(duì)消息的確認(rèn)有4種機(jī)制
1蜗顽、 AUTO_ACKNOWLEDGE = 1 自動(dòng)確認(rèn)
2布卡、 CLIENT_ACKNOWLEDGE = 2 客戶端手動(dòng)確認(rèn)
3、 DUPS_OK_ACKNOWLEDGE = 3 自動(dòng)批量確認(rèn)
4雇盖、 SESSION_TRANSACTED = 0 事務(wù)提交并確認(rèn)
ACK_MODE描述了Consumer與broker確認(rèn)消息的方式(時(shí)機(jī)),比如當(dāng)消息被Consumer接收之后,Consumer將在何時(shí)確認(rèn)消息忿等。所以ack_mode描述的不是producer于broker之間的關(guān)系,而是customer于broker之間的關(guān)系崔挖。
對(duì)于broker而言贸街,只有接收到ACK指令,才會(huì)認(rèn)為消息被正確的接收或者處理成功了,通過ACK,可以在consumer與Broker之間建立一種簡(jiǎn)單的“擔(dān)崩晗啵”機(jī)制.
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
第一個(gè)參數(shù):是否支持事務(wù)薛匪,如果為true,則會(huì)忽略第二個(gè)參數(shù)脓鹃,自動(dòng)被jms服務(wù)器設(shè)置為SESSION_TRANSACTED
AUTO_ACKNOWLEDGE
自動(dòng)確認(rèn)
“同步”(receive)方法返回message給消息時(shí)會(huì)立即確認(rèn)逸尖。
在"異步"(messageListener)方式中,將會(huì)首先調(diào)用listener.onMessage(message),如果onMessage方法正常結(jié)束,消息將會(huì)正常確認(rèn)瘸右。如果onMessage方法異常娇跟,將導(dǎo)致消費(fèi)者要求ActiveMQ重發(fā)消息。此外需要注意太颤,消息的重發(fā)次數(shù)是有限制的苞俘,每條消息中都會(huì)包含“redeliveryCounter”計(jì)數(shù)器,用來表示此消息已經(jīng)被重發(fā)的次數(shù)龄章,如果重發(fā)次數(shù)達(dá)到閥值吃谣,將導(dǎo)致broker端認(rèn)為此消息無法消費(fèi),此消息將會(huì)被刪除或者遷移到"dead letter"通道中。
因此當(dāng)我們使用messageListener方式消費(fèi)消息時(shí)做裙,可以在onMessage方法中使用try-catch,這樣可以在處理消息出錯(cuò)時(shí)記錄一些信息岗憋,而不是讓consumer不斷去重發(fā)消息;如果你沒有使用try-catch,就有可能會(huì)因?yàn)楫惓6鴮?dǎo)致消息重復(fù)接收的問題,需要注意onMessage方法中邏輯是否能夠兼容對(duì)重復(fù)消息的判斷
LIENT_ACKNOWLEDGE :
客戶端手動(dòng)確認(rèn)菇用,這就意味著AcitveMQ將不會(huì)“自作主張”的為你ACK任何消息澜驮,開發(fā)者需要自己擇機(jī)確認(rèn)陷揪⊥锱福可以用方法: message.acknowledge(),或session.acknowledge()悍缠;效果一樣卦绣。
如果忘記調(diào)用acknowledge方法,將會(huì)導(dǎo)致當(dāng)consumer重啟后飞蚓,會(huì)接受到重復(fù)消息滤港,因?yàn)閷?duì)于broker而言,那些尚未真正ACK的消息被視為“未消費(fèi)”。
我們可以在當(dāng)前消息處理成功之后溅漾,立即調(diào)用message.acknowledge()方法來"逐個(gè)"確認(rèn)消息山叮,這樣可以盡可能的減少因網(wǎng)絡(luò)故障而導(dǎo)致消息重發(fā)的個(gè)數(shù);當(dāng)然也可以處理多條消息之后添履,間歇性的調(diào)用acknowledge方法來一次確認(rèn)多條消息屁倔,減少ack的次數(shù)來提升consumer的效率,不過需要自行權(quán)衡暮胧。
DUPS_OK_ACKNOWLEDGE
類似于AUTO_ACK確認(rèn)機(jī)制锐借,為自動(dòng)批量確認(rèn)而生,而且具有“延遲”確認(rèn)的特點(diǎn)往衷,ActiveMQ會(huì)根據(jù)內(nèi)部算法钞翔,在收到一定數(shù)量的消息自動(dòng)進(jìn)行確認(rèn)。在此模式下席舍,可能會(huì)出現(xiàn)重復(fù)消息布轿,什么時(shí)候?當(dāng)consumer故障重啟后俺亮,那些尚未ACK的消息會(huì)重新發(fā)送過來驮捍。
SESSION_TRANSACTED
當(dāng)session使用事務(wù)時(shí),就是使用此模式脚曾。當(dāng)決定事務(wù)中的消息可以確認(rèn)時(shí)东且,必須調(diào)用session.commit()方法,commit方法將會(huì)導(dǎo)致當(dāng)前session的事務(wù)中所有消息立即被確認(rèn)本讥。在事務(wù)開始之后的任何時(shí)機(jī)調(diào)用rollback()珊泳,意味著當(dāng)前事務(wù)的結(jié)束,事務(wù)中所有的消息都將被重發(fā)拷沸。當(dāng)然在commit之前拋出異常色查,也會(huì)導(dǎo)致事務(wù)的rollback。