说起RabbitMQ大家第一时间应该想到的就是异步队列,关于异步队列的话题简直太多了,各位同学在园子里一搜便知。我第一次听异步队列这个名词感觉非常高大上,想到这项技术必须要学。但是学习的任何一门技术没经过项目的洗礼,都似乎少了点什么。嗯。是的。只有在企业级开发中,才能找到自己的遗漏的知识点。所以大家一定要想办法将自己学习到的东西糅合进项目中。以我现在一贯的作风就是学习、巩固、总结与分享。虽然介绍RabbitMQ这类博客已经很多了,但是人家写的毕竟是人家写的,我要把自己的学习心得记录下来,一来巩固自己的知识,二来可以帮到其它的小伙伴。

首先说一下队列.队列的本质是一种先进先出的线性存储结构。注意不要和栈弄反了,栈的存储结构是先进后出

那怎样理解异步队列?

举个例子:假如在电商系统中,用户下单成功之后。A服务要拿到下单信息发送邮件(350ms)给用户,B服务要拿到下单信息发送短信(400ms)给用户,C服务要拿到下单信息记录日志(300ms),如果三个服务利用RPC远程调用下单服务提供的api,在排队等候时(可能有分布式锁)将要耗费1050ms,而且耦合太高了,如果下单服务改由另一个服务承担那么ABC服务都得跟着改,接下来就变成下面这样。

用户下单成功后直接将数据存进消息队列(数据库也会存一份),ABC三服务直接从消息队列中拿下单信息,不再排队等候(异步),时间耗费400ms。性能提升了一倍之多。而且谁将数据放入消息队列ABC三服务根本不用管,它们现在只认数据不认人.

再来说一下RabbitMQ.RabbitMQ是采用Erlang语言实现的消息中间件。RabbitMQ几乎支持所有的常用语言,并且提供了用户管理界面,可以方便用户管理和监控消息。在使用RabbitMQ之前我们先安装她。这里的话我只说一下在Linux下使用小鲸鱼安装

  1. docker pull rabbitmq:management
  2. docker run -d -p 15672:15672 -p 5672:5672 --name rabbitmq rabbitmq:management

不出意外的话容器已经启动了,如果有问题的话就看日志.

默认情况下访问RabbitMQ 用户名和密码都是 "guest" ,但是这个这个账户有限制,默认只能通过本地网络访问,远程连接的话受限.

这里的话要执行以下命令.  ps:命令是网上找的

  1. docker exec -it rabbitmq bash --进入容器
  2. rabbitmq-plugins enable rabbitmq_management --开启插件命令

这里再说一下生产者和消费者。生产者就是往消息队列中加入(创建)数据的一方。消费者就是拿到(接收)消息的一方。

接下来在代码中简单演示一下.

新建两个控制台程序。引入包RabbitMQ.Client.

生产者代码:

  1. static void Main(string[] args)
  2. {
  3. //创建连接工厂
  4. var factory = new ConnectionFactory
  5. {
  6. UserName = "guest",//用户名
  7. Password = "guest",//密码
  8. HostName = "***.**.***.***",//rabbitmq ip
  9. Port = 5672,//端口号
  10. };
  11. //创建连接
  12. var connection = factory.CreateConnection();
  13. //创建信道
  14. var channel = connection.CreateModel();
  15. //创建一个队列,名称为:RabbitMQStudy
  16. channel.QueueDeclare("RabbitMQStudy", false, false, false, null);
  17. Console.WriteLine("已连接到RabbitMQ.^-^,可向队列投递消息!");
  18. Console.WriteLine("输入close则关闭连接");
  19. string text = string.Empty;
  20. bool flag = true;
  21. while (flag)
  22. {
  23. Console.WriteLine("请输入数据......");
  24. text = Console.ReadLine();
  25. switch (text)
  26. {
  27. case "close":
  28. flag = false;
  29. continue;
  30. default:
  31. flag = true;
  32. break;
  33. }
  34. var bytes = Encoding.UTF8.GetBytes(text);
  35. //发布消息
  36. channel.BasicPublish("", "RabbitMQStudy", null, bytes);
  37. Console.WriteLine("消息已发送成功!");
  38. Console.WriteLine(new string('-', 100));
  39. }
  40. Console.WriteLine("连接已关闭......");
  41. //关闭资源
  42. channel.Close();
  43. //释放连接
  44. connection.Close();
  45. }

消费者代码:

  1. static void Main(string[] args)
  2. {
  3. //创建连接工厂
  4. ConnectionFactory factory = new ConnectionFactory
  5. {
  6. UserName = "guest",//用户名
  7. Password = "guest",//密码
  8. HostName = "***.**.***.***",//rabbitmq ip
  9. Port = 5672,//端口号
  10. };
  11. //创建连接
  12. var connection = factory.CreateConnection();
  13. //创建信道
  14. var channel = connection.CreateModel();
  15.  
  16. //var consumer = new DefaultBasicConsumer(channel);
  17. var consumer = new EventingBasicConsumer(channel);
  18. //为消费者送达消息时产生的事件
  19. consumer.Received += (ch, ea) =>
  20. {
  21. var message = ea.Body.ToArray();//接收到的消息
  22. Console.WriteLine($"接收到信息:{Encoding.UTF8.GetString(message)}");
  23. //消息已被消费
  24. channel.BasicAck(ea.DeliveryTag, false);
  25. Console.WriteLine("消息已成功接收并消费!");
  26. Console.WriteLine(new string('-', 100));
  27. };
  28. //启动消费者并设置为手动应答
  29. String consumerTag = channel.BasicConsume("RabbitMQStudy", false, consumer);
  30. Console.WriteLine("消费者已启动成功!");
  31. Console.ReadKey();
  32. channel.Dispose();
  33. connection.Close();
  34. }

开启了三个消费者,这时队列中的消息会被平均分摊(订阅了同一个队列).RabbitMQ有轮询的机制,所以不是每个消费者都可以收到所有的消息井处理。

下面说一下三个重要的知识点:交换器、路由键、绑定

交换器:生产者向消息队列发送消息数据时,其实消息先到交换器再由交换器路由到相应的队列。这里有同学就会问了,我们刚刚上面的代码并没有申明交换器啊,其实这里我们发送消息时exchange参数为(" "),相当于默认创建好的一个交换器(类型为direct)。直接用RouteKey指定队列名即可.

  1. 交换器一共有四种类型:1.fanout:此类型的交换器会将发送到该交换器的的消息路由到所有与该交换器绑定的队列中
  2. 2.directc:如果交换器类型为direct类型,那么RoutingKey(路由键,相当于消息投送至与交换器绑定的哪个队列)和BindingKey(绑定键,交换器与队列相绑定有一个BindingKey)需要完全匹配(相同)。
  3. 3.topic:topic是升级版的direct类型的交换器,与direct类型交换器相同的是topic类型的交换器也是将消息路由到RoutingKeyBindingKey相匹配的队列中。与direct类型交换器不同的是topic类型的交换器有模糊匹配。 例如:我们发送消息时会路由到指定RouteKey队列中.交换器在与队列绑定的时候,BindingKey可以是模糊类型的.RouteKeyBindingKey都是以点号“.”分割的字符串.BindingKey的字符串可以存在“ * ”和“ # ”特殊字符。在以点号“ . ”为分割的字符串中,“ . ”用于匹配一个单词," # "用于匹配多个(或零个)单词.
  4. 4.headers:这个交换器我在这里不做介绍,我没用过,上面介绍的三个是最常用的了。

如下图所示申明了一个topic类型的交换器,当路由键为core.never.net的消息会同时路由到队列1和队列2中。当路由键为go.never.cn的消息也会同时路由到队列1与队列2中。当路由键为www.bilibili.com的消息会路由到队列2中。 

举个例子,在生产者代码中再加几句代码:

  1. //和上面一样,代码省略...
    //创建一个队列,名称为:RabbitMQStudy
  2. channel.QueueDeclare("RabbitMQStudy", false, false, false, null);
  3. //创建一个队列,名称为:RabbitMQStudy1
  4. channel.QueueDeclare("RabbitMQStudy1", false, false, false, null);
  5. //声明一个交换器
  6. channel.ExchangeDeclare("exange", "topic", true, false, null);
  7. //绑定
  8. channel.QueueBind("RabbitMQStudy", "exange","#.routeKey");
  9. //绑定
  10. channel.QueueBind("RabbitMQStudy1", "exange", "*.com");
  1. //和上面一样,代码省略...
  1. //发布消息
    channel.BasicPublish("exange", "core.routeKey", null, bytes);
  1. //和上面一样,代码省略...

在建一个控制台程序(消费者),和第一个消费者的代码一样,只不过两个消费者监听设置的队列名不一样。一个是RabbitMQStudy,一个是RabbitMQStudy1。

  1. //启动消费者并设置为手动应答
  2. String consumerTag = channel.BasicConsume("RabbitMQStudy1", false, consumer);

运行... ...

可以看到只有消费者1接收到了消息,模糊匹配的作用就展现出来了.

路由键:生产者将消息发送给交换器时,会指定一个路由key,用于设定这个消息的路由规则,路由key需要与交换器类型和绑定key联合使用才能有效。

绑定:RabbitMQ中通过绑定将交换器与队列进行关联,在交换器与队列进行绑定时会有一个绑定键,这样结合路由键RabbitMQ就会知道将消息投递到哪个队列中。

  1. 争对上述代码及文字我们来总结一下
  2.  
  3. 消息队列的优缺点:1.解耦,我上面提到了,消费者只需要拿数据,数据的投递方是谁它一点都不过问。
  4. 2.削峰.当我们设计一个秒杀业务的时候,假如成千上万的请求涌入,服务器的压力过大。为了缓解压力我们可以将请求先放入队列中,服务器一定时间内可以承受多少请求就拿多少。
  5. 3.异步.我上面也提到了.直接从消息队列中拿数据,无需排队等候,大大提高了系统性能。
  6.  
  7. RabbitMQ的调用过程:生产者:1.先创建连接工厂,与RabbitMQ建立连接。
  8. 2.创建信道。
  9. 3.声明一个交换器,设置交换器类型、是否持久化等。
  10. 4.声明队列,设置队列是否排他、是否持久化等。
  11. 5.将交换器与队列绑定,设置RouteKey
  12. 6.发送消息至交换器,并设置交换器名称、路由键、消息主体等。
  13. 7.交换器根据路由键和绑定的队列相匹配,投送消息至队列中。
  14. 8.如果没有找到相应队列,会根据生产者配置的属性丢弃消息或者退回给生产者。
  15. 9.关闭连接。
  16.  
  17. 消费者:1.先创建连接工厂,与RabbitMQ建立连接。
  18. 2.创建信道。
  19. 3.等待生产者投递消息至队列,消费者接收消息。
  20. 4.消费者确认接收到消息
  21. 5.RabbitMQ从队列中删除已确认的消息。
  22. 6.关闭连接。

今天就这么多,后续文章会一一介绍RabbitMQ其它特性。

如有不足,请见谅!

RabbitMQ巩固学习一的更多相关文章

  1. C#RabbitMQ基础学习笔记

    RabbitMQ基础学习笔记(C#代码示例) 一.定义: MQ是MessageQueue,消息队列的简称(是流行的开源消息队列系统,利用erlang语言开发).MQ是一种应用程序对应用程序的通信方法. ...

  2. Rabbitmq相关学习网址

    1.安装文档: http://www.cnblogs.com/shuzhenyu/p/9823324.html 2.RabbitMq的整理 exchange.route.queue关系 https:/ ...

  3. RabbitMQ小白菜学习之在window下的安装配置

    RabbitMQ安装 首先需要下载RabbitMQ的平台环境Erlang OTP平台和RabbitMQ Server(windows版): OTP 19.1 Windows 64-bit Binary ...

  4. RabbitMQ 应用学习随笔

    1.安装 Rabbit MQ 是建立在强大的Erlang OTP平台上,因此安装RabbitMQ之前要先安装Erlang. erlang:http://www.erlang.org/download. ...

  5. RabbitMQ的学习

    生成者就是发送信息,消费者就是接收信息,队列就是存储数据的排队.消息通过你的应用程序和RabbitMQ进行传输,它们只能存储在队列中,队列容量没有限制,你要存储多少消息都可以——基本上是一个无限的缓冲 ...

  6. rabbitmq系统学习(三)集群架构

    RabbitMQ集群架构模式 主备模式 实现RabbitMQ的高可用集群,一般在并发和数据量不高的情况下,这种模型非常的好用且简单.主备模式也称为Warren模式 HaProxy配置 listen r ...

  7. rabbitmq系统学习(二)

    Rabbitmq高级整合应用 RabbitMq整合Spring AMQP实战 RabbitAdmin 使用RabbitTemplate的execute方法执行对应操作 rabbitAdmin.decl ...

  8. rabbitmq系统学习(一)

    各种mq activemq,kafka使用zookeeper做管理 rocketmq自己实现nameserver broke管理 AMQP核心概念 高级消息队列协议 publisher applica ...

  9. rabbitmq基础学习+springboot结合rabbitmq实现回调确认confirm

    rabbitmq集群docker快速搭建 https://blog.csdn.net/u011058700/article/details/78708767 rabbitmq原理博客 https:// ...

随机推荐

  1. VUE 关键字

    转 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&q ...

  2. ubuntu 安装 swftoos

    一:下载依赖: freetype下载地址 : http://ftp.twaren.net/Unix/NonGNU/freetype/ jpegsrc:下载地址 http://www.ijg.org/f ...

  3. SOFA入门

    简介 scalable open financial architecture stack , 可扩展开放的金融架构栈: github: https://github.com/sofastack/so ...

  4. springboot 启动报错"No bean named 'org.springframework.context.annotation.ConfigurationClassPostProcessor.importRegistry' available"

    1.问题 springboot启动报错 "D:\Program Files\Java\jdk-11\bin\java.exe" -XX:TieredStopAtLevel=1 -n ...

  5. SourceTree 配置 GitLab

    生成SSH 创建SSH,执行ssh-keygen -t rsa -C "youremail@example.com",会在.ssh目录下生成id_rsa.id_rsa.pub两个私 ...

  6. shell日期格式化、加减运算

    #!/bin/bash echo i love you输出:i love you =======================================反引号的作用============== ...

  7. Alpha冲刺 —— 5.1

    这个作业属于哪个课程 软件工程 这个作业要求在哪里 团队作业第五次--Alpha冲刺 这个作业的目标 Alpha冲刺 作业正文 正文 github链接 项目地址 其他参考文献 无 一.会议内容 1.展 ...

  8. 【Win10】BeyondCompare时提示"许可证密钥已被撤销"的解决办法

    删除...AppData\Roaming\Scooter Software\Beyond Compare 3目录下所有文件. 应该是对应了bcompare的配置文件以及记录文件.删除了之后,就等于新安 ...

  9. Java实现 LeetCode 501 二叉搜索树中的众数

    501. 二叉搜索树中的众数 给定一个有相同值的二叉搜索树(BST),找出 BST 中的所有众数(出现频率最高的元素). 假定 BST 有如下定义: 结点左子树中所含结点的值小于等于当前结点的值 结点 ...

  10. Java实现 蓝桥杯VIP 算法提高 贪吃的大嘴

    算法提高 贪吃的大嘴 时间限制:1.0s 内存限制:256.0MB 问题描述 有一只特别贪吃的大嘴,她很喜欢吃一种小蛋糕,而每一个小蛋糕有一个美味度,而大嘴是很傲娇的,一定要吃美味度和刚好为m的小蛋糕 ...