這篇文章將為大家詳細(xì)講解有關(guān)MQ中消息重復(fù)消費(fèi)及解決是怎樣的,文章內(nèi)容質(zhì)量較高,因此小編分享給大家做個(gè)參考,希望大家閱讀完這篇文章后對(duì)相關(guān)知識(shí)有一定的了解。
10年積累的網(wǎng)站設(shè)計(jì)制作、成都網(wǎng)站制作經(jīng)驗(yàn),可以快速應(yīng)對(duì)客戶對(duì)網(wǎng)站的新想法和需求。提供各種問(wèn)題對(duì)應(yīng)的解決方案。讓選擇我們的客戶得到更好、更有力的網(wǎng)絡(luò)服務(wù)。我雖然不認(rèn)識(shí)你,你也不認(rèn)識(shí)我。但先網(wǎng)站設(shè)計(jì)制作后付款的網(wǎng)站建設(shè)流程,更有怒江州免費(fèi)網(wǎng)站建設(shè)讓你可以放心的選擇與我們合作。
因?yàn)樵诰W(wǎng)絡(luò)延遲的情況下,消息重復(fù)發(fā)送的問(wèn)題不可避免的發(fā)生,如果非要實(shí)現(xiàn)消息不可重復(fù)發(fā)送,那基本太難,因?yàn)榫W(wǎng)絡(luò)環(huán)境無(wú)法預(yù)知,還會(huì)使程序復(fù)雜度加大,因此默認(rèn)允許消息重復(fù)發(fā)送。
只要通過(guò)網(wǎng)絡(luò)交換數(shù)據(jù),就無(wú)法避免這個(gè)問(wèn)題。所以解決這個(gè)問(wèn)題的辦法就是繞過(guò)這個(gè)問(wèn)題。那么問(wèn)題就變成了:如果消費(fèi)端收到兩條一樣的消息,應(yīng)該怎樣處理?
RabbitMQ、RocketMQ、Kafka,都有可能會(huì)出現(xiàn)消息重復(fù)消費(fèi)的問(wèn)題,正常。因?yàn)檫@問(wèn)題通常不是 MQ 自己保證的,是由我們開(kāi)發(fā)來(lái)保證的。
RabbitMQ 不保證消息不重復(fù),如果你的業(yè)務(wù)需要保證嚴(yán)格的不重復(fù)消息,需要你自己在業(yè)務(wù)端去重。
AMQP 消費(fèi)者確認(rèn)機(jī)制
AMQP 定義了消費(fèi)者確認(rèn)機(jī)制(message ack),如果一個(gè)消費(fèi)者應(yīng)用崩潰掉(此時(shí)連接會(huì)斷掉,broker 會(huì)得知),但是 broker 尚未獲得 ack,那么消息會(huì)被重新放入隊(duì)列。所以 AMQP 提供的是“至少一次交付”(at-least-once delivery),異常情況下,消息會(huì)被重復(fù)消費(fèi),此時(shí)業(yè)務(wù)要實(shí)現(xiàn)冪等性(重復(fù)消息處理)。
消息重復(fù)發(fā)布:不存在,因?yàn)?AMQP 定義了事務(wù)(tx transaction)來(lái)確保生產(chǎn)消息被 broker 接收并成功入隊(duì)。TX 事務(wù)是阻塞調(diào)用,生產(chǎn)者需等待 broker 寫磁盤后返回的確認(rèn),之后才能繼續(xù)發(fā)送消息。事務(wù)提交失敗時(shí)(如 broker 宕機(jī)場(chǎng)景),broker 并不保證提交的消息全部入隊(duì)。RabbitMQ 使用 confirm 機(jī)制來(lái)優(yōu)化生產(chǎn)消息的確認(rèn)(可以持續(xù)發(fā)布消息,但會(huì)批量回復(fù)確認(rèn))。
消息重復(fù)消費(fèi):AMQP 提供的是“至少一次交付”(at-least-once delivery),異常情況下,消息會(huì)被重復(fù)消費(fèi),此時(shí)業(yè)務(wù)要實(shí)現(xiàn)冪等性(重復(fù)消息處理)。
Kafka
Kafka 實(shí)際上有個(gè) offset 的概念,就是每個(gè)消息寫進(jìn)去,都有一個(gè) offset,代表消息的序號(hào),然后 consumer 消費(fèi)了數(shù)據(jù)之后,每隔一段時(shí)間(定時(shí)定期),會(huì)把自己消費(fèi)過(guò)的消息的 offset 提交一下。
假如,有這么個(gè)場(chǎng)景。數(shù)據(jù) 1/2/3 依次進(jìn)入 kafka,kafka 會(huì)給這三條數(shù)據(jù)每條分配一個(gè) offset,代表這條數(shù)據(jù)的序號(hào),分配的 offset 依次是 152,153,154。消費(fèi)者從 kafka 去消費(fèi)的時(shí)候,也是按照這個(gè)順序去消費(fèi)。假如當(dāng)消費(fèi)者消費(fèi)了 offset=153 的這條數(shù)據(jù),剛準(zhǔn)備去提交 offset 到 zookeeper,此時(shí)消費(fèi)者進(jìn)程被重啟了。那么此時(shí)消費(fèi)過(guò)的數(shù)據(jù) 1,2 的 offset 并沒(méi)有提交,kafka 也就不知道你已經(jīng)消費(fèi)了 offset=153 這條數(shù)據(jù)。那么重啟之后,消費(fèi)者會(huì)找 kafka 把上次消費(fèi)到的那個(gè)地方后面的數(shù)據(jù)繼續(xù)傳遞過(guò)來(lái)。數(shù)據(jù) 1,2 再次被消費(fèi)。
如果消費(fèi)者干的事兒是拿一條數(shù)據(jù)就往數(shù)據(jù)庫(kù)里寫一條,會(huì)導(dǎo)致說(shuō),你可能就把數(shù)據(jù) 1,2 在數(shù)據(jù)庫(kù)里插入了 2 次,那么數(shù)據(jù)就錯(cuò)啦。其實(shí)重復(fù)消費(fèi)不可怕,可怕的是你沒(méi)考慮到重復(fù)消費(fèi)之后,怎么保證冪等性。
解決方案
消費(fèi)端處理消息的業(yè)務(wù)邏輯保持冪等性。
冪等性,通俗點(diǎn)說(shuō),就一個(gè)數(shù)據(jù),或者一個(gè)請(qǐng)求,給你重復(fù)來(lái)多次,你得確保對(duì)應(yīng)的數(shù)據(jù)是不會(huì)改變的,不能出錯(cuò)。
比如,你拿到這個(gè)消息做數(shù)據(jù)庫(kù)的insert操作。那就容易了,給這個(gè)消息做一個(gè)唯一主鍵,那么就算出現(xiàn)重復(fù)消費(fèi)的情況,就會(huì)導(dǎo)致主鍵沖突,避免數(shù)據(jù)庫(kù)出現(xiàn)臟數(shù)據(jù)。
再比如,你拿到這個(gè)消息做redis的set的操作,那就容易了,不用解決,因?yàn)槟銦o(wú)論set幾次結(jié)果都是一樣的,set操作本來(lái)就算冪等操作。
如果上面兩種情況還不行,上大招。準(zhǔn)備一個(gè)第三方介質(zhì),來(lái)做消費(fèi)記錄。以redis為例,給消息分配一個(gè)全局id,只要消費(fèi)過(guò)該消息,將
關(guān)于MQ中消息重復(fù)消費(fèi)及解決是怎樣的就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺(jué)得文章不錯(cuò),可以把它分享出去讓更多的人看到。