MQ訊息佇列
一、為什麼要用MQ?
(1)解耦:如果多個模組或者系統中,互相呼叫很複雜,維護起來比較麻煩,但是這個呼叫又不是同步呼叫,就可以運用MQ到這個業務中。
(2)非同步:這個很好理解,比如使用者的操作日誌的維護,可以不用同步處理,節約響應時間。
(3)削峰:在高峰期的時候
二、怎樣保證MQ的高可用?
RabbitMQ是比較有代表性的,因為是基於主從做高可用性的。
rabbitmq有三種模式:單機模式、普通叢集模式、映象叢集模式。
如何保證不被重複消費?
不通的消費佇列都會有一個消費通知的機制,如:
RabbitMQ提供了一個ACK確認訊息機制,
rocketMQ返回一個CONSUME_SUCCESS成功標誌
(1)比如,你拿到這個訊息做資料庫的insert操作。那就容易了,給這個訊息做一個唯一主鍵,那麼就算出現重複消費的情況,就會導致主鍵衝突,避免資料庫出現髒資料。
(2)再比如,你拿到這個訊息做redis的set的操作,那就容易了,不用解決,因為你無論set幾次結果都是一樣的,set操作本來就算冪等操作。
(3)如果上面兩種情況還不行,上大招。準備一個第三方介質,來做消費記錄。以redis為例,給訊息分配一個全域性id,只要消費過該訊息,將<id,message>以K-V形式寫入redis。那消費者開始消費前,先去redis中查詢有沒消費記錄即可。
三、如何保證消費的可靠傳輸性?
(1) 生產者丟失資料
以rabbitMQ為例,rabbitMQ提供了transaction和confirm模式來確保生產者不丟失資料,事務機制,傳送訊息前,開啟事務(channel.txSelect()),傳送訊息後出現異常,事務回滾(channel.txRollback()),傳送成功提交事務(channel.txCommit())。
上面這種方式吞吐量會下降,因此生產上應該使用confirm模式居多。
一旦channel進入confirm模式,所有在該通道釋出上的訊息都會被指派一個唯一的ID(從1開始),訊息進來如佇列後,rabbitMq會立即傳送一個ACK給生產者,其中包含了訊息的唯一ID,這就使得生產者知道訊息已經到達了訊息佇列裡。如果訊息佇列沒能處理該訊息,則會發送一個NACK給生產者進行重試操作。
) 訊息佇列丟失資料
訊息佇列丟失的情況一般是開啟持久化硬碟配置,這個持久化配置可以和confirm機制配合使用,可以在持久化硬碟之後,傳送一個ack給生產者,如果生產者收不到ack資訊,會重發資訊。
如何持久化硬碟:
①將queue的持久化標識durable設定為true,
②傳送訊息的時候將deliveryMode=2
這樣設定就算rabbitMQ掛了,重啟後也能恢復資料
(3) 消費者丟失資料
消費者丟失資料一般都是以為採用了自動確認訊息模式。消費者收到訊息後,rabbitMQ會立即從佇列裡面刪除該訊息,這是情況如果消費者出現異常而沒有及時處理該訊息就會丟失資料。
解決方案:採用手動確認訊息。
四、如何保證訊息的時序性?
先進先出佇列,比如linkedBlockingQueue。
五、如何保證訊息的順序性
解決方案:
拆分為多個queue,每個queue由一個consumer消費;
或者就一個queue但是對應一個consumer,然後這個consumer內部用記憶體佇列做排隊,然後分發給底層不同的worker來處理
人這輩子沒法做太多事情,所以每做一件事都要做到精彩絕倫。 因為,這就是我的宿命。人生苦短,你明白嗎? 所以這是我為人生做出的選擇