.NET 消息队列的使用

一、消息队列的优点

消息队列本质是生产者——消费者模式。也有很多使用方式。那么它有什么优点呢?以日常生活中邮寄信件这个行为举例, 当只有1个寄信人,1个邮递员的时候。寄信人想要寄信,到指定地点(邮局),直接将信件交给邮递员即可。

06cdd578b4e898ac129040606cfac594.png

当有50个寄信人的时候,1个邮递员的时候。这50个寄信人就要依次排队等待邮递员处理信件。可以增加邮递员的数量,但是依然会有忙闲不均的问题存在。

26865f39c9563913afb8880279dced50.png

我们现在增加一个邮筒(也就是数据缓冲区)

42f786a48d79c41c5a976cce984a6611.png

在这个例子中,寄信人就是生产者,邮递员是消费者。而邮筒就是一个消息队列。这个邮筒解决了以下问题:

1.1 解除耦合

实现了时间上解耦,也实现了对象间解耦。之前邮递员隶属于A邮局,寄信人想要寄信,到指定地点,直接将信件交给邮递员即可。如果因为实际需求,以后由B邮局的快递员负责寄信业务。那么寄信人就要去另一个地点寄信。这就是由于耦合产生的问题。现在不管信件是由A邮局还是其他邮局负责,寄信人只管将信件投递进邮筒就行了。解除了寄信人和邮递员的耦合性。

1.2 实现异步处理

之前寄信将信件直接交给邮递员,可能要等待邮递员要确认很多信息(比如寄件人信息)之后,长辄几分钟,才能结束本次寄信的行为。而现在将信件直接投递到邮箱里,只要不到1S,就能结束寄信的行为。

1.3 支持并发操作

解决同步处理的阻塞问题。之前所有寄信人需要排队等待上一个人寄信完毕,才能开始寄信。现在所有寄信人都把信件投递进邮筒即可。

1.4 实现流量削峰

可以根据邮递员方的处理能力,调节邮筒的容量。超过这个容量后,邮筒就放不下(拒绝)信件了。即能根据下游的处理能力自由调节流量,实现削峰。

二、安装erlang和RabbitMQ

2.1 安装erlang

由于RabbitMQ是基于erlang开发的,需要先安装erlang。确认自己要安装的RabbitMQ依赖的erlang的最低版本。

erlang:https://www.erlang.org/downloads 

安装后添加环境变量。

在系统变量中添加:

变量名:ERLANG_HOME

变量值:C:\Program Files\erl-24.0(安装ERLANG的文件夹) 

然后在用户变量的PATH中添加:%ERLANG_HOME%\bin

添加完环境变量之后可能需要重启。

然后打开CMD,运行erl,出现版本号为成功。

de73d8a77e0bcbe5dd4b407fe44152b8.png

2.2 安装RabbitMQ

RabbitMQ:https://github.com/rabbitmq/rabbitmq-server/releases/ 

安装成功后会自动创建RabbitMQ服务并且启动 

可以在任务管理器中确认:

2e5215d2394f302f67c33ca249796233.png

2.3 安装RabbitMQ的Web管理插件

在命令行中CD到安装目录下,执行 

rabbitmq-plugins.bat enable rabbitmq_management

13919625620d8e57f3eaaa1a62dc8557.png

成功后进入浏览器,输入:http://localhost:15672

初始账号和密码:guest/guest

e11e74aae35166f613d5bd785f8c4c83.png

三、理解消息队列中的基本概念

消息队列中有Exchange、Connection、Channel、Queue等概念

3.1 Exchange(交换机)

是生产者和消息队列的一个中介,负责将生产者的消息分发给消息队列。如果使用简单模式(只有一个生产者,一个消费者,一对一)时,不配置Exchange,实际上使用的是默认的Exchange。

3.2 Connection(连接)

是连接到MQ的TCP连接。为了方便理解,可以将Connection想象成一个光纤电缆。

3.3 Channel(通道)

一个Connection中存在多个Channel。可以把Channel理解为光纤电缆中的光纤。

3.4 Queue(消息队列)

一个Channel中可以存在多个Queue。

3.5 其他

因为建立和销毁 TCP 连接是非常昂贵的开销,所以一般维持Connection。在Connection之上,操作channel。Channel的其中一个作用就是,屏蔽Connection的TCP层面的细节,方便开发,同时达到TCP连接复用的效果。

四、尝试消息队列的简单模式(一对一)

新建一个解决方案,包含两个控制台程序,分别是生产者和消费者。右键解决方案,设置多项目启动。

bed0d2f535c8a81e038f73c93ad52051.png

4.1 生产者代码

/// <summary>
    /// 生产者
    /// </summary>
    internal class Program
    {
        private static void Main(string[] args)
        {
            //创建连接工厂
            ConnectionFactory factory = new ConnectionFactory
            {
                UserName = "guest",//用户名
                Password = "guest",//密码
                HostName = "localhost"//rabbitmq ip
            };

            //创建RabbitMQ的TCP长连接(可以比喻成一个光纤电缆)
            //因为建立和销毁 TCP 连接是非常昂贵的开销,所以一般维持连接(TCP连接复用)。在连接之上,建立和销毁channel。
            var connection = factory.CreateConnection();

            //创建通道(可以比喻成光纤电缆中的"一根"光纤)
            var channel = connection.CreateModel();

            /*声明一个队列:实现通道与队列的绑定
             * 5个参数:
             * queue:被绑定的消息队列名,当该消息队列不存在时,将新建该消息队列
             * durable:是否使用持久化
             * exclusive:该通道是否独占该队列
             * autoDelete:消费完成时是否删除队列, 该删除操作在消费者彻底断开连接之后进行。
             * args:其他配置参数
             */
            channel.QueueDeclare("hello", false, false, false, null);

            Console.WriteLine("\nRabbitMQ连接成功,生产者已启动,请输入消息,输入exit退出!");

            string input;
            do
            {
                input = Console.ReadLine();
                var sendBytes = Encoding.UTF8.GetBytes(input);
                //发布消息
                channel.BasicPublish("", "hello", null, sendBytes);
            }
            while (input.Trim().ToLower() != "exit");

            channel.Close();
            connection.Close();
        }
    }

4.2 消费者代码

/// <summary>
    /// 消费者
    /// </summary>
    internal class Program
    {
        private static void Main(string[] args)
        {
            //创建连接工厂
            ConnectionFactory factory = new ConnectionFactory
            {
                UserName = "guest",//用户名
                Password = "guest",//密码
                HostName = "localhost"//rabbitmq ip
            };

            //创建连接
            var connection = factory.CreateConnection();

            //创建通道
            var channel = connection.CreateModel();

            //事件基本消费者
            EventingBasicConsumer consumer = new EventingBasicConsumer(channel);

            //接收到消息事件
            consumer.Received += (ch, ea) =>
            {
                string message = Encoding.Default.GetString(ea.Body.ToArray());

                Console.WriteLine($"收到消息: {message}");

                //确认该消息已被消费
                channel.BasicAck(ea.DeliveryTag, false);

            };

            //启动消费者 设置为手动应答消息
            channel.BasicConsume("hello", false, consumer);
            Console.WriteLine("消费者已启动");
            Console.ReadKey();
            channel.Dispose();
            connection.Close();
        }
    }

4.3 测试

两个项目一起启动之后 在生产者对应的控制台输入文字后,添加到消息队列中,由消费者进行消费,显示在消费者控制台上。

2d38f9fc5b8e7afe91c9171be374a5ec.png

转自:SoraXTube.com✨

链接:cnblogs.com/soraxtube/p/14789116.html

版权声明:本文来源于网友收集或网友提供,仅供学习交流之用,如果有侵权,请转告版主或者留言,本公众号立即删除。

- EOF -

技术群:添加小编微信dotnet999

公众号:dotnet讲堂

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值