自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

RocketMQ消息中間件用起來真的可靠嗎?

開發(fā) 架構(gòu)
這篇文章對之前的Ack機制做了進一步的分析,包括底層的Delivery tag機制,以及消息處理失敗時的消息重發(fā)。

一、前情提示

上一篇文章《??MQ保證讀寫消息不丟失,這個你都不會就等著被開除吧...??》,我們初步介紹了之前制定的那些消息中間件數(shù)據(jù)不丟失的技術(shù)方案遺留的問題。

一個最大的問題,就是生產(chǎn)者投遞出去的消息,可能會丟失。

丟失的原因有很多,比如消息在網(wǎng)絡(luò)傳輸?shù)揭话氲臅r候因為網(wǎng)絡(luò)故障就丟了,或者是消息投遞到MQ的內(nèi)存時,MQ突發(fā)故障宕機導(dǎo)致消息就丟失了。

?針對這種生產(chǎn)者投遞數(shù)據(jù)丟失的問題,RabbitMQ實際上是提供了一些機制的。

比如,有一種重量級的機制,就是事務(wù)消息機制。采用類事務(wù)的機制把消息投遞到MQ,可以保證消息不丟失,但是性能極差,經(jīng)過測試性能會呈現(xiàn)幾百倍的下降。

所以說現(xiàn)在一般是不會用這種過于重量級的機制,而是會用輕量級的confirm機制。

但是我們這篇文章還不能直接講解生產(chǎn)者保證消息不丟失的confirm機制,因為這種confirm機制實際上是采用了類似消費者的ack機制來實現(xiàn)的。

所以,要深入理解confirm機制,我們得先從這篇文章開始,深?入的分析一下消費者手動ack機制保證消息不丟失的底層原理。

二、ack機制回顧

其實手動ack機制非常的簡單,必須要消費者確保自己處理完畢了一個消息,才能手動發(fā)送ack給MQ,MQ收到ack之后才會刪除這個消息。

如果消費者還沒發(fā)送ack,自己就宕機了,此時MQ感知到他的宕機,就會重新投遞這條消息給其他的消費者實例。

通過這種機制保證消費者實例宕機的時候,數(shù)據(jù)是不會丟失的。

三、ack機制實現(xiàn)原理:delivery tag

如果你寫好了一個消費者服務(wù)的代碼,讓他開始從RabbitMQ消費數(shù)據(jù),這時這個消費者服務(wù)實例就會自己注冊到RabbitMQ。

所以,RabbitMQ其實是知道有哪些消費者服務(wù)實例存在的。

大家看看下面的圖,直觀的感受一下:

接著,RabbitMQ就會通過自己內(nèi)部的一個“basic.delivery”方法來投遞消息到倉儲服務(wù)里去,讓他消費消息。

投遞的時候,會給這次消息的投遞帶上一個重要的東西,就是“delivery tag”,你可以認為是本次消息投遞的一個唯一標識。

這個所謂的唯一標識,有點類似于一個ID,比如說消息本次投遞到一個倉儲服務(wù)實例的唯一ID。通過這個唯一ID,我們就可以定位一次消息投遞。

所以這個delivery tag機制不要看很簡單,實際上他是后面要說的很多機制的核心基礎(chǔ)。

而且這里要給大家強調(diào)另外一個概念,就是每個消費者從RabbitMQ獲取消息的時候,都是通過一個channel的概念來進行的。

大家回看一下下面的消費者代碼片段,我們必須是先對指定機器上部署的RabbitMQ建立連接,然后通過這個連接獲取一個channel。

而且如果大家還有點印象的話,我們在倉儲服務(wù)里對消息的消費、ack等操作,全部都是基于這個channel來進行的,channel又有點類似于是我們跟RabbitMQ進行通信的這么一個句柄,比如看看下面的代碼:

另外這里提一句:之前寫那篇文章講解手動ack保證數(shù)據(jù)不丟失的時候,有很多人提出疑問:為什么上面代碼里直接是try finally,如果代碼有異常,那還是會直接執(zhí)行finally里的手動ack?其實很簡單,自己加上catch就可以了。

好的,咱們繼續(xù)。你大概可以認為這個channel就是進行數(shù)據(jù)傳輸?shù)囊粋€管道吧。對于每個channel而言,一個“delivery tag”就可以唯一的標識一次消息投遞,這個delivery tag大致而言就是一個不斷增長的數(shù)字。

大家來看看下面的圖,相信會很好理解的:

如果采用手動ack機制,實際上倉儲服務(wù)每次消費了一條消息,處理完畢完成調(diào)度發(fā)貨之后,就會發(fā)送一個ack消息給RabbitMQ服務(wù)器,這個ack消息是會帶上自己本次消息的delivery tag的。

咱們看看下面的ack代碼,是不是帶上了一個delivery tag?

channel.basicAck(
delivery.getEnvelope().getDeliveryTag(),
false);

然后,RabbitMQ根據(jù)哪個channel的哪個delivery tag,不就可以唯一定位一次消息投遞了?

接下來就可以對那條消息刪除,標識為已經(jīng)處理完畢。

這里大家必須注意的一點,就是delivery tag僅僅在一個channel內(nèi)部是唯一標識消息投遞的。

所以說,你ack一條消息的時候,必須是通過接受這條消息的同一個channel來進行。

大家看看下面的圖,直觀的感受一下。

其實這里還有一個很重要的點,就是我們可以設(shè)置一個參數(shù),然后就批量的發(fā)送ack消息給RabbitMQ,這樣可以提升整體的性能和吞吐量。

比如下面那行代碼,把第二個參數(shù)設(shè)置為true就可以了。

channel.basicAck(
delivery.getEnvelope().getDeliveryTag(),
true);

看到這里,大家應(yīng)該對這個ack機制的底層原理有了稍微進一步的認識了。起碼是知道delivery tag是啥東西了,他是實現(xiàn)ack的一個底層機制。

然后,我們再來簡單回顧一下自動ack、手動ack的區(qū)別。

實際上默認用自動ack,是非常簡單的。RabbitMQ只要投遞一個消息出去給倉儲服務(wù),那么他立馬就把這個消息給標記為刪除,因為他是不管倉儲服務(wù)到底接收到?jīng)]有,處理完沒有的。

所以這種情況下,性能很好,但是數(shù)據(jù)容易丟失。

如果手動ack,那么就是必須等倉儲服務(wù)完成商品調(diào)度發(fā)貨以后,才會手動發(fā)送ack給RabbitMQ,此時RabbitMQ才會認為消息處理完畢,然后才會標記消息為刪除。

這樣在發(fā)送ack之前,倉儲服務(wù)宕機,RabbitMQ會重發(fā)消息給另外一個倉儲服務(wù)實例,保證數(shù)據(jù)不丟。

四、RabbitMQ如何感知到倉儲服務(wù)實例宕機

之前就有同學(xué)提出過這個問題,但是其實要搞清楚這個問題,其實不需要深入的探索底層,只要自己大致的思考和推測一下就可以了。

如果你的倉儲服務(wù)實例接收到了消息,但是沒有來得及調(diào)度發(fā)貨,沒有發(fā)送ack,此時他宕機了。

我們想一想就知道,RabbitMQ之前既然收到了倉儲服務(wù)實例的注冊,因此他們之間必然是建立有某種聯(lián)系的。

一旦某個倉儲服務(wù)實例宕機,那么RabbitMQ就必然會感知到他的宕機,而且對發(fā)送給他的還沒ack的消息,都發(fā)送給其他倉儲服務(wù)實例。

所以這個問題以后有機會我們可以深入聊一聊,在這里,大家其實先建立起來這種認識即可。

我們再回頭看看下面的架構(gòu)圖:

五、倉儲服務(wù)處理失敗時的消息重發(fā)

首先,我們來看看下面一段代碼:

假如說某個倉儲服務(wù)實例處理某個消息失敗了,此時會進入catch代碼塊,那么此時我們怎么辦呢?難道還是直接ack消息嗎?

當(dāng)然不是了,你要是還是ack,那會導(dǎo)致消息被刪除,但是實際沒有完成調(diào)度發(fā)貨。

這樣的話,數(shù)據(jù)不是還是丟失了嗎?因此,合理的方式是使用nack操作。

就是通知RabbitMQ自己沒處理成功消息,然后讓RabbitMQ將這個消息再次投遞給其他的倉儲服務(wù)實例嘗試去完成調(diào)度發(fā)貨的任務(wù)。

我們只要在catch代碼塊里加入下面的代碼即可:

channel.basicNack(
delivery.getEnvelope().getDeliveryTag(),
true);

注意上面第二個參數(shù)是true,意思就是讓RabbitMQ把這條消息重新投遞給其他的倉儲服務(wù)實例,因為自己沒處理成功。

你要是設(shè)置為false的話,就會導(dǎo)致RabbitMQ知道你處理失敗,但是還是刪除這條消息,這是不對的。

同樣,我們還是來一張圖,大家一起來感受一下:

六、階段總結(jié)

這篇文章對之前的ack機制做了進一步的分析,包括底層的delivery tag機制,以及消息處理失敗時的消息重發(fā)。

通過ack機制、消息重發(fā)等這套機制的落地實現(xiàn),就可以保證一個消費者服務(wù)自身突然宕機、消息處理失敗等場景下,都不會丟失數(shù)據(jù)。

責(zé)任編輯:姜華 來源: 今日頭條
相關(guān)推薦

2022-08-09 08:31:29

RocketMQ消息中間件

2022-05-27 07:49:14

RocketMQ消息中間件分布式

2019-11-12 08:40:03

RocketMQ架構(gòu)

2023-06-29 10:10:06

Rocket MQ消息中間件

2023-10-24 07:50:18

消息中間件MQ

2015-08-11 11:16:36

淘寶中間件

2022-11-02 10:08:46

分布式高并發(fā)消息中間件

2021-12-14 10:39:12

中間件ActiveMQRabbitMQ

2023-05-08 08:09:26

路由元信息謂詞

2024-01-24 08:19:02

Stream應(yīng)用場景注解

2022-02-13 23:04:28

RedisRabbitMQKafka

2022-10-21 10:48:17

消息中間件互聯(lián)網(wǎng)應(yīng)用協(xié)議

2019-07-19 07:56:13

消息隊列消息代理消息中間件

2023-10-16 12:25:48

2024-07-11 11:17:00

消息隊列Java

2019-11-18 09:58:11

中間件投遞模式

2022-09-21 16:09:28

消息中間件

2019-12-13 10:32:56

開源消息中間件

2021-02-11 08:21:02

中間件開發(fā)CRUD

2011-05-24 15:10:48

點贊
收藏

51CTO技術(shù)棧公眾號