0


(一)「消息队列」之 RabbitMQ 入门

0、引言

想要实现两个应用程序之间的通信,我们可以借助“消息队列”技术。本文将介绍使用 C# 语言在 .NET 下实现 RabbitMQ 消息队列;当然无论是哪种编程语言,要使用消息队列,都需要完成以下两个基本步骤:

  1. 下载并安装相应的消息队列服务器软件,并根据需要进行配置;
  2. 在您的应用程序代码中引入相应的消息队列客户端库,并使用客户端库提供的API来建立与消息队列服务器的连接并进行通信。

这些步骤对于大多数消息队列中间件都是适用的。不同的消息队列中间件可能有不同的安装和配置方法,以及不同的客户端库和API,您可以根据自身需要阅读相应的官方文档即可。

本文主要参考:

  1. RabbitMQ Tutorials
  2. RabbitMQ使用教程(超详细)
  3. C# 消息队列之 RabbitMQ 基础入门
  4. 消息队列常见的几种使用场景介绍!- 知乎
  5. 分布式之消息队列的特点、选型、及应用场景详解
  6. 消息队列漫谈:什么是消息模型?- 知乎

1、基础概念

消息队列

消息队列
Message
Queue)是一种通信模式,用于在应用程序之间传递消息。它提供了一种异步的、可靠的通信方式,允许发送者(发送消息的应用程序)和接收者(接收消息的应用程序)能够独立地进行工作,而不需要彼此直接交互。

在消息队列中,消息是以队列的形式存储和传递的。发送者将消息放入队列的末尾,而接收者从队列的开头获取消息。这种队列的特性确保了消息的有序处理,并且允许多个发送者和接收者之间进行解耦,从而提高了系统的可伸缩性和可靠性。

在这里插入图片描述
消息队列的使用可以带来许多好处。首先,它允许异步处理,即发送者可以在发送消息后继续执行其他任务,而不需要等待接收者的响应。这种方式可以提高应用程序的性能和吞吐量,特别是在处理大量消息或处理延迟较高的操作时。

其次,消息队列可以解耦发送者和接收者之间的依赖关系。发送者只需将消息发送到队列中,而不需要知道具体的接收者是谁或接收者何时处理消息。这种松耦合的设计允许系统中的不同模块独立开发、部署和扩展,提高了系统的灵活性和可维护性。

此外,消息队列还提供了消息持久化的能力,确保即使在发送者和接收者之间发生故障或中断时,消息不会丢失。消息可以持久化到磁盘上,并在系统恢复后重新发送。这种可靠性保证了消息的传递不会因为故障而中断,使系统更加健壮和可靠。

常见的消息队列软件

  • RabbitMQ

  • Apache Kafka

  • Apache ActiveMQ

  • Amazon SQS

  • Microsoft Azure Service Bus

    中间件

中间件是指位于操作系统和应用程序之间的软件层。它充当了不同软件组件之间的桥梁,提供了通信和协调的功能,以便它们能够相互交互和协作。

中间件的主要目标是简化分布式系统的开发和管理。它提供了一组通用的功能和服务,使得不同的应用程序和系统可以进行互操作,并能够以可靠、安全和高效的方式进行通信。

中间件可以实现各种功能,包括但不限于以下几个方面:

  1. 消息传递:中间件提供消息传递机制,用于在分布式系统中传递和交换数据。消息队列就是一种常见的消息传递中间件。
  2. 远程过程调用(RPC):中间件可以实现远程过程调用,使得应用程序能够在不同的计算机或进程之间调用和执行函数或方法。
  3. 数据库连接和访问:中间件可以提供数据库连接和访问的功能,使得应用程序能够方便地操作和管理数据库。
  4. 分布式事务处理:中间件可以支持分布式系统中的事务处理,确保多个操作在不同的计算机或进程之间具有原子性、一致性、隔离性和持久性。
  5. 缓存管理:中间件可以提供缓存管理的功能,加速数据访问和提高系统性能。
  6. 安全认证和授权:中间件可以实现安全认证和授权机制,保护系统免受未经授权的访问和攻击。

Erlang

Erlang 是一种通用的编程语言,最初由爱立信(Ericsson)的开发团队在1980年代末创建。它是一种函数式编程语言,专门设计用于构建可扩展、并发和分布式的软实时系统。
RabbitMQ 服务是使用 Erlang 语言编写的。

AMQP (
Advanced
Message
Queuing
Protocol)

AMQP
高级消息队列协议:一种面向消息的网络协议(应用层协议),用于在应用程序之间传递消息。
RabbitMQ 是对 AMQP 0.9.1 协议的
实现。并在后续拓展了对
更多协议的支持。

RabbitMQ 介绍

RabbitMQ 是一个消息代理:它接受并转发消息。 你可以把它想象成一个邮局:当你把你想要邮寄的邮件放在邮箱里时, 您可以确定,邮递员最终会将邮件递送给您的收件人。 在这个类比中,RabbitMQ是一个邮政信箱,一个邮局和一个信件载体。

RabbitMQ 和邮局的主要区别在于它不处理纸张。相反,它接受、存储和转发二进制
blob 数据 ——
消息
Message)。

RabbitMQ,以及一般的消息传递,会使用一些术语:

  • 生产 Producing 仅仅只是意味着发送。发送消息的程序被称为 生产者 Producer
  • 在 RabbitMQ 中,邮箱的名字就称为 队列 queue。尽管消息流经 RabbitMQ 和您的应用程序,但它们只能存储在 队列 queue 中。队列 queue 仅受主机内存和磁盘限制的约束,它本质上是一个大型消息缓冲区。许多 生产者 Producer 可以往一个队列发送消息,许多 消费者 Consumer 也可以尝试从一个 队列 queue 接收数据。这就是我们表示队列的方式:
  • 消费 Consuming 与接收意思相近。主要等待接收消息的程序被称为 消费者 Consumer
🔔 请注意:生产者、消费者和代理不必驻留在同一主机上;事实上,在大多数应用程序中,它们不会。此外,一个应用程序可以同时是生产者和消费者。 

2、本文使用的相关软件或产品

  1. Windows 10 专业版 22H2
  2. Visual Studio Community 2022 - 17.6.2
  3. Microsoft .NET Framework 版本 4.8.04084
  4. 「.NET 桌面开发」工作负荷
  5. Erlang 25.3
  6. RabbitMQ Server 3.12.0

3、🔔 须知

大多数消息队列中间件都需要在计算机上安装服务器软件。安装服务器软件后,您需要启动消息队列服务器并根据需要进行配置。然后,您就可以在您的应用程序中使用相应的客户端库来连接到消息队列服务器并使用消息队列了。

4、安装前准备工作 —— 阅读安装向导页面

  1. 首先前往 RabbitMQ 的入门指南页面,点击“Download + Installation”:在这里插入图片描述
  2. 进入到下载和安装 RabbitMQ 页面,可以看到最新的 RabbitMQ 发行版本为 3.12.0。由于笔者使用的 Windows 操作系统,故点击“Windows Installer”进入 Windows 平台的安装程序的安装向导页面:在这里插入图片描述> 您也可以通过 Chocolatey 包安装(本文不演示)或者通过构建二进制包手动安装(通常不推荐)。

4.1、使用安装程序

官方的 RabbitMQ 安装程序是为每个 RabbitMQ 版本生成的。

与通过 Chocolatey 安装相比,此选项为 Windows 用户提供了最大的灵活性,但也要求他们了解安装程序中的某些假设和要求:

  • 一次只能安装一个 Erlang 版本;
  • 必须以管理员身份安装 Erlang;
  • 强烈建议 RabbitMQ 也是通过管理员身份安装;
  • 安装路径只能包含 ASCII 字符,强烈建议安装路径的任何目录名称中都不要包含空格;
  • 可能需要手动复制 CLI 工具使用的共享密钥文件;
  • CLI 工具要求在 UTF-8 模式下运行 Windows 控制台。

如果不满足这些条件,Windows 服务和 CLI 工具可能需要重新安装或其他手动步骤,以使它们按预期运行。

Windows 特定问题指南中对此进行了更详细的介绍。

4.1.1、依赖

RabbitMQ 需要安装 64 位其支持的 Erlang for Windows 版本。

Erlang 25.3 是最新的支持版本。您可以在 Erlang/OTP 版本树页面获取其他版本(比如:早期版本)的 Erlang for Windows 二进制构建包。

Erlang 必须以管理员身份安装,否则 RabbitMQ Windows 服务将无法发现它。安装完成支持的 Erlang 版本后,下载 RabbitMQ 安装程序

rabbitmq-server-{version}.exe

并运行它。安装程序会将 RabbitMQ 作为 Windows 服务进行安装并使用默认配置启动它。

4.1.2、直接下载

描述下载签名Windows 系统的安装程序(来自 Github)rabbitmq-server-3.12.0.exe签名

4.2、运行 RabbitMQ Windows 服务

一旦 Erlang 和 RabbitMQ 都被安装了,RabbitMQ 节点就能作为 Windows 服务启动。RabbitMQ 服务会自动启动。RabbitMQ Windows 服务可以从“开始”菜单进行管理。

4.3、CLI 工具

RabbitMQ 节点通常使用 PowerShell 中的 CLI 工具进行管理、检查和操作。

在 Windows 上,与其他平台相比,CLI 工具具有

.bat

后缀。例如:Windows 上的

rabbitmqctl

被调用为

rabbitmqctl.bat

为了使这些工具正常工作,它们必须能够使用名为 Erlang cookie 的共享密钥文件向 RabbitMQ 节点进行身份验证。

CLI 工具向导主页面涵盖了与命令行工具使用相关的绝大部分话题。

要了解各种 RabbitMQ CLI 工具提供的命令,请使用

help

命令:

# 罗列 rabbitmqctl.bat 提供的命令
rabbitmqctl.bat help# 罗列 rabbitmq-diagnostics.bat 提供的命令
rabbitmq-diagnostics.bat help# 罗列 rabbitmq-plugins.bat 提供的命令
rabbitmq-plugins.bat help

想要学习特定命令,将命令名称作为

help

的参数传递即可:

rabbitmqctl.bat help add_user

4.4、Cookie 文件位置

在 Windows 平台下,cookie 文件位置取决于是否设置了

HOMEDRIVE

HOMEPATH

环境变量。

如果 RabbitMQ 使用非管理员账户安装,则节点和 CLI 工具使用的共享密钥文件将不会被放到正确的位置,这会导致使用

rabbitmqctl.bat

以及其他 CLI 工具时出现身份验证失败错误。

可以使用下列选项之一化解:

  • 使用管理员账户重新安装 RabbitMQ
  • %SystemRoot%%SystemRoot%\system32\config\systemprofile 手动复制 .erlang.cookie 文件到 %HOMEDRIVE%%HOMEPATH%

…(更多内容请自行前往 Windows 平台的安装程序向导页面了解)

5、正式开始安装 RabbitMQ 服务器

5.1、下载安装 Erlang

  1. 在安装 RabbitMQ 之前,首先安装 RabbitMQ 依赖 —— Erlang。前往 Erlang 25.3,点击“Download Windows installer”:在这里插入图片描述
  2. 下载完成后,以管理员身份运行在这里插入图片描述
  3. 运行后进入组件选择页面,一般按默认选择即可,点击下一步:在这里插入图片描述
  4. 选择安装位置页面,可以按默认也可以根据自身喜好修改;确认后点击下一步:在这里插入图片描述
  5. 选择开始菜单文件夹页面,该页面要求您通过点击选中或者手动输入的方式以选择一个开始菜单文件夹用于创建程序的快捷方式,按默认即可。点击“安装”:在这里插入图片描述> 如果按照默认,安装完成后可以在开始菜单找到一个名为“**Erlang OTP 25 (x64)**”的文件夹,该文件夹存放了 Erlang 的快捷方式:> 在这里插入图片描述
  6. 安装完成,点击“关闭”:在这里插入图片描述
  7. 完成后,就可以删除 Erlang 的安装程序了:在这里插入图片描述

5.2、下载安装 RabbitMQ Server

  1. 安装完 Erlang 后,就可以下载安装 RabbitMQ Server 了,笔者安装的 Erlang 版本为 25.3.2,由该页面可知可以安装 RabbitMQ 的最新版本 —— 3.12.0在这里插入图片描述
  2. 下载完成后,以管理员身份运行在这里插入图片描述
  3. 运行后进入组件选择页面,一般按默认选择即可,点击下一步:在这里插入图片描述
  4. 选择安装位置页面,可以按默认也可以根据自身喜好修改;确认后点击“安装”:在这里插入图片描述> 💬 在这个官方页面提到过“强烈建议安装路径的任何目录名称中都不要包含空格”,但是安装程序默认的安装路径都是有空格的,所以我也不太懂他们了,,,还是按照默认的来吧。
  5. 安装完成后,点击下一步:在这里插入图片描述
  6. 完成页面,点击“结束”:在这里插入图片描述> 结束后可以在开始菜单中找到一个名为“RabbitMQ Server”的文件夹,可以从这里管理 RabbitMQ 服务器以及使用 CLI 工具:> 在这里插入图片描述
  7. 完成后,就可以删除 RabbitMQ Server 的安装程序了:在这里插入图片描述

5.3、启用服务管理

我们可以通过一些方法来管理 RabbitMQ 服务器,在官网的端口访问页面介绍了 RabbitMQ 节点绑定到的端口:
在这里插入图片描述
其中我们主要关注 15672 号端口:HTTP API 客户端,管理 UI 和 rabbitmqadmin(仅当启用了管理插件时)。

💬 我们可以通过 HTTP API 使用该管理插件用来管理和监控 RabbitMQ 节点和集群,以及使用基于浏览器的 UI 和命令行工具,rabbitmqadmin。

  1. 在开始菜单中打开 **RabbitMQ 命令提示符 (sbin dir)**:在这里插入图片描述
  2. 使用如下命令以启用 RabbitMQ 管理插件:rabbitmq-plugins enable rabbitmq_management在这里插入图片描述
  3. 这里提示改动会在重启代理后生效,前往计算机管理页找到 RabbitMQ Windows 服务,通过重启该服务以重启代理:在这里插入图片描述
  4. 打开浏览器,输入如下地址以访问:http://127.0.0.1:15672/在这里插入图片描述> 默认用户访问权限:代理会使用密码 > > guest> > 创建一个用户 > > guest> > 。未配置的客户端通常会使用这些凭据。默认情况下,这些凭据只能是在作为本地主机连接到代理时使用,所以你需要在任何其他设备连接到代理之前采取一些行动。> > 有关如何创建更多用户以及删除 > > guest> > 用户的信息,请参阅有关访问控制的文档。> > 综上,这一步我们使用默认账号 > > guest> > 和密码 > > guest> > 登录即可。
  5. 登录成功后如下图所示:在这里插入图片描述

6、在两个应用程序之间使用 RabbitMQ 消息队列中间件

💬 您可以前往 Github 或者 Gitee 下载笔者在本章使用的 demo。

  1. 打开 Visual Studio,创建两个控制台应用程序项目 RabbitMQProducerRabbitMQConsumer在这里插入图片描述> > RabbitMQProducer> > :生产者,用于向消息队列中发送消息;> > > > RabbitMQConsumer> > :消费者,接收来自消息队列中的消息
  2. 完成后,右击项目名称,点击“管理 NuGet 程序包”:在这里插入图片描述
  3. 分别为 RabbitMQProducerRabbitMQConsumer 两个项目引入 RabbitMQ.Client 库:在这里插入图片描述

以下是 RabbitMQProducer.cs 的代码:

using RabbitMQ.Client;
using System.Text;//连接 RabbitMQ 工厂实例
var factory = new ConnectionFactory(){ HostName ="localhost",//主机名,默认为 "localhost"
                                        Port =5672,//要连接的端口,默认为 -1(5672)
                                        UserName ="guest",//用户名,默认为 "guest"
                                        Password ="guest"};//密码,默认为 "guest"//创建连接对象using(var connection = factory.CreateConnection())//创建一个新的通道、会话和模型using(var channel = connection.CreateModel()){//声明一个消息队列
    channel.QueueDeclare(queue:"hello",//消息队列名称
                         durable: false,//队列是否能在代理重启后仍然存在
                         exclusive: false,//是否应该将此队列限制在其声明的连接中?这样的队列将在其声明连接关闭时被删除。(在一个客户端同时发送和读取消息的应用场景中适用)
                         autoDelete: false,//当最后一个消费者(如果有的话)退订时,是否应该自动删除这个队列?
                         arguments: null);//可选的;额外的队列参数,例如:“x-queue-type”//定义消息内容
    var message ="Hello RabbitMQ!";//转换为字节数组(编码格式UTF-8)
    var body = Encoding.UTF8.GetBytes(message);
    Console.WriteLine("按任意键开始发送消息!");
    Console.ReadKey();//循环发送一百次消息for(int i =0; i <100; i++){/*
         * 向 RabbitMQ 服务器发送一条消息
         * 调用 BasicPublish 方法后,指定的消息内容就会被发送到 RabbitMQ 服务器,并根据您指定的路由键被路由到相应的消息队列中
         */
        channel.BasicPublish(exchange:"",//指定要将消息发布到哪个交换机(exchange),设置为空字符串以使用默认交换机
                             routingKey:"hello",//指定消息的路由键(routing key),路由键用于确定消息应该被发送到哪些消息队列
                             basicProperties: null,//指定消息属性,可以用来设置消息的优先级、过期时间等属性
                             body: body);//消息内容,将要发送的数据转换为字节数组,并传递给这个参数//控制台打印发送的消息
        Console.WriteLine($"[{DateTime.Now.ToString("HH:mm:ss fff")}] Send: {message}");//当前线程暂停一秒钟
        Thread.Sleep(1000);}}

以下是 RabbitMQConsumer.cs 的代码:

using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System.Text;//连接 RabbitMQ 工厂实例
var factory = new ConnectionFactory(){ HostName ="localhost",//主机名,默认为 "localhost"
                                        Port =5672,//要连接的端口,默认为 -1(5672)
                                        UserName ="guest",//用户名,默认为 "guest"
                                        Password ="guest"};//密码,默认为 "guest"//创建连接对象
var connection = factory.CreateConnection();//创建一个新的通道、会话和模型
var channel = connection.CreateModel();//声明一个消息队列
channel.QueueDeclare(queue:"hello",//消息队列名称
                     durable: false,//队列是否能在代理重启后仍然存在
                     exclusive: false,//是否应该将此队列限制在其声明的连接中?这样的队列将在其声明连接关闭时被删除。(在一个客户端同时发送和读取消息的应用场景中适用)
                     autoDelete: false,//当最后一个消费者(如果有的话)退订时,是否应该自动删除这个队列?
                     arguments: null);//可选的;额外的队列参数,例如:“x-queue-type”//创建(将 IBasicConsumer 接口实现为事件的)EventingBasicConsumer 类对象并关联指定的 channel
var consumer = new EventingBasicConsumer(channel);/* 
 * 启动一个基本的内容类消费者(在当前通道中监听 hello 消息队列,并进行消费)
 * 调用 BasicConsume 方法后,您的应用程序就可以开始从指定的消息队列中接收消息了。
 * 当从消息队列中接收到一条消息时,消费者对象的 Received 事件会被触发,并执行相应的事件处理程序。
 */
channel.BasicConsume(queue:"hello",//消息队列名称
                     autoAck: true,//是否自动发送确认消息(acknowledgement)给 RabbitMQ 服务器
                     consumer: consumer);//指定用于接收消息的消费者对象//使用 Lambda 表达式注册事件处理程序并订阅 Received 事件
consumer.Received +=(sender, e)=>{
    var body = e.Body.ToArray();//获取消息字节数组
    var message = Encoding.UTF8.GetString(body);//UTF-8格式编码消息内容字符串
    Console.WriteLine($"[{DateTime.Now.ToString("HH:mm:ss fff")}] Consumer Received: {message},");//控制台打印消息内容(您也可以在这里添加其他的消息处理代码)};//控制台等待读取输入以避免进程退出
Console.ReadLine();//关闭连接以及它的所有通道
connection.Close();

运行效果:
在这里插入图片描述

7、生产[非]适用性免责声明

请记住,本教程和其他教程都是教程。他们一次展示一个新概念,可能会有意地过度简化一些东西,而忽略其他东西。例如,为了简洁起见,连接管理、错误处理、连接恢复、并发性和指标收集等主题在很大程度上被省略了。这种简化的代码不应该被认为可以用于生产。

在发布您的应用之前,请先查看其他文档。我们特别推荐以下指南:发布者确认和消费者确认,生产清单和监控。

8、Q&A

Q:Visual Studio 如何同时运行两个项目

A1:

  1. 在解决方案资源管理器中,右击解决方案节点,然后选择“属性”;在这里插入图片描述
  2. 展开“通用属性”节点,然后选择“启动项目”,选择“多个启动项目”选项并设置适当的操作。然后点击“应用”;在这里插入图片描述

A2: 或者更简单的,打开两个 Visual Studio 就好啦~

Q:我可以在第一台计算机上运行消息队列服务器,第二台计算机上运行发送消息的程序,第三台计算机上运行接收消息的程序吗?

A: 可以,只要这些平台之间能够相互通信(处于同一局域网内),它们就可以使用消息队列进行通信。同时这也意味着,在发送和接收消息的程序代码中,您需要指定 RabbitMQ 服务器所在的计算机的 IP 地址或主机名,以便连接到 RabbitMQ 服务器。
例如,如果您的消息队列服务器运行在 IP 地址为 192.168.1.100 的计算机上,您需要使用如下代码来创建

ConnectionFactory

对象:

var factory =newConnectionFactory(){HostName="192.168.1.100"};

💬 有关远程部署 RabbitMQ 服务的相关内容您可以点击这里了解更多。

标签: rabbitmq 分布式 c#

本文转载自: https://blog.csdn.net/YMGogre/article/details/131087813
版权归原作者 YMGogre 所有, 如有侵权,请联系我们删除。

“(一)「消息队列」之 RabbitMQ 入门”的评论:

还没有评论