針對以上問題,一個解決思路是:保證消息的唯一性,就算是多次傳輸,不要讓消息的多次消費帶來影響;保證消息等冪性;比如:在寫入消息隊列的數(shù)據(jù)做唯一標(biāo)示,消費消
息時,根據(jù)唯一標(biāo)識判斷是否消費過;假設(shè)你有個系統(tǒng),消費一條消息就往數(shù)據(jù)庫里插入一條數(shù)據(jù),要是你一個消息重復(fù)兩次,你不就插入了兩條,這數(shù)據(jù)不就錯了?但是你要
是消費到第二次的時候,自己判斷一下是否已經(jīng)消費過了,若是就直接扔了,這樣不就保留了一條數(shù)據(jù),從而保證了數(shù)據(jù)的正確性。
發(fā)送方確認模式將信道設(shè)置成?confirm 模式(發(fā)送方確認模式),則所有在信道上發(fā)布的消息都會被指派一個唯一的?ID。
一旦消息被投遞到目的隊列后,或者消息被寫入磁盤后(可持久化的消息),信道會發(fā)送一個確認給生產(chǎn)者(包含消息唯一?ID)。
如果?RabbitMQ 發(fā)生內(nèi)部錯誤從而導(dǎo)致消息丟失,會發(fā)送一條?nack(notacknowledged,未確認)消息。
發(fā)送方確認模式是異步的,生產(chǎn)者應(yīng)用程序在等待確認的同時,可以繼續(xù)發(fā)送消息。當(dāng)確認消息到達生產(chǎn)者應(yīng)用程序,生產(chǎn)者應(yīng)用程序的回調(diào)方法就會被觸發(fā)來處理確認消息。
接收方確認機制消費者接收每一條消息后都必須進行確認(消息接收和消息確認是兩個不同操作)。只有消費者確認了消息,RabbitMQ 才能安全地把消息從隊列中刪除。
這里并沒有用到超時機制,RabbitMQ 僅通過?Consumer 的連接中斷來確認是否需要重新發(fā)送消息。也就是說,只要連接不中斷,RabbitMQ 給了
Consumer 足夠長的時間來處理消息。保證數(shù)據(jù)的最終一致性;下面羅列幾種特殊情況
消息不可靠的情況可能是消息丟失,劫持等原因;丟失又分為:生產(chǎn)者丟失消息、消息列表丟失消息、消費者丟失消息;生產(chǎn)者丟失消息:從生產(chǎn)者弄丟數(shù)據(jù)這個角度來看,
RabbitMQ提供?transaction和confirm模式來確保生產(chǎn)者不丟消息;
transaction機制就是說:發(fā)送消息前,開啟事務(wù)(channel.txSelect()),然后發(fā)送消息,如果發(fā)送過程中出現(xiàn)什么異常,事務(wù)就會回滾
(channel.txRollback()),如果發(fā)送成功則提交事務(wù)
(channel.txCommit())。然而,這種方式有個缺點:吞吐量下降;
confirm模式用的居多:一旦channel進入confirm模式,所有在該信道上發(fā)布的消息都將會被指派一個唯一的ID(從1開始),一旦消息被投遞到所有匹配的隊列之后;
rabbitMQ就會發(fā)送一個ACK給生產(chǎn)者(包含消息的唯一ID),這就使得生產(chǎn)者知道消息已經(jīng)正確到達目的隊列了;
如果rabbitMQ沒能處理該消息,則會發(fā)送一個Nack消息給你,你可以進行重試操作。
消息隊列丟數(shù)據(jù):消息持久化。
處理消息隊列丟數(shù)據(jù)的情況,一般是開啟持久化磁盤的配置。
這個持久化配置可以和confirm機制配合使用,你可以在消息持久化磁盤后,再給生產(chǎn)者發(fā)送一個Ack信號。
這樣,如果消息持久化磁盤之前,rabbitMQ陣亡了,那么生產(chǎn)者收不到Ack信號,生產(chǎn)者會自動重發(fā)。
那么如何持久化呢?
這里順便說一下吧,其實也很容易,就下面兩步
\1. 將queue的持久化標(biāo)識durable設(shè)置為true,則代表是一個持久的隊列
\2. 發(fā)送消息的時候?qū)?/span>deliveryMode=2
這樣設(shè)置以后,即使rabbitMQ掛了,重啟后也能恢復(fù)數(shù)據(jù)消費者丟失消息:消費者丟數(shù)據(jù)一般是因為采用了自動確認消息模式,改為手動確認消息即可!消費者在收到消息之
后,處理消息之前,會自動回復(fù)RabbitMQ已收到消息;如果這時處理消息失敗,就會丟失該消息;解決方案:處理消息成功后,手動回復(fù)確認消息。
首先,必然導(dǎo)致性能的下降,因為寫磁盤比寫?RAM 慢的多,message 的吞吐量可能有?10 倍的差距。
其次,message 的持久化機制用在?RabbitMQ 的內(nèi)置?cluster 方案時會出現(xiàn)“坑爹”問題。矛盾點在于,若?message 設(shè)置了?persistent 屬性,但?queue 未設(shè)置?durable 屬性,那
么當(dāng)該?queue 的?owner node 出現(xiàn)異常后,在未重建該?queue 前,發(fā)往該?queue 的?message 將被?blackholed ;若?message 設(shè)置了?persistent 屬性,同時?queue 也設(shè)置了
durable 屬性,那么當(dāng)?queue 的?owner node 異常且無法重啟的情況下,則該?queue 無法在其他?node 上重建,只能等待其?owner node 重啟后,才能恢復(fù)該?queue 的使用,
而在這段時間內(nèi)發(fā)送給該?queue 的?message 將被?blackholed 。
所以,是否要對?message 進行持久化,需要綜合考慮性能需要,以及可能遇到的問題。若想達到?100,000 條/秒以上的消息吞吐量(單?RabbitMQ 服務(wù)
器),則要么使用其他的方式來確保?message 的可靠?delivery ,要么使用非??焖俚拇鎯ο到y(tǒng)以支持全持久化(例如使用?SSD)。另外一種處理原則是:
僅對關(guān)鍵消息作持久化處理(根據(jù)業(yè)務(wù)重要程度),且應(yīng)該保證關(guān)鍵消息的量不會導(dǎo)致性能瓶頸。
RabbitMQ 是比較有代表性的,因為是基于主從(非分布式)做高可用性的,
我們就以?RabbitMQ 為例子講解第一種?MQ 的高可用性怎么實現(xiàn)。RabbitMQ 有三種模式:單機模式、普通集群模式、鏡像集群模式。
單機模式,就是?Demo 級別的,一般就是你本地啟動了玩玩兒的?,沒人生產(chǎn)用單機模式普通集群模式,意思就是在多臺機器上啟動多個?RabbitMQ 實例,每個機器啟動一個。
你創(chuàng)建的?queue,只會放在一個?RabbitMQ 實例上,但是每個實例都同步?queue 的元數(shù)據(jù)(元數(shù)據(jù)可以認為是?queue 的一些配置信息,通過元數(shù)據(jù),可以找到?queue 所在實
例)。你消費的時候,實際上如果連接到了另外一個實例,那么那個實例會從?queue 所在實例上拉取數(shù)據(jù)過來。這方案主要是提高吞吐量的,就是說讓集群中多個節(jié)點來服務(wù)某
個?queue 的讀寫操作。
鏡像集群模式:這種模式,才是所謂的?RabbitMQ 的高可用模式。跟普通集群模式不一樣的是,在鏡像集群模式下,你創(chuàng)建的?queue,無論元數(shù)據(jù)還是?queue 里的消息都會存
在于多個實例上,就是說,每個?RabbitMQ 節(jié)點都有這個?queue 的一個完整鏡像,包含?queue 的全部數(shù)據(jù)的意思。然后每次你寫消息到?queue 的時候,都會自動把消息同步到
多個實例的?queue 上。
RabbitMQ 有很好的管理控制臺,就是在后臺新增一個策略,這個策略是鏡像集群模式的策略,指定的時候是可以要求數(shù)據(jù)同步到所有節(jié)點的,也可以要求同步到指定數(shù)量的節(jié)
點,再次創(chuàng)建?queue 的時候,應(yīng)用這個策略,就會自動將數(shù)據(jù)同步到其他的節(jié)點上去了。這樣的話,好處在于,你任何一個機器宕機了,沒事兒,其它機器(節(jié)點)還包含了這
個?queue 的完整數(shù)據(jù),別的?consumer 都可以到其它節(jié)點上去消費數(shù)據(jù)。壞處在于,第一,這個性能開銷也太大了吧,消息需要同步到所有機器上,導(dǎo)致網(wǎng)絡(luò)帶寬壓力和消耗很 文章來源:http://www.zghlxwxcb.cn/news/detail-465492.html
重!RabbitMQ 一個?queue 的數(shù)據(jù)都是放在一個節(jié)點里的,鏡像集群下,也是每個節(jié)點都放這個queue 的完整數(shù)據(jù)。 文章來源地址http://www.zghlxwxcb.cn/news/detail-465492.html
到了這里,關(guān)于如何保證RabbitMQ消息的順序性的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!