RabbitMQ技術說明與應用
一、常用訊息代理軟體的基本介紹

二、RabbitMQ的特性與優點
- 免費開源特性
- 多種訊息協定:支援AMQP、MQTT、STOMP、HTTP。
- 輕量級的系統:支援Linux、Windows、macOS等系統。
- 支援開發語言:如Java、Python、JavaScript、.NET Core等。
- 第三方插件支援:可透過如Logstash支援的插件將佇列訊息儲存到資料庫上。
- 可視化GUI介面:提供豐富的UI介面,可於後台進行Exchange、Queue等操作。
- 工具支援:可與市面上主要CI/CD工具配合使用,如GitLab、Docker等。
三、什麼是RabbitMQ?

RabbitMQ是由基礎的訊息架構所延伸的一套系統,如下圖所示為一個基本的訊息傳遞模型,可分為「生產者」、「消費者」及「訊息」,其說明如下:
- 生產者:發送訊息的來源端,主要進行「發送」動作,將訊息發送到「訊息代理端」後進行分派。
- 消費者:接收訊息的終端,主要進行「接收」動作,接著來自「訊息代理端」的分派資訊。
- 訊息:生產者提供訊息並由訂閱的消費者接收,訊息內容可以為標頭、JSON、XML、純文字等。

RabbitMQ是一個訊息代理軟體,它是基於AMQP(Advanced Message Queuing Protocol),可分為「發佈者」、「消費者」、「交換器」及「佇列」,與「基本的訊息傳遞模型」不同的是AMQP提供更多樣組合選擇,其說明如下:
- 交換器:提供「Direct」、「Fanout」、「Topic」、「Headers」四種交換方式,各交換器對訊息的過濾上有不同的作用。
- 佇列:建立需要的訊息佇列,透過交換器進行綁定,則訊息僅能從該交換器傳送訊息。
- 發佈者:提供相對應的訊息規則,將訊息內容發送至綁定的交換器,再由「交換器」分派給對應的消費者。
- 消費者:透過訂閱佇列來接收對應交換器傳送出來的內容。
四、介紹RabbitMQ的幾種交換器和佇列
1. Direct交換類型

- 生產者(Producer)向交換器(Exchange)發送訊息。
- 佇列(Queue)使用路由鍵(Routing Key)與交換器(Exchange)進行綁定。
- 傳送到交換器(Exchange)的訊息會根據路由鍵(Routing Key)將訊息轉送到一個或多個佇列(Queue)。
- 消費者(Consumer)訂閱佇列(Queue)接收訊息。
備註:佇列可以與交換器綁定相同或不同路由鍵(Routing Key)
2. Fanout扇出交換類型

- 生產者(Producer)向交換器(Exchange)發送訊息。
- 一個或多個佇列綁定到沒有路由鍵(Routing Key)的扇出交換器。
- 交換器(Exchange)將訊息無條件轉送到各個佇列。
- 消費者(Consumer)訂閱佇列(Queue)接收訊息。

標頭匹配流程
- 生產者(Producer)將帶有標頭屬性的訊息傳送到對應交換器(Exchange)。
- 一或多個佇列(Queue)使用標頭屬性來綁定交換器(Exchange)
- 如果標頭訊息的條件匹配,則將訊息轉送到佇列(Queue)。
- 消費者(Consumer)訂閱佇列(Queue)接收訊息。
標頭匹配演算法說明
- 標頭格式主要以「Key:Value」方式定義
- 標頭的匹配類型可以為「OR」和「AND」,以本例來說分別設定為「any」和「all」
- 發送的標頭中需要包含匹配條件,再來才是訊息內容
- 以本例來說,假設生產者(Producer)傳入「any」且訊息內容為「h1」,則訂閱佇列(Queue)的消費者(Consumer)會接收到「HealthQ」和「EducationQ」的佇列訊息。
4. Topic交換類型

- Topic Exchange中的路由鍵必須由零個或多個以點分隔的單字組成,例如「health.education」。
- 主題交換中的路由鍵通常稱為路由模式。
- 路由模式只包含「*」、「.」和「#」的正規表達式。
- 星字符號「*」表示只允許一個單字。
- 井字符號「#」表示允許零個或多個單字。
- 點符號「.」表示單字分隔符號,多個關鍵術語由點分隔符號進行分隔。
- 如果路由模式為「health.*」,則表示以路由鍵「health」作為第一個單字發送的任何訊息都會到達佇列。
- 例如「health.education」將到達此佇列,但「sports.health」不會起作用。
五、Erlang安裝步驟
步驟 1 - 下載並安裝Erlang
首先打開 Erlang下載連結 ,在右邊選擇「Download Windows installer」並下載符合系統環境的位元

步驟 2 - 選擇要安裝的元件
確定安裝介面預設已勾選「Erlang」、「Associations」、「Erlang Documentation」後,單擊「Next」繼續。

步驟 3 - 選擇安裝路徑
通常預設路徑即可,接著單擊「Next」繼續。

步驟 4 - 進行安裝並等待安裝完成
單擊「Install」進行安裝,請等待所有程序安裝結束。

六、RabbitMQ安裝步驟
步驟 1 - 下載並安裝RabbitMQ
首先打開 RabbitMQ下載連結 並捲動到底下單擊「Windows Installer」 進行下載。

步驟 2 - 選擇要安裝的元件
確定安裝介面預設已勾選「RabbitMQ Service」、「Start Menu Shortcuts」後,單擊「Next」繼續。

步驟 3 - 進行安裝並等待安裝完成
單擊「Install」進行安裝,請等待所有程序安裝結束。

步驟 4 - 啟動RabbitMQ Service
開啟「RabbitMQ Service-start」。

開啟「RabbitMQ Command Prompt」,輸入「sc query "RabbitMQ"」,以確認服務已啟用。
步驟 5 - 確認RabbitMQ Service是否啟動

步驟 6 - 安裝RabbitMQ管理套件
開啟「RabbitMQ Command Prompt」。

輸入「rabbitmq-plugins.bat enable rabbitmq_management」,接著按下Enter。

步驟 7 - 登入後臺頁面
首先打開瀏覽器輸入RabbitMQ後臺預設網址,接著輸入帳號密碼單擊「Login」按鈕後即可進入後臺網址,登入網址及預設帳號密碼如下所示。


七、實作 .NET Core及RabbitMQ
1. 開發環境說明
- 作業系統:Windows 11
- Server端:Erlang 26.1.2 & RabbitMQ 3.12.8
- Client端:.NET Core Console
- NuGet套件:
- RabbitMQ.Client (6.6.0)
- Microsoft.Extensions.Hosting.WindowsServices (7.0.1)
- Microsoft.Extensions.Hosting.Abstractions (7.0.0)
- Microsoft.AspNetCore.Hosting.WindowsServices (6.0.24)
- NLog (5.2.5)
- NLog.Extensions.Logging (5.3.5)
- NLog.Web.AspNetCore (5.3.5)
2. 實作範例 - 建立消費者佇列接收模型
MessageReceiver.cs
3. 實作範例 - Direct交換類型
- 新增交換器名稱及類型
- 交換器名稱:my-direct-exchange
- 交換器類型:direct

- 新增佇列名稱及類型
- 佇列名稱:ACQ、LightQ、MobileQ
- 佇列類型:classic


.NET Core Code
從實作結果可以發現,發佈者只有將訊息發佈到交換器「my-direct-exchange」上的路由鍵「homeAppliance」,因此在我們訂閱的三個佇列項目,只有ACQ、LightQ兩個佇列接收到訊息。

4. 實作範例 - Fanout扇出交換類型
- 新增交換器名稱及類型
- 交換器名稱:my-fanout-exchange
- 交換器類型:fanout


.NET Core Code
從實作結果可以發現,「Fanout」交換類型的特性是不帶「Routing Key」的方式將訊息發佈給有訂閱的消費者,因此在我們訂閱的三個佇列項目都接收的到訊息。


- 新增交換器名稱及類型
- 交換器名稱:my-headers-exchange
- 交換器類型:headers

- 新增佇列名稱及類型
- 佇列名稱:HealthQ、SportsQ、EducationQ
- 佇列類型:classic

- 交換器綁定佇列
- 綁定佇列:
- HealthQ
- 參數:
- x-match:any
- h1:Header1
- h2:Header2
- SportsQ
- 參數:
- x-match:all
- h1:Header1
- h2:Header2
- EducationQ
- 參數:
- x-match:any
- h1:Header1
- h2:Header2
.NET Core Code
從實作結果可以發現,Headers交換類型是透過「OR」、「AND」條件及定義標頭來篩選發佈的訊息,本例先定義「HealthQ」、「EducationQ」具備「Any」的條件,接著再定義「SportsQ」具備「All」的條件,最後再定義其他標頭來模擬篩選情況。
第一個發佈者先發送「h1:Header1」、「h3:Header3」訊息,只有「HealthQ」及「EducationQ」先符合條件,故成功接收到第一批訊息。
第二個發佈者接著發送「h2:Header2」訊息,此時「HealthQ」、「SportsQ」、「EducationQ」因為也符合條件,故成功接收到第二批訊息,其中「SportsQ」為「All」條件,只有當具備兩種標頭才能夠接收成功。

6. 實作範例 - Topic交換類型

-
新增交換器名稱及類型
- 交換器名稱:my-topic-exchange
- 交換器類型:topic
-
新增佇列名稱及類型
- 佇列名稱:HealthQ、SportsQ、EducationQ
- 佇列類型:classic

- 交換器綁定佇列
- 綁定佇列:
- HealthQ
- SportsQ
- EducationQ
.NET Core Code
從實作結果可以發現,Topic交換類型是透過「正規表達式」來進行匹配,首先我們分別發送「health.education」、「education」、「education.health」三則訊息,由於三個佇列「HealthQ」、「SportsQ」、「EducationQ」分別綁定「health.」、「#.sports.」、「#.education」,因此符合條件的有「HealthQ」及「EducationQ」兩種佇列,以下將對其分別解析原理:
- HealthQ [health.*]:米字號代表一個單詞,因此只有「health.education」符合條件。
- SportsQ [#.sports.*]:井字號代表零個或多個單字,米字號代表一個單詞,因此沒有任何一條訊息符合條件。
- EducationQ [#.education]:井字號代表零個或多個單字,因此「health.education」及「education」都符合條件。

八、案例實作
在現實生活中有許多智慧物聯網的應用,舉例來說像車牌辨識、車輛偵測、人臉辨識、火焰煙霧偵測等就是現今常見的AI應用,而這些AI模組得到的資訊通常都是需要即時且大量的傳輸到Server上,通常作法會是使用如TCP/IP方式來進行封包傳輸,但此一技術的缺點僅限於數據量還不夠多的時候,若傳輸的封包過於繁雜可能會造成黏包、丟包等問題,而這時候可以搭配RabbitMQ的佇列特性來達到此目的,我們將以上述情境透過「.NET Core」及「RabbitMQ」來進行實作。

本例將分別實作「MQ Server」及「MQ Services」,前者主要模擬伺服端持續接收訊息的消費者(Consumer),而後者則模擬AI模組持續發送訊息的發佈者(Producer),以下將分別進行程式撰寫:
1. 實作MQ Server
步驟 1 - 新增佇列

步驟 2 - 新增交換器及綁定佇列

步驟 3 - 程式撰寫
ConsumerModel.cs - 消費者模組
Program.cs - 主系統執行
2. 實作MQ Services
定義範例模型 - 程式撰寫
IMQSpecs.cs - MQTT規格介面
BoxContainer.cs - 偵測矩形容器
MockDataModel.cs - 虛擬資料模型
FaceRecognitionData.cs - 人臉辨識模組
FireSmokeRecognitionData.cs - 火焰煙霧偵測模組
LicensePlateRecognitionData.cs - 車牌辨識模組
VehiclesRecognitionData.cs - 車輛偵測模組
撰寫Windows服務程式 - 程式撰寫
IMQTTService.cs - MQ服務介面
MQTTService.cs - MQ服務邏輯
Worker.cs - 服務核心
Program.cs - 主系統執行
3. 實作結果
.NET Core 範例程式下載
下載連結 1:MQServices
下載連結 2:MQClient
當訂閱「人臉辨識佇列」之後,可以取得「人臉辨識模組」所發佈的訊息

當訂閱「車牌辨識佇列」之後,可以分別取得「車輛偵測模組」及「車牌辨識模組」所發佈的訊息

RabbitMQ技術說明與應用
一、常用訊息代理軟體的基本介紹
二、RabbitMQ的特性與優點
三、什麼是RabbitMQ?
四、介紹RabbitMQ的幾種交換器和佇列
1. Direct交換類型
備註:佇列可以與交換器綁定相同或不同路由鍵(Routing Key)
2. Fanout扇出交換類型
3. Headers交換類型
標頭匹配流程
標頭匹配演算法說明
4. Topic交換類型
五、Erlang安裝步驟
步驟 1 - 下載並安裝Erlang
步驟 2 - 選擇要安裝的元件
步驟 3 - 選擇安裝路徑
步驟 4 - 進行安裝並等待安裝完成
六、RabbitMQ安裝步驟
步驟 1 - 下載並安裝RabbitMQ
步驟 2 - 選擇要安裝的元件
步驟 3 - 進行安裝並等待安裝完成
步驟 4 - 啟動RabbitMQ Service
步驟 5 - 確認RabbitMQ Service是否啟動
步驟 6 - 安裝RabbitMQ管理套件
步驟 7 - 登入後臺頁面
Server: http://localhost:15672/
Username: guest
Password: guest
七、實作 .NET Core及RabbitMQ
1. 開發環境說明
2. 實作範例 - 建立消費者佇列接收模型
MessageReceiver.cs
3. 實作範例 - Direct交換類型
.NET Core Code
4. 實作範例 - Fanout扇出交換類型
.NET Core Code
5. 實作範例 - Headers交換類型
.NET Core Code
6. 實作範例 - Topic交換類型
新增交換器名稱及類型
新增佇列名稱及類型
.NET Core Code
八、案例實作
1. 實作MQ Server
步驟 1 - 新增佇列
步驟 2 - 新增交換器及綁定佇列
步驟 3 - 程式撰寫
ConsumerModel.cs - 消費者模組
Program.cs - 主系統執行
2. 實作MQ Services
定義範例模型 - 程式撰寫
IMQSpecs.cs - MQTT規格介面
BoxContainer.cs - 偵測矩形容器
MockDataModel.cs - 虛擬資料模型
FaceRecognitionData.cs - 人臉辨識模組
FireSmokeRecognitionData.cs - 火焰煙霧偵測模組
LicensePlateRecognitionData.cs - 車牌辨識模組
VehiclesRecognitionData.cs - 車輛偵測模組
撰寫Windows服務程式 - 程式撰寫
IMQTTService.cs - MQ服務介面
MQTTService.cs - MQ服務邏輯
Worker.cs - 服務核心
Program.cs - 主系統執行
3. 實作結果
.NET Core 範例程式下載
下載連結 1:MQServices
下載連結 2:MQClient