《RabbitMQ實(shí)戰(zhàn)指南》讀書(shū)筆記

RabbitMQ簡(jiǎn)介
  1. 什么是消息中間件

消息:在應(yīng)用間傳送的數(shù)據(jù),消息可以非常簡(jiǎn)單比如只包含文本字符串、json等,也可以很復(fù)雜比如內(nèi)嵌對(duì)象

消息隊(duì)列中間件(MQ):利用高效可靠的消息傳遞機(jī)制進(jìn)行與平臺(tái)無(wú)關(guān)的數(shù)據(jù)交流,并基于數(shù)據(jù)通信來(lái)進(jìn)行分布式系統(tǒng)的集成。一般有兩種傳遞方式:點(diǎn)對(duì)點(diǎn)模式和發(fā)布/訂閱模式

  1. MQ的作用:

    • 解耦(擴(kuò)展性):MQ在處理過(guò)程中插入了一個(gè)隱含的、基于數(shù)據(jù)的接口層,兩邊的處理過(guò)程都要實(shí)現(xiàn)這一接口,允許獨(dú)立擴(kuò)展或修改兩邊的處理過(guò)程,只要確保它們遵守同樣的接口約束即可,方便提高消息入隊(duì)和處理的效率。

    • 冗余(存儲(chǔ)):有些情況下處理數(shù)據(jù)的過(guò)程會(huì)失敗。MQ可以把消息進(jìn)行持久化直到它們已經(jīng)被完全處理,規(guī)避了數(shù)據(jù)丟失風(fēng)險(xiǎn)。在把一個(gè)消息從MQ中刪除之前,需要處理系統(tǒng)明確指出該消息已經(jīng)被處理完成,從而確保數(shù)據(jù)被安全保存直到使用完畢。

    • 削峰:訪問(wèn)量劇增的情況下應(yīng)用仍然需要繼續(xù)發(fā)揮作用,但是這樣的突發(fā)流量并不常見(jiàn),如果以能處理這類峰值為標(biāo)準(zhǔn)而投入資源是巨大的浪費(fèi)。使用MQ能夠使關(guān)鍵組件支撐突發(fā)訪問(wèn)壓力。

    • 可恢復(fù)性:MQ降低了進(jìn)程間的耦合度,即使一個(gè)處理消息的進(jìn)程掛掉,加入MQ的消息仍可以在系統(tǒng)恢復(fù)后進(jìn)行處理。

    • 順序保證:在大多數(shù)使用場(chǎng)景下,數(shù)據(jù)處理順序很重要,大部分MQ支持一定程度上的順序性。

    • 異步通信:很多時(shí)候應(yīng)用不想也不需要立即處理信息。MQ提供了異步處理機(jī)制,允許應(yīng)用把一些消息放入MQ中但不立即處理它,在之后需要的時(shí)候再慢慢處理。

RabbitMQ入門
  1. 相關(guān)概念介紹

    RabbitMQ整體上是一個(gè)生產(chǎn)者消費(fèi)者模型,主要負(fù)責(zé)接受、存儲(chǔ)和轉(zhuǎn)發(fā)消息??梢园严鬟f的過(guò)程想象成:當(dāng)你講一個(gè)包裹送到郵局,郵局會(huì)暫存并最終將郵件通過(guò)郵遞員送到收件人手上。

    RabbitMQ就好比由郵局、郵箱和郵遞員組成的一個(gè)系統(tǒng)。從計(jì)算機(jī)術(shù)語(yǔ)層面上,RabbitMQ模型更像是一種交換機(jī)模型。


    rabbitMQ模型架構(gòu).png
    • 生產(chǎn)者和消費(fèi)者

      • Producer:生產(chǎn)者,投遞消息的一方。

        • 生產(chǎn)者創(chuàng)建消息,發(fā)布到RabbitMQ中

        • 消息組成

          • 消息體(payload):一般是一個(gè)帶有業(yè)務(wù)邏輯結(jié)構(gòu)的數(shù)據(jù),比如一個(gè)json字符串,可以做進(jìn)一步的序列化操作。
          • 標(biāo)簽(label):表述消息,比如一個(gè)交換器名稱和一個(gè)路由鍵,用于讓MQ以此為依據(jù)發(fā)給感興趣的消費(fèi)者
    • Consumer:消費(fèi)者,接受消息的一方。

      • 連接到MQ并訂閱隊(duì)列

      • 消費(fèi)一條消息時(shí)只是消費(fèi)消息的消息體,不知道生產(chǎn)者是誰(shuí)

    • Broker:消息中間件的服務(wù)節(jié)點(diǎn)

rabbitMQ運(yùn)轉(zhuǎn)過(guò)程.png
  • 隊(duì)列:RabbitMQ內(nèi)部對(duì)象,消息都只能存儲(chǔ)在隊(duì)列中

    • 多個(gè)消費(fèi)者可以訂閱同一個(gè)隊(duì)列,此時(shí)隊(duì)列中的消息被平均分?jǐn)偅ㄝ喸儯┙o多個(gè)消費(fèi)者進(jìn)行處理
  • 交換器

    • 生產(chǎn)者將消息發(fā)送到交換器,由交換器將消息路由到隊(duì)列


      rabbitMQ交換器.png
 - 4種類型

   - fanout

     把所有發(fā)送到該交換器的消息路由到所有與該交換器綁定的隊(duì)列中

   - direct

     把消息路由到BindingKey和RoutingKey完全匹配的隊(duì)列中

   - topic

     類似direct,匹配規(guī)則上存在*和#進(jìn)行模糊匹配,BindingKey和RoutingKey都用.來(lái)進(jìn)行分割

   - headers

     根據(jù)發(fā)送的消息內(nèi)容中的headers屬性進(jìn)行匹配,性能很差不實(shí)用
  • 路由鍵、綁定

    • 生產(chǎn)者將消息發(fā)送給交換器時(shí)需要一個(gè)RoutingKey
    • 交換器和隊(duì)列關(guān)聯(lián)通過(guò)一個(gè)BindingKey,綁定時(shí)使用的路由鍵
    • 交換器相當(dāng)于投遞包裹的郵箱,RoutingKey相當(dāng)于包裹上的地址,BindingKey相當(dāng)于包裹的目的地,當(dāng)填寫(xiě)在包裹上的地址和實(shí)際想要投遞的地址匹配時(shí)就會(huì)被正確投遞到目的地
  • connection和信道

    • NIO(非阻塞IO)

      • 包含三大核心部分:channel、buffer、selector。數(shù)據(jù)總是從信道讀取到緩沖區(qū)或者從緩沖區(qū)寫(xiě)入信道中。selector用于監(jiān)聽(tīng)多個(gè)信道事件(如連接打開(kāi),數(shù)據(jù)到達(dá)等)。單線程可以監(jiān)聽(tīng)多個(gè)數(shù)據(jù)的線道。
      • 每個(gè)信道流量不是很大時(shí)復(fù)用單一的connection可以在產(chǎn)生性能瓶頸的情況下有效節(jié)省TCP連接資源。但是當(dāng)信道本身流量很大時(shí)就需要開(kāi)辟多個(gè)connection去均攤。
    • 運(yùn)轉(zhuǎn)流程

      • 生產(chǎn)者
        • 生產(chǎn)者連接到MQ Broker建立一個(gè)連接和開(kāi)啟一個(gè)信道
        • 生產(chǎn)者聲明一個(gè)交換器并設(shè)置屬性(交換機(jī)類型、是否持久化等)
        • 生產(chǎn)者聲明一個(gè)隊(duì)列并設(shè)置屬性(是否排他、是否持久化、是否自動(dòng)刪除等)
        • 生產(chǎn)者通過(guò)RoutingKey和BindingKey綁定起來(lái)
        • 生產(chǎn)者發(fā)送消息給MQ Broker
        • 相應(yīng)的交換器根據(jù)收到的RoutingKey查找匹配的隊(duì)列
        • 如果找到則將生產(chǎn)者發(fā)送過(guò)來(lái)的消息存入相應(yīng)隊(duì)列中
        • 如果沒(méi)找到根據(jù)生產(chǎn)者配置的屬性選擇丟棄或回退給生產(chǎn)者
        • 關(guān)閉信道
        • 關(guān)閉連接
      • 消費(fèi)者
        • 消費(fèi)者連接到MQ Broker,建立一個(gè)連接和開(kāi)啟一個(gè)信道
        • 消費(fèi)者向Broker請(qǐng)求消費(fèi)相應(yīng)隊(duì)列中的消息,可能會(huì)設(shè)置相應(yīng)的回調(diào)函數(shù)以及做一些準(zhǔn)備工作
        • 等待Broker回應(yīng)并投遞相應(yīng)隊(duì)列中的消息,消費(fèi)者接收消息
        • 消費(fèi)者確認(rèn)接收到的消息回復(fù)ack
        • MQ從隊(duì)列中刪除相應(yīng)已確認(rèn)的消息
        • 關(guān)閉信道
        • 關(guān)閉連接
    rabbitMQ信道.png
  1. 消費(fèi)端的確認(rèn)與拒絕

    • 消息確認(rèn)機(jī)制

      消費(fèi)者在訂閱隊(duì)列時(shí)可以指定autoAck參數(shù)

      • autoAck=false
        • MQ會(huì)等待消費(fèi)者顯式回復(fù)確認(rèn)信號(hào)后才移去消息(實(shí)質(zhì)上是打上刪除標(biāo)記之后再刪除)
        • 對(duì)于MQ服務(wù)端來(lái)說(shuō)隊(duì)列中的消息分成了兩個(gè)部分
          • 等待投遞給消費(fèi)者的消息
          • 已經(jīng)投遞給消費(fèi)者但是還沒(méi)有收到消費(fèi)確認(rèn)信號(hào)的消息
            • 一直沒(méi)收到消費(fèi)者確認(rèn)信號(hào)而且消費(fèi)此消息的消費(fèi)者斷開(kāi)連接,MQ會(huì)安排該消息重新進(jìn)入隊(duì)列等待投遞
            • MQ不會(huì)為未確認(rèn)的消息設(shè)置過(guò)期時(shí)間,設(shè)計(jì)者允許消費(fèi)者消費(fèi)一條消息的時(shí)間可以很久很久
      • autoAck=true
        • MQ會(huì)自動(dòng)把發(fā)送出去的消息設(shè)置為確認(rèn)然后刪除,不管消費(fèi)者是否真正消費(fèi)到了
    • 消費(fèi)接收到消息后可以選擇回復(fù)拒絕

      • requeue=true

        重新將消息存入隊(duì)列以便發(fā)送給下一個(gè)訂閱的消費(fèi)者

      • requeue=false

        MQ立即把消息從隊(duì)列中移除,死信隊(duì)列可以通過(guò)檢測(cè)被拒絕或者未送達(dá)的消息來(lái)追蹤

RabbitMQ進(jìn)階
  1. 消息何去何從

    • mandatory參數(shù):交換器無(wú)法匹配到隊(duì)列后的處理
      • true:將消息返回給生產(chǎn)者
      • false:直接丟棄
    • immediate參數(shù):隊(duì)列無(wú)匹配到消費(fèi)者后的處理
      • 消息關(guān)聯(lián)的隊(duì)列上有消費(fèi)者則立刻投遞
      • 所有匹配的隊(duì)列上都沒(méi)有消費(fèi)者則直接返回給生產(chǎn)者,不用將消息入隊(duì)列而等待消費(fèi)者
      • 影響鏡像隊(duì)列的性能增加了代碼復(fù)雜性,官方建議用TTL和DLX替代
    • 備份交換器(Alternate Exchange):未被路由的消息存儲(chǔ)在備份交換器中
  2. 過(guò)期時(shí)間(TTL)

    TTL:Time to Live

    • 消息TTL
      • 對(duì)消息本身單獨(dú)設(shè)置,如隊(duì)列里也有設(shè)置則以較小值為準(zhǔn)
      • 消息過(guò)期不會(huì)馬上從隊(duì)列中抹去,因?yàn)槊織l消息是否過(guò)期是在即將投遞到消費(fèi)者之前判定的
    • 隊(duì)列TTL
      • 隊(duì)列中所有消息都有相同的過(guò)期時(shí)間
      • 一旦消息過(guò)期,直接從隊(duì)列中抹去,因?yàn)橐堰^(guò)期的消息肯定在隊(duì)列頭部
      • MQ會(huì)確保過(guò)期時(shí)間到達(dá)后將隊(duì)列刪除,但不保障刪除的動(dòng)作有多及時(shí)
    • 消息在隊(duì)列中的生存時(shí)間超過(guò)TTL時(shí)變成死信(Dead Message)
  3. 死信隊(duì)列(DLX)

    進(jìn)入到DLX的一般情況:

    • 消息被拒絕
    • 消息過(guò)期
    • 隊(duì)列達(dá)到最大長(zhǎng)度
  4. 延遲隊(duì)列

    • 延遲隊(duì)列存儲(chǔ)的對(duì)象是對(duì)應(yīng)的延遲消息,消息被發(fā)送以后并不想消費(fèi)者立刻拿到消息而是等待特定時(shí)間后消費(fèi)者才能拿到

    • 延遲隊(duì)列不是MQ本身的功能,通過(guò)DLX和TTL可以模擬

      rabbitMQ延遲隊(duì)列.png
  1. 優(yōu)先級(jí)隊(duì)列

    • 優(yōu)先級(jí)高的消息具備優(yōu)先被消費(fèi)的特權(quán)。
    • 如果消費(fèi)者的消費(fèi)速度>生產(chǎn)者的速度且Broker中沒(méi)有消息堆積,對(duì)發(fā)送的消息設(shè)置優(yōu)先級(jí)就沒(méi)有實(shí)際意義了,因?yàn)樯a(chǎn)者剛發(fā)送完一條消息就被消費(fèi)者消費(fèi)了,相當(dāng)于Broker中至多只有一條信息。
  2. 持久化

    • 交換器持久化

      • 如果交換器不設(shè)置持久化,MQ服務(wù)重啟之后相關(guān)的交換器元數(shù)據(jù)會(huì)丟失但是消息不會(huì)丟失只是不能將消息發(fā)送到這個(gè)交換器中了。
    • 隊(duì)列持久化

      • 如果隊(duì)列不設(shè)置持久化,MQ服務(wù)重啟之后相關(guān)隊(duì)列的元數(shù)據(jù)會(huì)丟失,數(shù)據(jù)也會(huì)丟失,隊(duì)列里的消息也丟失了。
      • 隊(duì)列的持久化能保證隊(duì)列本身的元數(shù)據(jù)不會(huì)因異常情況而丟失,但是并不能保證內(nèi)部存儲(chǔ)的消息不會(huì)丟失。
    • 消息持久化

      • 設(shè)置了隊(duì)列的消息的持久化,MQ服務(wù)重啟后消息才依舊存在。
      • 所有的消息都設(shè)置為持久化會(huì)嚴(yán)重影響MQ的性能。對(duì)于可靠性不是那么高的消息可以不采取持久化處理以提高整體的吞吐量。
      • 在選擇消息是否持久化時(shí)需要可靠性和吞吐量之間做一個(gè)權(quán)衡。
    • 交換器、隊(duì)列、消息都設(shè)置持久化也不能百分百保證消息不丟失

      角色 場(chǎng)景 解決方案
      消費(fèi)者 消費(fèi)者訂閱消費(fèi)隊(duì)列時(shí)autoAck設(shè)置為true,消費(fèi)者接收到信息后還沒(méi)來(lái)得及處理就宕機(jī)了 autoAck設(shè)置為false
      Broker 持久化的消息正確存入MQ之后還需要一段時(shí)間(雖然短但是不可忽視)才能存入磁盤(pán)中。MQ并不會(huì)為每條信息都進(jìn)行同步存盤(pán)的處理,可能僅僅保存到操作系統(tǒng)緩存而不是物理磁盤(pán)中,如果這段時(shí)間內(nèi)MQ服務(wù)節(jié)點(diǎn)發(fā)生宕機(jī)、重啟等異常情況,消息還沒(méi)來(lái)得及落盤(pán)消息將會(huì)丟失 1. 引入MQ鏡像隊(duì)列,配置副本,主節(jié)點(diǎn)在此特殊時(shí)間內(nèi)掛掉可以自動(dòng)切換到從節(jié)點(diǎn)保證高可用,除非整個(gè)集群都掛掉 2. 發(fā)送者引入事務(wù)機(jī)制或者發(fā)送方確認(rèn)機(jī)制來(lái)確保消息已經(jīng)正確發(fā)送存儲(chǔ)至MQ中
  3. 生產(chǎn)者確認(rèn)

    • 事務(wù)機(jī)制
      • 只有消息成功被MQ接收事務(wù)才能提交成功,捕獲異常之后進(jìn)行事務(wù)回滾的同時(shí)進(jìn)行消息重發(fā)
      • 吸干MQ的性能,從AMQP協(xié)議層面來(lái)看沒(méi)有更好辦法,但是MQ提供了改進(jìn)方案-發(fā)送方確認(rèn)機(jī)制
      • 在一條消息發(fā)送之后會(huì)使發(fā)送端阻塞以等待MQ回應(yīng),之后才能繼續(xù)發(fā)下一條消息
    • 發(fā)送方確認(rèn)機(jī)制
      • 生產(chǎn)者將信道設(shè)置成confirm模式,所有該信道上發(fā)布的消息都會(huì)被指派一個(gè)唯一的ID,一旦消息被投遞到所有匹配的隊(duì)列后MQ就會(huì)發(fā)送一個(gè)確認(rèn)(ACK)給生產(chǎn)者(包含消息的唯一ID)。如果消息和隊(duì)列都是可持久化的,ACK會(huì)在消息寫(xiě)入磁盤(pán)后發(fā)出
      • 異步機(jī)制,一旦發(fā)布一條消息生產(chǎn)者可以在等信道返回確認(rèn)的同時(shí)繼續(xù)發(fā)下一條消息,當(dāng)消息最終確認(rèn)之后生產(chǎn)者通過(guò)回調(diào)方法來(lái)處理該確認(rèn)信息,如果MQ因?yàn)樽陨韮?nèi)部錯(cuò)誤導(dǎo)致消息丟失會(huì)發(fā)送一條nack命令
      • 設(shè)置multiple參數(shù)表示到這個(gè)序號(hào)之前的所有消息都已經(jīng)得到了處理
  4. 消費(fèi)者要點(diǎn)

    • 消息分發(fā)
      • 隊(duì)列擁有多個(gè)消費(fèi)者時(shí),隊(duì)列收到的消息將以輪詢方式分發(fā)給消費(fèi)者。每條消息置灰發(fā)送給訂閱列表里的一個(gè)消費(fèi)者。負(fù)載加重時(shí)只需要?jiǎng)?chuàng)建更多的消費(fèi)者來(lái)消費(fèi)處理消息。
      • 如果有n個(gè)消費(fèi)者,MQ會(huì)將第m條消息分發(fā)給第m%n個(gè)消費(fèi)者,不管消費(fèi)者是否消費(fèi)并已經(jīng)確認(rèn)了消息。如果某些消費(fèi)者來(lái)不及消費(fèi)那么多的消息,而有些消費(fèi)者由于某些原因(如業(yè)務(wù)邏輯簡(jiǎn)單、機(jī)器性能好等)很快處理完了所分配到的消息,就會(huì)造成整體應(yīng)用吞吐量下降。
        • 解決方式:設(shè)置允許限制信道上的消費(fèi)者所能保持的最大未確認(rèn)消息的數(shù)量(對(duì)拉模式的消費(fèi)方式無(wú)效)
    • 消息順序性
      • 順序性被打破的常見(jiàn)情形
        • 生產(chǎn)者使用了事務(wù)機(jī)制或者啟用confirm時(shí)要重發(fā)消息,如果補(bǔ)償重發(fā)是在另一個(gè)線程實(shí)現(xiàn)的那么生產(chǎn)者源頭就出現(xiàn)了錯(cuò)序。
        • 生產(chǎn)者發(fā)送的消息設(shè)置了不同的超時(shí)時(shí)間并且設(shè)置了死信隊(duì)列,整體上來(lái)說(shuō)相當(dāng)于一個(gè)延遲隊(duì)列,那么消費(fèi)者在消費(fèi)這個(gè)延遲隊(duì)列時(shí)消息的順序和生產(chǎn)者發(fā)送消息的順序一致
        • 消息設(shè)置了優(yōu)先級(jí)
      • 順序性場(chǎng)景
        • 不使用任何MQ的高級(jí)特性,沒(méi)有消息丟失、網(wǎng)絡(luò)故障之類異常情況發(fā)生,只有一個(gè)消費(fèi)者和生產(chǎn)者的情況下可以保證消息的順序性
      • 保證順序性
        • 業(yè)務(wù)方使用MQ之后做進(jìn)一步處理,比如在消息體內(nèi)做全局有序標(biāo)識(shí)(類似Sequence ID)來(lái)實(shí)現(xiàn)
  5. 消息傳輸保障

    一般消息中間件的傳輸保障分為三個(gè)級(jí)別

    • At most once:最多一次,消息可能會(huì)丟失單絕不會(huì)重復(fù)傳輸

    • At least once:最少一次,消息絕不會(huì)丟失,但可能重復(fù)傳輸

    • Exactly once:恰好一次,每條消息肯定會(huì)被傳輸且僅傳輸一次-

      RabbitMQ支持At most onceAt least once

    • At most once實(shí)現(xiàn)需要考慮以下方面:

      • 生產(chǎn)者需要開(kāi)啟事務(wù)機(jī)制或者confirm機(jī)制,保證消息可以可靠傳輸?shù)組Q中

      • 生產(chǎn)者需要配合使用mandatory參數(shù)或者備份交換器來(lái)確保消息能夠從交換器路由到隊(duì)列中,進(jìn)而能保存下來(lái)不被丟棄

      • 消息和隊(duì)列都需要進(jìn)行持久化處理,以確保MQ服務(wù)器在遇到異常情況時(shí)不會(huì)丟消息

      • 消費(fèi)者在消費(fèi)消息的同時(shí)將autoAck設(shè)置為false,通過(guò)手動(dòng)確認(rèn)的方式去確認(rèn)已經(jīng)正確消費(fèi)消息以避免在消費(fèi)端引起不必要的消息丟失

    • At least once無(wú)需考慮以上方面,生產(chǎn)者隨意發(fā)送,消費(fèi)者隨意消費(fèi),不過(guò)很難保證消息不會(huì)丟失

    • Exactly once是RabbitMQ目前無(wú)法保障的

      • 重復(fù)場(chǎng)景
        • 消費(fèi)完一條消息后向MQ發(fā)送ACK時(shí)網(wǎng)絡(luò)斷開(kāi)或者其他原因MQ沒(méi)有收到ACK,MQ不會(huì)將此條消息標(biāo)記刪除。重新建立連接后消費(fèi)者還是會(huì)消費(fèi)到這條消息
        • 生產(chǎn)者使用confirm機(jī)制時(shí)發(fā)送完一條消息等待MQ返回確認(rèn)圖通知時(shí)網(wǎng)絡(luò)斷開(kāi)生產(chǎn)者捕獲到異常情況選擇重新發(fā)送,這樣MQ有兩條同樣的消息
      • 去重策略
        • 一般是業(yè)務(wù)客戶端實(shí)現(xiàn),比如引用GUID(Globally Unique Identifier),需要引入集中式緩存會(huì)增加依賴復(fù)雜度。實(shí)際生產(chǎn)環(huán)境中,業(yè)務(wù)方根據(jù)自身的業(yè)務(wù)特性進(jìn)行去重,比如業(yè)務(wù)消息本身具備冪等性,或者借助Redis等進(jìn)行去重。
RabbitMQ分布式
  1. 分布式部署方式(非互斥)

    • 集群

      • 集群遷移
        • 元數(shù)據(jù)重建
        • 數(shù)據(jù)遷移
        • 與客戶端連接的切換
    • Federation

    • Shovel

      能夠可靠、持續(xù)地從一個(gè)Broker中的隊(duì)列拉取數(shù)據(jù)轉(zhuǎn)發(fā)到另一個(gè)Broker中的交換器,,優(yōu)勢(shì)在于

      • 松耦合:Shovel可以移動(dòng)位于不同管理域中的Broker上的消息,這些Broker包含不同的用戶和vhost,也可以使用不同的RabbitMQhe Erlang版本
      • 支持廣域網(wǎng):Shovel插件同樣基于AMQP協(xié)議在Broker之間進(jìn)行通信,被設(shè)計(jì)成可以容忍時(shí)斷時(shí)續(xù)的連通情形并且能夠保證消息的可靠性
      • 高度定制:當(dāng)Shovel成功連接后可以對(duì)其進(jìn)行配置以執(zhí)行相關(guān)AMQP命令
  2. 消息堆積

    • 雙刃劍
      • 適量堆積可以有削峰、緩存只用
      • 堆積嚴(yán)重可能影響其他隊(duì)列的使用導(dǎo)致整體服務(wù)質(zhì)量下降
    • 處理方案
      • 清空隊(duì)列或者采用空消費(fèi)程序丟棄部分消息(不重要的數(shù)據(jù))
      • 增加下游消費(fèi)者的消費(fèi)能力
        • 后期優(yōu)化代碼邏輯(遠(yuǎn)水解不了近渴)
        • 增加消費(fèi)者實(shí)例數(shù)
      • 通過(guò)Shovel把隊(duì)列中的消息移交給另一個(gè)集群
  3. 隊(duì)列結(jié)構(gòu)

    • 組成

      • rabbit_amqqueue:復(fù)雜協(xié)議相關(guān)的消息處理即接收生產(chǎn)者消息、向消費(fèi)者交付消息、處理消息的確認(rèn)(包括生產(chǎn)端的confirm和消費(fèi)端的ack)

      • backing_queue:消息存儲(chǔ)的具體形式和引擎,向rabbit_amqqueue_process提供相關(guān)接口以供調(diào)用

    • 隊(duì)列消息狀態(tài)

      • alpha:消息內(nèi)容(消息體、屬性和headers)和消息索引都存儲(chǔ)在內(nèi)存中

        • 最耗內(nèi)存但很少消耗CPU
      • beta:消息內(nèi)容保存在磁盤(pán)中,消息索引保存在內(nèi)存中

      • gamma(持久化的消息才有):消息內(nèi)容保存在磁盤(pán)中,消息索引在磁盤(pán)和內(nèi)存中都有

        • 開(kāi)啟confirm時(shí)只有到了gamma狀態(tài)才會(huì)確認(rèn)該消息已被接收
      • delta:消息內(nèi)容和索引都在磁盤(pán)中

        • 基本不消耗內(nèi)存但是需要更多的CPU和磁盤(pán)IO操作

        對(duì)于持久化的消息,消息內(nèi)容和消息索引都必須先保存在磁盤(pán)上,才會(huì)出于上述狀態(tài)中的一種

  4. 惰性隊(duì)列

    • 設(shè)計(jì)場(chǎng)景
      • 默認(rèn)情況下生產(chǎn)者將消息發(fā)送到MQ的時(shí)候隊(duì)列中的消息會(huì)盡可能存儲(chǔ)在內(nèi)存中這樣可以更快速地將消息發(fā)送給消費(fèi)者。
      • 即便是持久化的消息,在被寫(xiě)入磁盤(pán)的同時(shí)也會(huì)在內(nèi)存中駐留一份備份。
      • 當(dāng)MQ需要釋放內(nèi)存的時(shí)候會(huì)將內(nèi)存中的消息換頁(yè)至磁盤(pán)中,這個(gè)操作會(huì)消費(fèi)較長(zhǎng)時(shí)間且阻塞隊(duì)列操作,進(jìn)而無(wú)法接收新的消息
    • 設(shè)計(jì)目標(biāo)
      • 盡可能將消息存入磁盤(pán)中,在消費(fèi)者消費(fèi)到相應(yīng)的消息時(shí)才被加載到內(nèi)存中
      • 能夠支持更長(zhǎng)的隊(duì)列,即支持更多的消息存儲(chǔ)
  5. 鏡像隊(duì)列

    • 可用性場(chǎng)景

      • 消息在發(fā)送之后和被寫(xiě)入磁盤(pán)并執(zhí)行刷盤(pán)動(dòng)作之間存在一個(gè)短暫且會(huì)發(fā)生問(wèn)題的時(shí)間窗,即使通過(guò)confirm機(jī)制能讓客戶端知道哪些消息已存入磁盤(pán)但是一般不希望因單點(diǎn)故障導(dǎo)致服務(wù)不可用
    • 主從結(jié)構(gòu)

      rabbitMQ主從結(jié)構(gòu).png
 -  將隊(duì)列鏡像到集群中的其他Broker節(jié)點(diǎn),如果集群中的一個(gè)節(jié)點(diǎn)失效隊(duì)列能自動(dòng)切換到鏡像中的另一個(gè)節(jié)點(diǎn)上以保證服務(wù)的可用性

 - slave會(huì)準(zhǔn)確按照master執(zhí)行命令的順序進(jìn)行動(dòng)作,故slave與master上維護(hù)的狀態(tài)應(yīng)該是相同的。如果master由于某種原因失效,那么“資歷最老”(加入時(shí)間最長(zhǎng))的slave會(huì)被提升為新的master。 

 - 發(fā)送到鏡像隊(duì)列的所有消息會(huì)被同時(shí)發(fā)往master和所有slave上,如果此時(shí)master掛了消息還會(huì)在slave上這樣slave提升為master的消息消息也不會(huì)丟失。

 - 消費(fèi)者與slave建立連接并進(jìn)行訂閱消費(fèi)時(shí),實(shí)質(zhì)上都是從master上獲取消息,只不過(guò)看起來(lái)是從slave上消費(fèi)而已。大多的讀寫(xiě)壓力都是落在了master。

   - 這里的master和slave是針對(duì)隊(duì)列而言的,隊(duì)列可以均勻散落在集群的各個(gè)Broker節(jié)點(diǎn)以達(dá)到負(fù)載均衡的目的

   - 真正的負(fù)載是針對(duì)實(shí)際的機(jī)器而言的而不是內(nèi)存中駐留的隊(duì)列進(jìn)程

   - 至于為什么不像Mysql一樣讀寫(xiě)分離,RabbitMQ從編程邏輯上完全可以實(shí)現(xiàn)但是得不到更好的收益即不能進(jìn)一步優(yōu)化負(fù)載,卻會(huì)增加編碼實(shí)現(xiàn)的復(fù)雜度增加出錯(cuò)可能
rabbitMQ集群結(jié)構(gòu).png
  • 確認(rèn)機(jī)制

    • RabbitMQ鏡像隊(duì)列支持confirm和事務(wù)兩種機(jī)制
      • 在事務(wù)機(jī)制中,只有前事務(wù)在全部鏡像中執(zhí)行之后客戶端才會(huì)收到提交成功的消息。
      • 在confirm機(jī)制中,生產(chǎn)者進(jìn)行當(dāng)前確認(rèn)的前提是該消息被全部進(jìn)行所接收了。
  • 節(jié)點(diǎn)機(jī)制

    • master掛了
      • 與master連接的客戶端連接全部斷開(kāi)
      • 選舉最老的slave作為新的master,因?yàn)樽罾系膕lave與舊的master之間的同步狀態(tài)應(yīng)該是最好的。如果此時(shí)所有slave處于未同步狀態(tài)則未同步的消息會(huì)丟失
      • 新的master重新入隊(duì)所有unack的消息,因?yàn)樾碌膕lave無(wú)法區(qū)分這些unack消息是否已經(jīng)達(dá)到客戶端,或者是ack信息丟失在老的master鏈路上。出于消息可靠性的考慮重新入隊(duì)所有unack的消息,客戶端可能會(huì)有重復(fù)消息
  1. 網(wǎng)絡(luò)分區(qū)

    • 設(shè)計(jì)思路
      • 鏡像隊(duì)列有比較強(qiáng)的一致性,如果出現(xiàn)網(wǎng)絡(luò)波動(dòng)或者網(wǎng)絡(luò)故障等異常情況整個(gè)數(shù)據(jù)鏈的性能大大降低,所以引入網(wǎng)絡(luò)分區(qū)來(lái)講異常的節(jié)點(diǎn)剝離出整個(gè)分區(qū),以確保MQ服務(wù)的可用性及可靠性。等待網(wǎng)絡(luò)恢復(fù)后進(jìn)行相應(yīng)的處理將之前異常節(jié)點(diǎn)加入集群中。
    • 判定思路
      • 如果某節(jié)點(diǎn)出現(xiàn)網(wǎng)絡(luò)故障,或者是端口不通,則會(huì)致使與此節(jié)點(diǎn)的交互出現(xiàn)中斷,這里會(huì)有個(gè)超時(shí)判定機(jī)制
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容