入門RabbitMQ訊息佇列,看這篇文章就夠了

張君鴻發表於2020-04-03

前言

關於訊息佇列,筆者依稀記得多年前剛畢業實習的時候,由於業務上的需要,有過一段時間的研究,那時候研究的目的是要引入一個更好的訊息佇列中介軟體來解決公司門店資料與總部機房資料通訊的問題,只可惜那時候筆者經驗尚淺,並沒有對訊息佇列有更深入的理解。

不過出於開發的需要,最近又開始訊息佇列的學習,並將學習筆記整理成這篇文章,以備查驗。

什麼是佇列

佇列(Queue)是一種常見的資料結構,其最大的特性就是先進先出(Firist In First Out),作為最基礎的資料結構,佇列應用很廣泛,比如我們熟知的Redis基礎資料型別List,其底層資料結構就是佇列。

什麼是訊息佇列

訊息佇列(Messaeg Queue)是一種使用佇列(Queue)作為底層儲存資料結構,可用於解決不同程式與應用之間通訊的分散式訊息容器,也稱為訊息中介軟體。

目前使用得比較多的訊息佇列有ActiveMQRabbitMQKafkaRocketMQ等。

什麼是RabbitMQ

RabbitMQ是用Erlang語言開發的一個實現了AMQP協議的訊息佇列伺服器,相比其他同型別的訊息佇列,最大的特點在保證可觀的單機吞吐量的同時,延時方面非常出色。

RabbitMQ支援多種客戶端,比如:PythonRuby.NETJavaJMSCPHPActionScriptXMPPSTOMP等。

AMQP,即Advanced Message Queuing Protocol,高階訊息佇列協議,是應用層協議的一個開放標準,為面向訊息的中介軟體設計。

訊息佇列的應用場景

訊息佇列使用廣泛,其應用場景有很多,下面我們列舉比較常見的五個場景。

訊息通訊

訊息佇列最主要功能收發訊息,其內部有高效的通訊機制,因此非常適合用於訊息通訊。

我們可以基於訊息佇列開發點對點聊天系統

也可以開發廣播系統,用於將訊息廣播給大量接收者。

非同步處理

一般我們寫的程式都是順序執行(同步執行),比如一個使用者註冊函式,其執行順序如下:

  • 1.寫入使用者註冊資料。
  • 2.傳送註冊郵件。
  • 3.傳送註冊成功的簡訊通知。
  • 4.更新統計資料。

按照上面的執行順序,要全部執行完畢,才能返回成功,但其實在第1步執行成功後,其他的步驟完全可以非同步執行,我們可以將後面的邏輯發給訊息佇列,再由其他程式非同步執行,如下所示:

使用訊息佇列進行非同步處理,可以更快地返回結果,加快伺服器的響應速度,提升了伺服器的效能。

服務解耦

在我們的系統中,應用與應用之間的通訊是很常見的,一般我們應用之間直接呼叫,比如說應用A呼叫應用B的介面,這時候應用之間的關係是強耦合的。

如果應用B處於不可用的狀態,那麼應用A也會受影響。

在應用A與應用B之間引入訊息佇列進行服務解耦,如果應用B掛掉,也不會影響應用A的使用。

流量削峰

對於高併發的系統來說,在訪問高峰時,突發的流量就像洪水般嚮應用系統湧過來,尤其是一些高併發寫操作,隨時會導致資料庫伺服器癱瘓,無法繼續提供服務。

而引入訊息佇列則可以減少突發流量對應用系統的衝擊。訊息佇列就像“水庫”一樣,攔蓄上游的洪水,削減進入下游河道的洪峰流量,從而達到減免洪水災害的目的。

這方面最常見的例子就是秒殺系統,一般秒殺活動瞬間流量很高,如果流量全部湧向秒殺系統,會壓垮秒殺系統,通過引入訊息佇列,可以有效緩衝突發流量,達到“削峰填谷”的作用。

RabbitMQ安裝與啟動

RabbitMQ支援LinuxWindowsUnixMacOS等多種作業系統,我們可以根據自己的作業系統來安裝對應的版本,下面我們只講解如何在Cnetos7上安裝,和使用Docker進行安裝。

更多安裝詳細資訊,可檢視官網

在Cnetos7上的安裝

下面演示ErlangRabbitMQ的安裝,我們使用rpm的一鍵安裝包,這種方式比較方便,比較適合初學者。

基礎依賴安裝

如果你的作業系統是Linux的最小安裝包,那麼應該有很多基礎的依賴包沒有安裝,在安裝RabbitMQ之前,需要安裝好這些基礎依賴包,可以執行如下命令:

$ sudo yum install openssql openssl-devel make gcc gcc-c++ kernel-devel
複製程式碼
安裝Socat

RabbitMQ依賴於Socat,因此在安裝RabbitMQ前要安裝Socat,如下:

$ sudo yum install -y socat
複製程式碼
安裝Erlang

因為RabbitMQ是用Erlang語言開發,所以在安裝RabbitMQ前,要先安裝Erlang執行環境,我們使用Erlang語言的rpm安裝包。

# 下載
$ wget https://github.com/rabbitmq/erlang-rpm/releases/download/v22.3/erlang-22.3-1.el7.x86_64.rpm

安裝

複製程式碼

$ rpm -ivh erlang-22.3-1.el7.x86_64.rpm 複製程式碼

安裝RabbitMQ

上面所說的依賴安裝完成後,最後我們可以執行下面的命令安裝RabbitMQ:

# 下載
$ wget https://github.com/rabbitmq/rabbitmq-server/releases/download/v3.8.3/rabbitmq-server-3.8.3-1.el7.noarch.rpm

安裝

複製程式碼

$ rpm -ivh rabbitmq-server-3.8.3-1.el7.noarch.rpm 複製程式碼

啟動與關閉

安裝完成之後,可以使用rabbitmq-server命令啟動伺服器,如下:

# 直接啟動
$ sudo rabbitmq-server

-detached為可選引數,表示後臺開啟

複製程式碼

$ sudo rabbitmq-server -detached 複製程式碼

啟動成功,輸出如下:

如果要關閉,則可以使用下面的命令:

#關閉RabbitMQ服務:  
$ sudo rabbitmqctl stop  
複製程式碼

外掛管理

上面我們使用rabbitmq-server啟動伺服器,也可以使用rabbitmqctl命令管理伺服器,包括建立交換機、佇列、使用者管理等操作,除了命令管理工具,RabbitMQ還提供了Web管理工具,而Web管理工具作為RabbitMQ的外掛,如果要開啟,可以使用下面的命令 :

rabbitmq-plugins是RabbitMQ管理外掛的命令。

$ sudo rabbitmq-plugins enable rabbitmq_management 
複製程式碼

啟動外掛後,我們再啟動伺服器,最後一行顯示執行了3個外掛,如下:

重新啟動伺服器後,可以開啟瀏覽器訪問RabbitMQ的Web管理介面

Web管理程式的埠號是15672,在瀏覽器中輸入http://localhost:15672,即可以訪問。

Docker上的安裝

上面演示的是直接在作業系統上安裝RabbitMQ的過程,如果你本地有安裝Docker執行環境,那麼可以下載RabbitMQDocker映象進行安裝,這種方式很方便,也不需要自己安裝RabbitMQ依賴。

可以Docker Hub上查詢我們需要的RabbitMQ映象包,如下:

我們選擇以tag帶management字尾的映象, 這表示該版本帶有Web管理介面。

# 拉取映象包
docker pull rabbitmq:3.8.3-management

啟動映象

複製程式碼

docker run -d --name rabbitmq -p 5672:5672 -p 15672:15672 -v pwd複製程式碼/data:/var/lib/rabbitmq --hostname myRabbit -e RABBITMQ_DEFAULT_VHOST=my_vhost -e RABBITMQ_DEFAULT_USER=admin -e RABBITMQ_DEFAULT_PASS=admin rabbitmq3.8.3-management 複製程式碼

核心概念

RabbitMQ有屬於自己的一套核心概念,對這些概念的理解很重要,只有理解了這些核心概念,才有可能建立對RabbitMQ的全面理解。

Broker

Broker概念比較簡單,我們可以把Broker理解為一個RabitMQ Server

Producer與Consumer

生產者與消費者相對於RabbitMQ伺服器來說,都是RabbitMQ伺服器的客戶端。

  • 生產者(Producer):連到RabbitMQ伺服器,將訊息傳送到RabbitMQ伺服器的佇列,是訊息的傳送方。
  • 消費者(Consumer):連線到RabbitMQ則是為了消費佇列中的訊息,是訊息的接收方。

生產者與消費者一般由我們的應用程式充當。

Connection

ConnectionRabbitMQ內部物件之一,用於管理每個到RabbitMQTCP網路連線。

Channel

Channel是我們與RabbitMQ打交道的最重要的一個介面,我們大部分的業務操作是在Channel這個介面中完成的,包括定義Queue、定義Exchange、繫結QueueExchange、釋出訊息等

Exchnage

訊息交換機,作用是接收來自生產者的訊息,並根據路由鍵轉發訊息到所繫結的佇列。

生產者傳送上的訊息,就是先通過Exchnage按照繫結(binding)規則轉發到佇列的。

交換機型別(Exchange Type)有四種:fanoutdirecttopicheaders,其中headers並不常用。

  • fanout:這種型別不處理路由鍵(RoutingKey),很像子網廣播,每臺子網內的主機都獲得了一份複製的訊息,釋出/訂閱模式就是指使用fanout交換機型別,fanout型別交換機轉發訊息是最快的。

  • direct:模式處理路由鍵,需要路由鍵完全匹配的佇列才能收到訊息,路由模式使用的是direct型別的交換機。

  • topic:將路由鍵和某模式進行匹配。主題模式使用的是topic型別的交換機。

路由模式,釋出訂閱模式,主題模式,這些工作模式我們下面會講。

Queue

Queue,即佇列,RabbitMQ內部用於儲存訊息的物件,是真正用儲存訊息的結構,在生產端,生產者的訊息最終傳送到指定佇列,而消費者也是通過訂閱某個佇列,達到獲取訊息的目的。

Binding

Binding是一種操作,其作用是建立訊息從Exchange轉發到Queue的規則,在進行ExchangeQueue的繫結時,需要指定一個BindingKey,Binding操作一般用於RabbitMQ的路由工作模式和主題工作模式。

BindingKey的概念,我們下面在講RabbitMQ的工作模式會詳細講解。

Virtual Host

Virutal host也叫虛擬主機,一個VirtualHost下面有一組不同ExchnageQueue,不同的Virtual hostExchnageQueue之間互相不影響。

應用隔離與許可權劃分,Virtual host是RabbitMQ中最小顆粒的許可權單位劃分。

如果要類比的話,我們可以把Virtual host比作MySQL中的資料庫,通常我們在使用MySQL時,會為不同的專案指定不同的資料庫,同樣的,在使用RabbitMQ時,我們可以為不同的應用程式指定不同的Virtual host

上面我們一一列舉了RabbitMQ的核心概念,通過下面的示意圖,我們可以更清晰地瞭解它們之間的關係。

工作模式

RabbitMQ一共有六種工作模式,分別為簡單模式、工作佇列模式、釋出/訂閱模式、路由模式、主題模式和RPC模式,RPC模式並不常用,因此我們下面只講前面五種工作模式。

簡單(simple)模式

simple模式,是RabbitMQ幾種模式中最簡單的一種模式,其結構如下圖所示:

從上面的示意圖,我們可以看出simple模式有以下幾個特徵:

  • 只有一個生產者、一個消費者和一個佇列。
  • 生產者和消費者在傳送和接收訊息時,只需要指定佇列名,而不需要指定傳送到哪個ExchangeRabbitMQ伺服器會自動使用Virtual host的預設的Exchange,預設Exchangetypedirect

工作(work)模式

simple模式下只有一個生產者和消費者,當生產者生產訊息的速度大於消費者的消費速度時,我們可以新增一個或多個消費者來加快消費速度,這種在simple模式下增加消費者的模式,稱為work模式,如下圖所示:

work模式有以下兩個特徵:

  • 可以有多個消費者,但一條訊息只能被一個消費者獲取。
  • 傳送到佇列中的訊息,由伺服器平均分配給不同消費者進行消費。

釋出/訂閱(pub/sub)模式

work模式可以將訊息轉到多個消費者,但每條訊息只能由一個消費者獲取,如果我們想一條訊息可以同時給多個消費者消費呢?

這時候就需要釋出/訂閱模式,其示意圖如下所示:

從上面的示意圖我們可以看出來,在釋出/訂閱模式下,需要指定傳送到哪個Exchange中,上面圖中的X表示Exchange

  • 釋出/訂閱模式中,Echangetypefanout
  • 生產者傳送訊息時,不需要指定具體的佇列名,Exchange會將收到的訊息轉發到所繫結的佇列。
  • 訊息被Exchange轉到多個佇列,一條訊息可以被多個消費者獲取。

路由(routing)模式

前面幾種模式,訊息的目標佇列無法由生產者指定,而在路由模式下,訊息的目標佇列,可以由生產者指定,其示意圖如下所示:

從上面示意圖,我們可以看出路由模式有以下特徵:

  • 路由模式下Exchange的type為direct
  • 訊息的目標佇列可以由生產者按照routingKey規則指定。
  • 消費者通過BindingKey繫結自己所關心的佇列。
  • 一條訊息隊可以被多個訊息者獲取。
  • 只有RoutingKeyBidingKey相匹配的佇列才會收到訊息。

RoutingKey用於生產者指定Exchange最終將訊息路由到哪個佇列,BindingKey用於消費者繫結到某個佇列。

主題(topic)模式

主題模式是在路由模式的基礎上,將路由鍵和某模式進行匹配。其中#表示匹配多個詞,*表示匹配一個詞,消費者可以通過某種模式的BindKey來達到訂閱某個主題訊息的目的,如示意圖如下所示:

  • 主題模式Exchange的type取值為topic。
  • 一條訊息可以被多個消費者獲取。

幾種常見訊息佇列的對比

除了RabbitMQ之外,還有其他比較常見的訊息佇列中介軟體,如KafkaRocketMQActiveMQ等,下面的表格中列舉了這幾種訊息佇列的差異:

訊息佇列 RabbitMQ ActiveMQ RocketMQ Kafka
所屬公司/社群 Mozilla Public License Apache Ali Apache
成熟度 成熟 成熟 比較成熟 成熟
授權方式 開源 開源 開源 開源
開發語言 Erlang Java Java Scala & Java
客戶端支援語言 官方支援Erlang,java,Ruby等,社群產出多種語言API,幾乎支援所有常用語言 JAVA,C++,pyhton,php,perl,net等 java,c++ 官方支援java,開源社群有多種語言版本,如PHP,python,go,c/c++,ruby,node.js等語言
協議支援 多協議支援AMQP,XMPP,SMTP,STOMP OpenWire,STOMP,REST,XMPP/AMOP 自定義的一套 自定義協議
訊息批量操作 不支援 支援 支援 支援
訊息推拉模式 多協議,pull/push均有支援 多協議pull/push均有支援 多協議,pull/push均有支援 pull
HA master/slave模式 基於zookeeper+LevelDB的master-slave 支援多master模式,多master多slave模式,非同步複製模式 支援replica機制,leader宕掉後,備份自動頂替,並重新選擇leader
資料可靠性 可以保證資料不丟,有slave備份 master/slave 支援非同步實時刷盤,同步刷盤,同步複製,民步複製 資料可靠,並且有replica機制,有容錯容災能力
單機吞吐量 其次(萬級) 最差(萬級) 最高(十萬級) 次之(十萬級)
訊息延遲 微秒級 \ 比Kafka快 毫秒級
持久化能力 記憶體、檔案、支援資料堆積,但資料堆積反過來影響生產速率 記憶體、檔案、資料庫 碰盤檔案 磁碟檔案 磁碟檔案,只要磁碟容量夠,可以做到無限訊息堆積
是否有序 若想有序,只能使用一個client 可以支援有序 有序 多client保證有序
事務 支援 支援 支援 不支援
叢集 支援 支援 支援 支援
負載均衡 支援 支援 支援 支援
管理介面 較好 一般 命令列介面 官方只提供了命令列版
部署方式 獨立 獨立 獨立 獨立

小結

本文講解了佇列與RabbitMQ的概念、如何安裝RabbitMQRabbitMQ的核心概念以及幾種工作模式,由於涉及到RabbitMQ的大部分知識點,因此鑑於筆者水平有限,文章中講解不對或不足的地方,歡迎指出,不勝感激!


如果你覺得文章不錯,歡迎掃碼關注,你的關注就是我寫作的最大動力

相關文章