rabbitMQ

RabitMQ採用Erlang語言實現的AMQP(Advanced Message Queued Protocol)的消息中間件,最初起源於金融系統,用在分佈式系統存儲轉發消息。

RabbitMQ發展到今天,被越來越多的人認可,這和它在易用性、擴展性、可靠性和高可用性等方面的卓著表現是分不開的。RabbitMQ的具體特點可以概括爲以下幾點:

  • 可靠性:RabbitMQ使用一些機制來保證可靠性,如持久化、傳輸確認及發佈確認等。

  • 靈活的路由:在消息進入隊列之前,通過交換器來路由消息。對於典型的路由功能,RabbitMQ己經提供了一些內置的交換器來實現。針對更復雜的路由功能,可以將多個交換器綁定在一起,也可以通過插件機制來實現自己的交換器。

  • 擴展性:多個RabbitMQ節點可以組成一個集羣,也可以根據實際業務情況動態地擴展集羣中節點。

  • 高可用性:隊列可以在集羣中的機器上設置鏡像,使得在部分節點出現問題的情況下隊仍然可用。

  • 多種協議:RabbitMQ除了原生支持AMQP協議,還支持STOMP,MQTT等多種消息中間件協議。

  • 多語言客戶端:RabbitMQ幾乎支持所有常用語言,比如Jav a、Python、Ruby、PHP、C#、JavaScript等。

  • 管理界面:RabbitMQ提供了一個易用的用戶界面,使得用戶可以監控和管理消息、集羣中的節點等。

  • 插件機制:RabbitMQ提供了許多插件,以實現從多方面進行擴展,當然也可以編寫自己的插件。

一、安裝 

1. 安裝erlang、rabbitMq

https://blog.csdn.net/qq_22638399/article/details/81704372

2. 安裝php-amqp擴展

apt-get install php-amqp

 

二、PHP demo

https://www.cnblogs.com/miketwais/p/RabbitMQ.html

 

三、工作原理

消費者:接收消息

邏輯:
創建連接-->創建channel-->創建交換機-->創建隊列-->綁定交換機/隊列/路由鍵-->接收消息(阻塞模式)

生產者:發送消息

邏輯:
創建連接-->創建channel-->創建交換機對象-->發送消息

配置多個消費者

設置不同的路由key,消息會輪流發給每個消費者(比如說有3個消費者,4個任務。分別分發每個消費者一個任務後,第4個任務又分發給了第一個消費者)。

四、交換機(exchange)

類型

說明

路由規則

Default

默認交換機

自動命名的直交換機

Direct

直連交換機

Routing Key==Binding Key,嚴格匹配

Fanout

扇型交換機

把發送到該 Exchange 的消息路由到所有與它綁定的 Queue 中

Topic

主題交換機

Routing Key==Binding Key,模糊匹配

Headers

頭交換機

根據發送的消息內容中的 headers 屬性進行匹配

        轉自 https://blog.csdn.net/weixin_37641832/article/details/83270778

五、名詞解釋

連接
AMQP 連接通常是長連接。AMQP 是一個使用 TCP 提供可靠投遞的應用層協議。AMQP 使用認證機制並且提供 TLS(SSL)保護。當一個應用不再需要連接到 AMQP 代理的時候,需要優雅的釋放掉 AMQP 連接,而不是直接將 TCP 連接關閉。

通道(處理多連接)
有些應用需要與 AMQP 代理建立多個連接。無論怎樣,同時開啓多個 TCP 連接都是不合適的,因爲這樣做會消耗掉過多的系統資源並且使得防火牆的配置更加困難。AMQP 0-9-1 提供了通道(channels)來處理多連接,可以把通道理解成共享一個 TCP 連接的多個輕量化連接。

在涉及多線程 / 進程的應用中,爲每個線程 / 進程開啓一個通道(channel)是很常見的,並且這些通道不能被線程 / 進程共享。

一個特定通道上的通訊與其他通道上的通訊是完全隔離的,因此每個 AMQP 方法都需要攜帶一個通道號,這樣客戶端就可以指定此方法是爲哪個通道準備的。

虛擬主機
爲了在一個單獨的代理上實現多個隔離的環境(用戶、用戶組、交換機、隊列 等),AMQP 提供了一個虛擬主機(virtual hosts - vhosts)的概念。這跟 Web servers 虛擬主機概念非常相似,這爲 AMQP 實體提供了完全隔離的環境。當連接被建立的時候,AMQP 客戶端來指定使用哪個虛擬主機。
 

備註:

  • 隊列與交換機、路由綁定後,關係就會一直存在,想要重新設置綁定關係需要去管理界面清除綁定

常見問題

1、怎樣才能做到按照每個消費者的能力分配消息呢?

聯合使用 Qos 和 Acknowledge 就可以做到。basicQos 方法設置了當前信道最大預獲取(prefetch)消息數量爲1。消息從隊列異步推送給消費者,消費者的 ack 也是異步發送給隊列,從隊列的視角去看,總是會有一批消息已推送但尚未獲得 ack 確認,Qos 的 prefetchCount 參數就是用來限制這批未確認消息數量的。設爲1時,隊列只有在收到消費者發回的上一條消息 ack 確認後,纔會向該消費者發送下一條消息。prefetchCount 的默認值爲0,即沒有限制,隊列會將所有消息儘快發給消費者。

2、消息的確認模式

消費者從隊列中獲取消息,服務端如何知道消息已經被消費呢?

模式1:自動確認
只要消息從隊列中獲取,無論消費者獲取到消息後是否成功消息,都認爲是消息已經成功消費。
模式2:手動確認
消費者從隊列中獲取消息後,服務器會將該消息標記爲不可用狀態,等待消費者的反饋,如果消費者一直沒有反饋,那麼該消息將一直處於不可用狀態。
 

3、交換機和隊列持久化

持久化:將交換機或隊列的數據保存到磁盤,服務器宕機或重啓之後依然存在。
非持久化:將交換機或隊列的數據保存到內存,服務器宕機或重啓之後將不存在。

非持久化的性能高於持久化。如何選擇持久化?非持久化? – 看需求。

 

4、如何保證消息不被重複消費(如何保證消息消費時的冪等性

正常情況下,消費者在消費消息時候,消費完畢後,會發送一個確認信息給消息隊列,消息隊列就知道該消息被消費了,就會將該消息從消息隊列中刪除。那造成重複消費的原因?,就是因爲網絡傳輸等等故障,確認信息沒有傳送到消息隊列,導致消息隊列不知道自己已經消費過該消息了,再次將該消息分發給其他的消費者。

這個問題針對業務場景來答分以下幾點
  (1)比如,你拿到這個消息做數據庫的insert操作。那就容易了,給這個消息做一個唯一主鍵,那麼就算出現重複消費的情況,就會導致主鍵衝突,避免數據庫出現髒數據。
  (2)再比如,你拿到這個消息做redis的set的操作,那就容易了,不用解決,因爲你無論set幾次結果都是一樣的,set操作本來就算冪等操作。
  (3)如果上面兩種情況還不行,上大招。準備一個第三方介質,來做消費記錄。以redis爲例,給消息分配一個全局id,只要消費過該消息,將<id,message>以K-V形式寫入redis。那消費者開始消費前,先去redis中查詢有沒消費記錄即可。

注:消費者消費消息的時候在某些場景下要放過消費不了的消息,遇到消費不了的消息通過日誌記錄一下或者搞個什麼措施以後再來處理,但是一定要放過消息,因爲在某些場景下例如spring-rabbitmq的默認回饋策略是出現異常就沒有提交ack,導致了一直在重發那條消費異常的消息,而且一直還消費不了。

 

5、如何保證消息的可靠性傳輸

可靠性傳輸,每種MQ都要從三個角度來分析:生產者弄丟數據、消息隊列弄丟數據、消費者弄丟數據。

(1)生產者丟數據
從生產者弄丟數據這個角度來看,RabbitMQ提供transaction和confirm模式來確保生產者不丟消息。

transaction機制就是說,發送消息前,開啓事物(channel.txSelect()),然後發送消息,如果發送過程中出現什麼異常,事物就會回滾(channel.txRollback()),如果發送成功則提交事物(channel.txCommit())。

transaction模式的缺點就是吞吐量下降了。因此,生產上用confirm模式的居多。一旦channel進入confirm模式,所有在該信道上面發佈的消息都將會被指派一個唯一的ID(從1開始),一旦消息被投遞到所有匹配的隊列之後,rabbitMQ就會發送一個Ack給生產者(包含消息的唯一ID),這就使得生產者知道消息已經正確到達目的隊列了.如果rabiitMQ沒能處理該消息,則會發送一個Nack消息給你,你可以進行重試操作。

事務機制和cnofirm機制最大的不同在於,事務機制是同步的,你提交一個事務之後會阻塞在那兒,但是confirm機制是異步的,你發送個消息之後就可以發送下一個消息,然後那個消息RabbitMQ接收了之後會異步回調你一個接口通知你這個消息接收到了。所以一般在生產者這塊避免數據丟失,都是用confirm機制的。

(2)消息隊列丟數據
處理消息隊列丟數據的情況,一般是開啓持久化磁盤的配置。這個持久化配置可以和confirm機制配合使用,你可以在消息持久化磁盤後,再給生產者發送一個Ack信號。這樣,如果消息持久化磁盤之前,rabbitMQ陣亡了,那麼生產者收不到Ack信號,生產者會自動重發。
持久化分兩步:
1、將queue的持久化標識durable設置爲true,則代表是一個持久的隊列
2、發送消息的時候將deliveryMode=2
這樣設置以後,rabbitMQ就算掛了,重啓後也能恢復數據


(3)消費者丟數據
消費者丟數據一般是因爲採用了自動確認消息模式。這種模式下,消費者會自動確認收到信息。這時rahbitMQ會立即將消息刪除,這種情況下如果消費者出現異常而沒能處理該消息,就會丟失該消息。
至於解決方案,採用手動確認消息即可。

其他文章:

http://www.php.cn/php-weizijiaocheng-230336.html

https://blog.csdn.net/alinshen/article/details/80583214

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章