專題03——RabbitMQ
1. RabbitMQ安裝
服務端
使用如下sh指令碼安裝:
#!/bin/sh
sudo apt-get install curl gnupg apt-transport-https -y
## Team RabbitMQ's main signing key
curl -1sLf "https://keys.openpgp.org/vks/v1/by-fingerprint/0A9AF2115F4687BD29803A206B73A36E6026DFCA" | sudo gpg --dearmor | sudo tee /usr/share/keyrings/com.rabbitmq.team.gpg > /dev/null
## Community mirror of Cloudsmith: modern Erlang repository
curl -1sLf https://ppa1.novemberain.com/gpg.E495BB49CC4BBE5B.key | sudo gpg --dearmor | sudo tee /usr/share/keyrings/rabbitmq.E495BB49CC4BBE5B.gpg > /dev/null
## Community mirror of Cloudsmith: RabbitMQ repository
curl -1sLf https://ppa1.novemberain.com/gpg.9F4587F226208342.key | sudo gpg --dearmor | sudo tee /usr/share/keyrings/rabbitmq.9F4587F226208342.gpg > /dev/null
## Add apt repositories maintained by Team RabbitMQ
sudo tee /etc/apt/sources.list.d/rabbitmq.list <<EOF
## Provides modern Erlang/OTP releases
##
deb [signed-by=/usr/share/keyrings/rabbitmq.E495BB49CC4BBE5B.gpg] https://ppa1.novemberain.com/rabbitmq/rabbitmq-erlang/deb/ubuntu jammy main
deb-src [signed-by=/usr/share/keyrings/rabbitmq.E495BB49CC4BBE5B.gpg] https://ppa1.novemberain.com/rabbitmq/rabbitmq-erlang/deb/ubuntu jammy main
## Provides RabbitMQ
##
deb [signed-by=/usr/share/keyrings/rabbitmq.9F4587F226208342.gpg] https://ppa1.novemberain.com/rabbitmq/rabbitmq-server/deb/ubuntu jammy main
deb-src [signed-by=/usr/share/keyrings/rabbitmq.9F4587F226208342.gpg] https://ppa1.novemberain.com/rabbitmq/rabbitmq-server/deb/ubuntu jammy main
EOF
## Update package indices
sudo apt-get update -y
## Install Erlang packages
sudo apt-get install -y erlang-base \
erlang-asn1 erlang-crypto erlang-eldap erlang-ftp erlang-inets \
erlang-mnesia erlang-os-mon erlang-parsetools erlang-public-key \
erlang-runtime-tools erlang-snmp erlang-ssl \
erlang-syntax-tools erlang-tftp erlang-tools erlang-xmerl
## Install rabbitmq-server and its dependencies
sudo apt-get install rabbitmq-server -y --fix-missing
配置檔案在/etc/rabbitmq
中,透過rabbitmq-env.conf
配置環境,rabbitmq-env.conf
如下:
export RABBITMQ_NODENAME=rabbit@localhost
export RABBITMQ_NODE_IP_ADDRESS=127.0.0.1
export ERL_EPMD_ADDRESS=127.0.0.1
客戶端
使用NuGet安裝RabbitMQ.Client
2. 接收者
using System.Text;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
// 工廠方法,用於配置連線
var factory = new ConnectionFactory
{
// RabbitMQ的服務端地址
HostName = SharedConfig.Configuration.HostName,
// 非同步消費
DispatchConsumersAsync = true
};
// 建立連線
using var connection = factory.CreateConnection();
// 建立通道
var channel = connection.CreateModel();
// 注:XxxDeclare的意思是:沒有就建立,有就複用(由於不知道是Sender還是Receiver先啟動,所以都要宣告)
// 宣告交換機
channel.ExchangeDeclare(exchange: SharedConfig.Configuration.ExchangeName,
type: SharedConfig.Configuration.ExchangeType);
// 宣告佇列
channel.QueueDeclare(queue: SharedConfig.Configuration.QueueName, durable: true, exclusive: false, autoDelete: false,
arguments: null);
// 將佇列與交換機繫結
channel.QueueBind(queue: SharedConfig.Configuration.QueueName, exchange: SharedConfig.Configuration.ExchangeName,
routingKey: SharedConfig.Configuration.EventName);
// 從佇列中獲取訊息(拉取模式)
var asyncEventingBasicConsumer = new AsyncEventingBasicConsumer(channel);
// 訂閱Received事件
asyncEventingBasicConsumer.Received += OnMessageReceived;
// 確認佇列中正在消費的事件狀態(Ack或Reject)
channel.BasicConsume(queue: SharedConfig.Configuration.QueueName, autoAck: false, consumer: asyncEventingBasicConsumer);
Console.ReadLine();
async Task OnMessageReceived(object sender, BasicDeliverEventArgs args)
{
try
{
var bytes = args.Body.ToArray();
var message = Encoding.UTF8.GetString(bytes);
Console.WriteLine($"{DateTime.Now}: 收到了訊息-{message}");
channel.BasicAck(args.DeliveryTag, multiple: false);
await Task.Delay(800);
}
catch (Exception e)
{
channel.BasicReject(args.DeliveryTag, true); // 失敗重發
Console.WriteLine($"處理收到的訊息出錯,{e.Message}");
}
}
3. 傳送者
using System.Globalization;
using System.Text;
using RabbitMQ.Client;
var connectionFactory = new ConnectionFactory
{
HostName = SharedConfig.Configuration.HostName,
DispatchConsumersAsync = true
};
// 和RabbitMQ建立TCP連線
using var connection = connectionFactory.CreateConnection();
// 每間隔3s將當前時間傳送到佇列當中去,共傳送30次
for (int i = 0; i < 30; i++)
{
// 等待傳送的訊息
string message = DateTime.Now.ToString(CultureInfo.InvariantCulture);
// 將訊息重新編碼為RabbitMQ能夠接受的格式(byte[])
var mqMessage = Encoding.UTF8.GetBytes(message);
// 建立通道
using (var channel = connection.CreateModel())
{
var properties = channel.CreateBasicProperties();
// 訊息遞送模式:持久化模式
properties.DeliveryMode = 2;
// 宣告交換機
// 注:XxxDeclare的意思是:沒有就建立,有就複用(由於不知道是Sender還是Receiver先啟動,所以都要宣告)
channel.ExchangeDeclare(exchange: SharedConfig.Configuration.ExchangeName,
type: SharedConfig.Configuration.ExchangeType);
// 釋出訊息
channel.BasicPublish(exchange: SharedConfig.Configuration.ExchangeName,
routingKey: SharedConfig.Configuration.EventName, mandatory: true,
basicProperties: properties, body: mqMessage);
}
Console.WriteLine($"釋出了訊息:{message}");
Thread.Sleep(3000);
}
4. 共用的配置類
namespace SharedConfig;
public struct Configuration
{
// RabbitMQ的地址,這裡用本地地址和預設埠
public const string HostName = "localhost";
// 交換機名稱
public const string ExchangeName = "exchange1";
// 交換機型別
public const string ExchangeType = "direct";
// 當作routingKey使用(路由的依據)
public const string EventName = "event1";
// 佇列名稱
public const string QueueName = "queue1";
}