1. 程式人生 > >RabbitMQ的架構、交換機機制和ACK機制

RabbitMQ的架構、交換機機制和ACK機制

RabbitMQ 

  1. RabbitMQ是一個由erlang開發的AMQP(Advanced Message Queue )的開源實現。
  2. RabbitMQ 即一個訊息佇列,_主要是用來實現應用程式的非同步和解耦,同時也能起到訊息緩衝,訊息分發的作用。_
  3. RabbitMQ使用的是AMQP協議,它是一種二進位制協議。預設啟動埠 5672。

RabbitMQ 的架構

  • RabbitMQ Server: 也叫broker server,它不是運送食物的卡車,而是一種傳輸服務。
    1. RabbitMQ isn’t a food truck, it’s a delivery service。 他的角色就是維護一條從Producer到Consumer的路線,保證資料能夠按照指定的方式進行傳輸。
    2. 但是這個保證也不是100%的保證,但是對於普通的應用來說這已經足夠了。
    3. 當然對於商業系統來說,可以再做一層資料一致性的guard,就可以徹底保證系統的一致性了。
  • Client A & B: 也叫Producer,資料的傳送方。
    1. create messages and publish (send) them to a broker server (RabbitMQ)。一個Message有兩個部分:payload(有效載荷)和label(標籤)。
    2. payload顧名思義就是傳輸的資料。label是exchange的名字或者說是一個tag,它描述了payload,而且RabbitMQ也是通過這個label來決定把這個Message發給哪個Consumer。
    3. AMQP僅僅描述了label,而RabbitMQ決定了如何使用這個label的規則。
  • Client 1,2,3:也叫Consumer,資料的接收方。
    1. Consumers attach to a broker server (RabbitMQ) and subscribe to a queue。把queue比作是一個有名字的郵箱。當有Message到達某個郵箱後,RabbitMQ把它傳送給它的某個訂閱者即Consumer。當然可能會把同一個Message傳送給很多的Consumer。
    2. 在這個Message中,只有payload,label已經被刪掉了。對於Consumer來說,它是不知道誰傳送的這個資訊的。就是協議本身不支援。
    3. 但是當然瞭如果Producer傳送的payload包含了Producer的資訊就另當別論了。

對於一個數據從Producer到Consumer的正確傳遞,還有幾個個概念需要明確:

其中比較重要的概念有 4 個,分別為:虛擬主機,交換機,佇列,和繫結。

  • 虛擬主機:一個虛擬主機持有一組交換機、佇列和繫結。為什麼需要多個虛擬主機呢?很簡單,RabbitMQ當中,_使用者只能在虛擬主機的粒度進行許可權控制。_因此,如果需要禁止A組訪問B組的交換機/佇列/繫結,必須為A和B分別建立一個虛擬主機。每一個RabbitMQ伺服器都有一個預設的虛擬主機“/”。
  • 交換機(Exchanges are where producers publish their messages.):Exchange 用於轉發訊息,但是它不會做儲存_ ,如果沒有 Queue bind 到 Exchange 的話,它會直接丟棄掉 Producer 傳送過來的訊息。
  • 這裡有一個比較重要的概念:路由鍵 。訊息到交換機的時候,互動機會轉發到對應的佇列中,那麼究竟轉發到哪個佇列,就要根據該路由鍵。
  • 佇列: Queues are where the messages end up and are received by consumers
  • 繫結(Bindings are how the messages get routed from the exchange to particular queues):也就是交換機需要和佇列相繫結,這其中如上圖所示,是多對多的關係。

    
還有幾個概念是上述圖中沒有標明的,那就是Connection(連線),Channel(通道,頻道)。
 

  • Connection 就是一個TCP的連線。Producer和Consumer都是通過TCP連線到RabbitMQ Server的。以後我們可以看到,程式的起始處就是建立這個TCP連線。
  • Channels 虛擬連線。它建立在上述的TCP連線中。資料流動都是在Channel中進行的。也就是說,一般情況是程式起始建立TCP連線,第二步就是建立這個Channel。

那麼,為什麼使用Channel,而不是直接使用TCP連線?

  1. 對於OS來說,建立和關閉TCP連線是有代價的,頻繁的建立關閉TCP連線對於系統的效能有很大的影響,而且TCP的連線數也有限制,
  2. 這也限制了系統處理高併發的能力。
  3. 但是,在TCP連線中建立Channel是沒有上述代價的。對於Producer或者Consumer來說,可以併發的使用多個Channel進行Publish或者Receive。
  4. 有實驗表明,1s的資料可以Publish10K的資料包。
  5. 當然對於不同的硬體環境,不同的資料包大小這個資料肯定不一樣,但是我只想說明,對於普通的Consumer或者Producer來說,這已經足夠了。
  6. 如果不夠用,你考慮的應該是如何細化split你的設計。

RabbitMQ 的交換機機制

什麼是交換機

rabbitmq的message model實際上訊息不直接傳送到queue中,中間有一個exchange是做訊息分發,producer甚至不知道訊息傳送到那個佇列中去。因此,當exchange收到message時,必須準確知道該如何分發。是append到一定規則的queue,還是append到多個queue中,還是被丟棄?這些規則都是通過exchagne的4種type去定義的。

  1. The core idea in the messaging model in RabbitMQ is that the producer never sends any messages directly to a queue. 
  2. Actually, quite often the producer doesn't even know if a message will be delivered to any queue at all.
  3. Instead, the producer can only send messages to an exchange.
  4. An exchange is a very simple thing. On one side it receives messages from producers and the other side it pushes them to queues. 
  5. The exchange must know exactly what to do with a message it receives.
  6. Should it be appended to a particular queue? Should it be appended to many queues? Or should it get discarded.
  7. The rules for that are defined by the exchange type.

exchange是一個訊息的agent,每一個虛擬的host中都有定義。它的職責是把message路由到不同的queue中。

binding

  1. exchange和queue通過routing-key關聯,這兩者之間的關係是就是binding。
  2. 如下圖所示,X表示交換機,紅色表示佇列,交換機通過一個routing-key去binding一個queue,routing-key有什麼作用呢?
  3. 看Direct exchange型別交換機。

Directed Exchange

  • 路由鍵交換機,該交換機收到訊息後會把訊息傳送到指定routing-key的queue中。那訊息交換機是怎麼知道的呢?其實,producer deliver訊息的時候會把routing-key add到 message header中。routing-key只是一個messgae的attribute。
  1. A direct exchange delivers messages to queues based on a message routing key. 
  2. The routing key is a message attribute added into the message header by the producer. 
  3. The routing key can be seen as an "address" that the exchange use to decide how to route the message.
  4. A message goes to the queue(s) whose binding key exactly matches the routing key of the message.
  • Default Exchange
  1. 這種是特殊的Direct Exchange,是rabbitmq內部預設的一個交換機。
  2. 該交換機的name是空字串,所有queue都預設binding 到該交換機上。
  3. 所有binding到該交換機上的queue,routing-key都和queue的name一樣。

Topic Exchange

  • 萬用字元交換機,exchange會把訊息傳送到一個或者多個滿足萬用字元規則的routing-key的queue。
  • 其中"_"表號匹配一個word,"#"匹配多個word和路徑,路徑之間通過"."隔開。
  • 如滿足a._.c的routing-key有a.hello.c;滿足#.hello的routing-key有a.b.c.helo。

Fanout Exchange

  • 扇形交換機,該交換機會把訊息傳送到所有binding到該交換機上的queue。這種是publisher/subcribe模式。用來做廣播最好。
  • 所有該exchagne上指定的routing-key都會被ignore掉。
  1. The fanout copies and routes a received message to all queues that are bound to it regardless of routing keys or pattern matching as with direct and topic exchanges. 
  2. Keys provided will simply be ignored.

Header Exchange

  • 設定header attribute引數型別的交換機。

RabbitMQ 的訊息持久化

  • 在生產環境中,我們需要考慮萬一生產者掛了,消費者掛了,或者 rabbitmq 掛了怎麼樣。一般來說,如果生產者掛了或者消費者掛了,其實是沒有影響,因為訊息就在佇列裡面。那麼萬一 rabbitmq 掛了,之前在佇列裡面的訊息怎麼辦,其實可以做訊息持久化,RabbitMQ 會把資訊儲存在磁碟上。
  • 做法是可以先從 Connection 物件中拿到一個 Channel 通道物件,然後再可以通過該物件設定 訊息持久化

RabbitMQ 的生產者或者消費者斷線重連

  • 這裡 Spring 有自動重連機制。

RabbitMQ 的ACK 確認機制

  • 每個Consumer可能需要一段時間才能處理完收到的資料。如果在這個過程中,Consumer出錯了,異常退出了,而資料還沒有處理完成,那麼 非常不幸,這段資料就丟失了。因為我們採用no-ack的方式進行確認,也就是說,每次Consumer接到資料後,而不管是否處理完 成,RabbitMQ Server會立即把這個Message標記為完成,然後從queue中刪除了。
  • 如果一個Consumer異常退出了,它處理的資料能夠被另外的Consumer處理,這樣資料在這種情況下就不會丟失了(注意是這種情況下)。
  • 為了保證資料不被丟失,RabbitMQ支援訊息確認機制,即acknowledgments。
  • 為了保證資料能被正確處理而不僅僅是被Consumer收到,那麼我們不能採用no-ack。而應該是在處理完資料後傳送ack。
  • 在處理資料後傳送的ack,就是告訴RabbitMQ資料已經被接收,處理完成,RabbitMQ可以去安全的刪除它了。
  • 如果Consumer退出了但是沒有傳送ack,那麼RabbitMQ就會把這個Message傳送到下一個Consumer。
  • 這樣就保證了在Consumer異常退出的情況下資料也不會丟失。

RabbitMQ 總結

  1. RabbitMQ 作用:非同步,解耦,緩衝,訊息分發。
  2. RabbitMQ 主要分為3個部分,生產者,交換機和佇列,消費者。
  3. 需要注意訊息持久化,目的為了防止 RabbitMQ 宕機;考慮 ACK 機制,目的為了如果消費者對訊息的處理失敗了,那麼後續要如何處理。