消息队列5:rabbitmq的WorkQueue模式

环境:

  • win10
  • rabbitmq-3.8.8
  • .net core 3.1
  • RabbitMQ.Client 6.2.1
  • vs2019

安装RabbitMq环境参照:

说明:

这一部分的代码与上一篇:《消息队列3:rabbitmq入门实例》基本上没有出入。
这一片注重rabbitmq的模式和参数的说明。

一、rabbitmq模式概念

一般说rabbitmq有6种工作模式

  1. 简单模式;
  2. WorkQueue模式
  3. Pub/Sub(发布/订阅模式);
  4. Routing(路由模式);
  5. Topic(主题模式);
  6. Rpc模式;

注意:这种划分模式的方法不是很让人理解,因为太过表面,如果我们明白其中的原理就能明白这几种模式都是由交换机队列的不同组合演变来的。
.
不过这里先默认划分为上面的6种工作模式,并讲解WorkQueue模式

WorkQueue模式:

应用场景举例:

网站有一个在线pdf转word的功能,但是此功能需要耗时10s,在高并发的时候容易造成请求积压,造成系统卡死。此时可以使用工作者模式解决:

  1. web站点接收请求时将参数压入队列,返回一个轮训标记;
  2. 后端根据处理能力部署多个消费者去消费转换任务,转换完成后,将该任务的轮训标记和转换结果存入redis;
  3. 前端根据轮训标记每个3秒轮训一次。

直接用图形说明:
在这里插入图片描述

在这种模式下,可以有多个生产者同时向队列中发送消息,而接收方也可以有多个,但是一条消息只能发送给一个消费者,rabbitmq默认是轮训发送的,但是我们可以通过参数控制消费者接受消息的能力。

二、代码

准备解决方案如下:
在这里插入图片描述
发送端(send)和接收端(receive)都引用rabbitmq客户端:

<PackageReference Include="RabbitMQ.Client" Version="6.2.1" />

2.1 发送端的代码

using RabbitMQ.Client;
using System;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Send
{
    class Program
    {
        static void Main(string[] args)
        {
            //1. 实例化连接工厂
            var factory = new ConnectionFactory()
            {
                HostName = "localhost",//默认: localhost
                Port = 5672,//默认: 5672
                UserName = "guest",//默认: guest
                Password = "guest",//默认: guest
                VirtualHost = "/" //默认: /
            };
            //2. 建立连接
            using (var connection = factory.CreateConnection())
            {
                var t = Task.Factory.StartNew(() =>
                  {
                      //3. 创建信道
                      var channel = connection.CreateModel();
                      {
                          //4. 声明队列 注意,同名的队列多次声明时以第一次声明的参数为准,其后声明的参数必须与第一次的声明一致,否则其后的声明会报错
                          channel.QueueDeclare(
                                queue: "hello",//队列名字
                                durable: true,//是否持久化消息(持久化后对于未消费的消息,rabbitmq可以保证重启后消息不丢失)
                                exclusive: false,//独占的,为true时表示: 当前队列只能同时被一个连接声明(一个连接的多个信道内可以多次声明),当connection关闭时队列被自动删除,队列内的数据不会保存,工作模式下这个参数设置为false,它的应用场景在pub/sub上,当sub加入时声明一个独占的队列,当sub断开时此队列就自动删除了
                                autoDelete: false,// 当这个队列的consumer从非0变为0的时候,这个队列会被删除,任何发向此队列的消息都会丢失,当有新的消费者出现时,消费者会接收到新发送的消息(注意: 只有在consumer从非0变为0的时候才会触发删除,刚开始没有消费者的时候,发向此队列的消息是会被积累的),工作模式下这个参数设置为false
                                arguments: null//其他参数信息
                                );
                          //5. 发送数据包
                          var index = 1;
                          while (true)
                          {
                              string message = $"chanel1-{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")} 测试消息:{index}";
                              var body = Encoding.UTF8.GetBytes(message);
                              channel.BasicPublish(exchange: "", routingKey: "hello", basicProperties: null, body: body);
                              Console.WriteLine(" [x] Sent {0}", message);
                              Thread.Sleep(1000);
                              index++;
                          }
                      }
                  }, TaskCreationOptions.LongRunning);
                t.Wait();
            }
        }
    }
}

2.2 消费端的代码

using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System;
using System.Text;
using System.Threading;

namespace Receive
{
    class Program
    {
        static void Main(string[] args)
        {
            //1.实例化连接工厂
            var factory = new ConnectionFactory();
            //2. 建立连接
            using (var connection = factory.CreateConnection())
            {
                //3. 创建信道
                using (var channel = connection.CreateModel())
                {
                    //4. 声明队列
                    channel.QueueDeclare(queue: "hello", durable: false, exclusive: false, autoDelete: true, arguments: null);
                    //5. 构造消费者实例
                    var consumer = new EventingBasicConsumer(channel);
                    //6. 绑定消息接收后的事件委托
                    consumer.Received += (model, ea) =>
                    {
                        var message = Encoding.UTF8.GetString(ea.Body.ToArray());
                        Console.WriteLine(" [x] Received {0}", message);
                        Thread.Sleep(1000);//模拟耗时
                        Console.WriteLine(" [x] Done");
                    };
                    //7. 启动消费者
                    channel.BasicConsume(queue: "hello", autoAck: true, consumer: consumer);
                    Console.WriteLine(" Press [enter] to exit.");
                    Console.ReadLine();
                }
            }
        }
    }
}

运行效果:

开启一个发送端和两个接收端(也可以开启两个发送端,这里为了演示接收端的消息竞争仅开一个发送端):

发送端的效果:
在这里插入图片描述
其中一个接受端效果:
在这里插入图片描述

最后,示例代码下载:
https://download.csdn.net/download/u010476739/16746253

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jackletter

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值