RabbitMQ 筆記
===
###### tags: `技術備忘錄` `RabbitMQ`
參照[RabbitMQ實戰指南](https://www.tenlong.com.tw/products/9787121329913) , [官方API](https://www.rabbitmq.com/dotnet-api-guide.html)
安裝篇->[RabbitMQ 快速安裝筆記](/DZaDoKJ8REit9tTgE_3v2Q)
進階篇->[RabbitMQ 叢集搭建](/NWL3qD7IRhS2wAyx_XUvZQ)
---
[TOC]
---
底下開始為RabbitMQ預設走AMQP的情況
MQTT請往最下
## 大概的層級概念
**Virtual Hosts可以複數的User跟Queue**
> User跟Queue都是建立在Virtual Hosts底下
#### 發送
```graphviz
digraph hierarchy {
User -> {Virtual_Hosts}
Virtual_Hosts -> {Exchange User}
Exchange -> {Routing_Key Queue}
Routing_Key -> {Queue Exchange}
}
```
#### 接收
```graphviz
digraph hierarchy {
User -> {Virtual_Hosts}
Virtual_Hosts -> {Queue User}
}
```
## 交換器 Exchange
每當一個Virtual Hosts建立就會產生一組預設的Exchange
> 預設產生的Exchange們
> ![](https://i.imgur.com/Y8Iwz8S.png)
### 路由鍵
1. Bindings (BindingKey)
* 對應建立在Exchange下,實際上就是Server端Exchange下的RoutingKey
3. RoutingKey
* 為Client端帶的RoutingKey
* 對應BindingKey
* 以" . "分割字串
> ![](https://i.imgur.com/iiKFm3a.png)
完成效果類似這樣
在"amq.direct"(Exchange)下,
建立Bindings將Key指為"OAO.key",
並將資料倒給"OAO"(Queue) --> (可以給Queue or Exchange)
> To Exchange的樣式![](https://i.imgur.com/9EYVklB.png)
### 交換器類型(Exchange type)
1. fanout
* 將資料倒給所有綁定在此Exchange的Queue
* 如果沒有綁定Queue會自動丟棄進來的資料
2. direct
* 依照Routing Key將資料倒給對應的Queue
* 如果沒有對應的Routing Key會自動丟棄進來的資料
3. topic
* 同direct,差別: topic支援 # 或 * 的模糊搜尋
* # : 多字串
* * : 單一字串
> 模糊搜尋,必須設定在BindingKey上(Server端)
> 類似這樣↓
> ![](https://i.imgur.com/zXzzMpJ.png)
4. headers
* 根據資料的header做導向
* 不實用,~~不要理他~~
### 預設情況
在沒有指定的Exchange的情形下所有的資料都會進入預設的Exchange
> 如圖,為預設的Exchange
> ![](https://i.imgur.com/malAUjt.png)
可以從圖看到這個Exchange的type為direct
也就是說進來的資料必須要有Routing Key做對應
而預設Exchange的Routing Key就是直接對應Queue Name
> Exchange default : Routing Key <--> Queue Name
## Queue
**進入Queue的資料在有人收走以前是不會消失的**
### 設定參數
建立新Queue可以設定的參數的定義
#### Durability
* Durable : 系統關機後會保存
* Transient : 系統關機後Queue會消失
#### Auto delete
* No : Queue不會自我刪除
* Yes : Queue在最後一個連線到自己的連線斷了之後會自我刪除
> 備註: 當Queue建立時,假設Auto delete設為Yes,那在第一個人與這隻Queue建立連線之前,Queue的Auto delete機制都不會觸發
>
>另有名為 Quorum Queues 的特別 Queue,參照[RabbitMQ 叢集搭建 - Quorum Queues](/NWL3qD7IRhS2wAyx_XUvZQ#Quorum-Queues)
## 實作
### 相關套件
RabbitMQ.Client
![](https://i.imgur.com/1W9tB7w.png)
> 題外話,網路上有人說這套比官方的那套好用
> ![](https://i.imgur.com/z9pUy9B.png)
> 可是我拉這套怎樣都連不進Server,莫名其妙
### 共通部分
建立連線的基本資料,發送跟接收都會用到
```C#
public class RabbitMqFactory
{
public static ConnectionFactory Create()
{
return new ConnectionFactory()
{
HostName = "192.168.11.142",
UserName = "dpc",
Password = "123",
VirtualHost = "DPC"
};
}
}
```
### 接收
```C#
var factory = RabbitMqFactory.Create();
using (var connection = factory.CreateConnection())
{
using (var channel = connection.CreateModel())
{
var consumer = new EventingBasicConsumer(channel);
consumer.Received += (model, ea) =>
{
var body = ea.Body;
var message = Encoding.UTF8.GetString(body);
Console.WriteLine(" [x] Received {0}", message);
};
//底下代表同時監聽OAO,OAO2,OAO3
channel.BasicConsume(queue: "OAO",
autoAck: true,
consumer: consumer);
channel.BasicConsume(queue: "OAO2",
autoAck: true,
consumer: consumer);
channel.BasicConsume(queue: "OAO3",
autoAck: true,
consumer: consumer);
Console.WriteLine(" Press [enter] to exit.");
Console.ReadLine();
}
}
```
### 發送
```C#
var factory = RabbitMqFactory.Create();
using (var connection = factory.CreateConnection())
{
using (var channel = connection.CreateModel())
{
string message = "Hello World!";
var body = Encoding.UTF8.GetBytes(message);
channel.BasicPublish(exchange: "",
routingKey: "OAO",
basicProperties: null,
body: body);
Console.WriteLine(" [x] Sent {0}", message);
}
}
```
### 建立Exchange
```C#
channel.ExchangeDeclare("testOAO",ExchangeType.Direct);
```
### 建立Queue
```C#
channel.QueueDeclare(queue: "OAO",
durable: false,
exclusive: false,
autoDelete: false,
arguments: null);
```
### 查詢卡在Queue上的資料
```C#
BasicGetResult result = channel.BasicGet("QueueName", false);
uint count = result != null ? result.MessageCount : 0;
```
> https://stackoverflow.com/questions/1038318/check-rabbitmq-queue-size-from-client
---
## For MQTT
RabbitMQ 預設是沒有MQTT的情況
要走MQTT要開[對應的功能](https://www.rabbitmq.com/mqtt.html)
### 連線狀況
在用MQTT協定連RabbitMQ時
Client的連線設定會長的不一樣
MQTT Client可以帶的值有
* User Name
* Password
* Topic (?)
MQTT協定下預設走 "/" 的 Virtual Hosts
> 因為預設走 "/"
> 所以如果 User 沒有辦法操作 "/" 的 VH
> **連線會直接不過**
>
每個進來的連線會自動開對應那個連線的Queue
![](https://i.imgur.com/BLRqoSx.png)
並且所有資料都走預設的Exchange ==> "amq.topic"
上面說 Client 帶的 Topic 會直接變成 RabbitMQ 的 Routing key
![](https://i.imgur.com/gXewW3W.png)
*然後上面的C#接收方式只能直接對接Queue
所以在接收端的實作上可能會需要依照Routing key
在接受後再做一次判斷 (??)*
其他就都一樣 ((不確定,有狀況再補