文章目录

  • 前言
    • 1.WorkQueue(工作队列)
      • 消息预取机制
    • 2.Publish&Subscribe(发布-订阅)
      • 1.Fanout(广播)
      • 2.DirectExchange(路由)
      • 3.TopicExchange(话题)
    • MQ的优点

前言

MQ的出现进一步降低了微服务模块之间的耦合度,相比于同步通信而言减少了关联服务的等待时间,使消息的传递更加多变,灵活
不管什么东西,只要被Spring整合就会变得十分简单,RabbitMQ也不例外
使用SpringAMQP来实现消息收发,不需要重复地配置连接参数,解决了一部分“硬编码”的问题。可以说和MyBatis整合JDBC非常相似。
在以前,使用原生的RabbitMQ收发消息是这样的:

使用SpringAMQP后收发消息是这样的:
这就是一个基本队列(Basic-Queue)

可以看到,只要引入依赖spring-boot-starter-amqp,写好yml配置文件,建立连接、创建通道的工作Spring都为我们做好了,而我们要做的仅仅就是利用工具类发送、监听消息,可以说相当的方便!
针对不同的场景,我们要使用不同的队列模型:

1.WorkQueue(工作队列)


对于单一消费者情况(简单队列),当生产者每秒发送50条消息,消费者每秒处理40条消息,这样每秒钟就会多出10条消息无法处理,由此就会产生生产过剩而导致消息堆积在队列中,一旦达到队列内存的上限,新来的消息就无法被处理而被丢弃。
为了提高消息处理的速度,避免队列中消息的堆积可以将队列绑定多个消费者,即WorkQueue

为了方便观察控制台,一般这样设计:
生产者:

@Test
public void testSendMessage2WorkQueue() throws InterruptedException {String queueName = "work.queue";String message = "hello, MQQ";for (int i = 1; i <= 50; i++) {rabbitTemplate.convertAndSend(queueName, message + i);Thread.sleep(20);}
}

消费者:
为了尽可能的模拟真实场景(消费者处理消息的能力不同),所以设置两个消费者的sleep参数为不同的两个时间

@RabbitListener(queues = "work.queue")
public void listenWorkQueue1(String msg) throws InterruptedException {System.out.println("消费者1接收到消息——【" + msg + "】" + "At "+LocalTime.now());Thread.sleep(20);
}@RabbitListener(queues = "work.queue")
public void listenWorkQueue2(String msg) throws InterruptedException {System.err.println("消费者2接收到消息——【" + msg + "】" + "At "+ LocalTime.now());Thread.sleep(200);
}

消息预取机制

运行后观察控制台,发现所有的消息处理完时间竟然花费了差不多五秒钟,很显然这样的效率是非常低下的:

为何绑定了两个消费者消费消息的速度不快反慢了呢?
仔细观察控制台会发现50条消息是被平均分配的,两个消费者分别消费id为偶数、奇数的消息,这样一想好像是处理能力差的消费者拖了后腿(200msX25=5000ms=5s),为什么会出现这样的情况?
这是由于MQ存在消息预取机制,即消费者会在处理之前预先拿到消息的通道,然后逐个处理消息,这个过程是与处理消息相隔离的!
如果还有人不明白就想想使用原生的RabbitMQ时我们是怎么处理消息的:

当执行完回调函数有可能消息都不会被处理,这时程序会继续向下执行,过段时间才会开始处理消息(其实我认为这也是体现RabbitMQ异步的一个地方
这样的机制存在是保证异步性的关键,通过人为的设置参数也可以将消息预取的方式做出调整,来保证处理的效率,就像这样:

listener:simple:prefetch: 1

通过prefetch参数来保证消费者每次获取消息的个数,以及处理完成后才能获取下一个批次的消息
进行数据预取设置后消费者在一秒之内处理完了所有的消息:

由此可见对于WorkQueue中消费者的设置要进行“按劳分配”的策略才较为完美
使用工作队列WorkQueue之后处理消息的效率得到了很大的提升,并且也不会出现消息堆积的情况

2.Publish&Subscribe(发布-订阅)

对于简单队列和工作队列模型,生产者发布消息,消费者一旦消费完,消息就会被销毁。这样无法做到将一个消息同时发送给多个消费者。

对于一个微服务项目,在支付订单的模型中当支付服务完成,会发消息同时去通知短信服务、订单服务…这就需要保证消息的高可用,不能一个服务消费完消息就被销毁而导致其他服务接收不到消息
如何做到将同一消息发送给多个消费者并让其各自接收到?采用发布&订阅的工作模型即可

通过交换机(exchange)将消息路由到不同的队列中,再由消费者来消费各自订阅队列中的消息
针对不同的交换机种类会有不同的发布策略:

1.Fanout(广播)

SpringAMQPA提供了声明交换机、队列、绑定关系的API

所以使用Exchange接口下的实现类就可以实现将消息路由到每一个绑定的Queue中,使用代码就会变得非常简单,声明交换机并绑定队列即可:

@Bean
public FanoutExchange fanoutExchange(){return new FanoutExchange("yu7.fanout");
}// fanout.queue1
@Bean
public Queue fanoutQueue1(){return new Queue("fanout.queue1");
}// 绑定队列1到交换机
@Bean
public Binding fanoutBinding1(Queue fanoutQueue1, FanoutExchange fanoutExchange){return BindingBuilder.bind(fanoutQueue1).to(fanoutExchange);
}// fanout.queue2
@Bean
public Queue fanoutQueue2(){return new Queue("fanout.queue2");
}// 绑定队列2到交换机
@Bean
public Binding fanoutBinding2(Queue fanoutQueue2, FanoutExchange fanoutExchange){return BindingBuilder.bind(fanoutQueue2).to(fanoutExchange);
}


注意:交换机只能用作消息的转发路由,不能用作消息的存储,一旦路由失败消息就会丢失!

2.DirectExchange(路由)

DirectExchange会将接收到的消息根据规则路由到指定的Queue中,生产者发布消息时指定消息的RoutingKey与消费者声明的bindingKey相匹配,从而达到“精确制导”

为了简化开发不使用声明Bean的方式来完成配置,通过@RabbitListener注解即可一键完成,所以根本不需要使用配置类:

生产者:

@Test
public void testSendDirectExchange() {// 交换机名称String exchangeName = "yu7.direct";// 消息String message = "hello, MQ!";// 发送消息rabbitTemplate.convertAndSend(exchangeName, "A", message);
}

消费者:

@RabbitListener(bindings = @QueueBinding(value = @Queue(name = "direct.queue1"),exchange = @Exchange(name = "yu7.direct", type = ExchangeTypes.DIRECT),key = {"A", "B"}
))
public void listenDirectQueue1(String msg){System.out.println("消费者接收到direct.queue1的消息:【" + msg + "】");
}@RabbitListener(bindings = @QueueBinding(value = @Queue(name = "direct.queue2"),exchange = @Exchange(name = "yu7.direct", type = ExchangeTypes.DIRECT),key = {"A", "C"}
))
public void listenDirectQueue2(String msg){System.out.println("消费者接收到direct.queue2的消息:【" + msg + "】");
}


当队列的bindingKey都相同时就变成了广播模型

3.TopicExchange(话题)

Topic与Direct非常相似,他允许RoutingKey-BindingKey以通配符的形式进行匹配,这样就可以更加有针对性的路由、订阅更多消息,并且以前用多个BindingKey的情况现在只需要用一个就能解决:
#:代表0或者多个单词
*:代指一个单词

MQ的优点

1、耦合度低:每次有新需求,只需要添加对应的订阅即可
2、吞吐量提升:各自处理自己订阅的事件,不需要等待执行完毕后再释放资源
3、故障隔离:因为没有强依赖,中间某一环节出了问题,不会影响整个流程
4、流量削峰:MQ就像—根管道,大量请求来了,你们给我排好队,依次执行

微服务的异步通信技术RabbitMQ相关推荐

  1. 网易蜂巢微服务架构:用RabbitMQ实现轻量级通信

    本文根据第60期线上分享整理而成,文末还有书送哦~ 本次分享内容由三个部分组成: 微服务架构与MQ RabbitMQ场景分析与优化 RabbitMQ在网易蜂巢中的应用和案例分享 微服务架构是一种架构模 ...

  2. 微服务框架 SpringCloud微服务架构 服务异步通讯 51 死信交换机 51.3 延迟队列 51.3.1 延迟队列 51.3.2 延迟队列插件

    微服务框架 [SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈课程|黑马程序员Java微服务] 服务异步通讯 文章目录 微服 ...

  3. 微服务那么热,创业公司怎么选用实践?

    2019独角兽企业重金招聘Python工程师标准>>> 微服务那么热,创业公司怎么选用实践? 博客分类: 架构 互联网公司的核心技术资产之一是云端运行的后台服务. 近些年在后台服务领 ...

  4. 微服务链路追踪之zipkin搭建

    前言 微服务治理方案中,链路追踪是必修课,SpringCloud的组件其实使用很简单,生产环境中真正令人头疼的往往是软件维护,接口在微服务间的调用究竟哪个环节出现了问题,哪个环节耗时较长,这都是项目上 ...

  5. 「Java分享客栈」随时用随时翻:微服务链路追踪之zipkin搭建

    前言 微服务治理方案中,链路追踪是必修课,SpringCloud的组件其实使用很简单,生产环境中真正令人头疼的往往是软件维护,接口在微服务间的调用究竟哪个环节出现了问题,哪个环节耗时较长,这都是项目上 ...

  6. python-37-python微服务框架Nameko

    Python微服务框架nameko的简单使用 推荐一款 Python 微服务框架 - Nameko 微服务框架有Istio.Dubbo和nameko三种: 一.Istio Istio是一个用来连接.管 ...

  7. java版Spring Cloud+Mybatis 微服务商城 b2b2c商城 直播商城 小程序商城 多商家入驻商城 APP商城源码 聚合支付商城

    1. 平台简介 一个全新覆盖全行业,以直播.短视频带货,商家实体VR全景体验,多营销模式,分销分佣,多商家入驻,多端支持的大型新零售电商平台. 2. 平台清单 系统管理平台 + 商家端(PC+手机) ...

  8. 基于Gitlab Jenkins Docker集群 微服务搭建自动化部署平台

    随着公司应用系统的不断增多,原有手工部署流程越来越不满足上线的需求.为了各个系统能快速迭代与测试,减少上线流程时间和人为出错,迫切需要一套自动化部署系统. 转载原文:https://luoji.liv ...

  9. 微服务框架 SpringCloud微服务架构 27 自动补全 27.2 自定义分词器

    微服务框架 [SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈课程|黑马程序员Java微服务] SpringCloud微服务 ...

最新文章

  1. 《精通Unix下C语言编程与项目实践》目录
  2. DenseNet 测试
  3. 浅谈.NET中的类型和装箱、拆箱原理
  4. c# 检查目录,当指定目录不存在时建立目录
  5. 计算机科学导论 第4版,计算机科学导论.第4版
  6. vim 的配置文件 #vim ~/.vimrc
  7. 前端学习(3125):react-hello-react之类式组件里的构造器域props
  8. 【形式语言与自动机】图灵机
  9. 《天天数学》连载19:一月十九日
  10. vue与外部html通信,VUE页面实现加载外部HTML方法
  11. 量子计算机张庆瑞讲座报告,燕山大学彭秋明、张庆瑞教授来我校开展学术交流...
  12. 服务链路追踪配置mysql_学习微服务的服务链路追踪——Spring Cloud Sleuth+zipkin
  13. 自己的包增加为第三方包,使用Eclipse环境报Unresolved import错误(pycharm可用正常引用)...
  14. java pkcs8_java中公钥,私钥,pkcs1格式,pkcs8格式互转
  15. 微信小程序布局 左右结构简单例子
  16. Rsyslog Properties and the Property Replacer
  17. 读 孙卫琴《Tomcat与Javaweb开发技术详解》
  18. a5 1c语言实现,A5算法的C语言实现
  19. 安装了,还是显示证书无效
  20. java中处理打折率_java:某商场给顾客的折扣率如下 购物金额小于200,不打折。购物金额大于等于200小于500...

热门文章

  1. 【GDAL】矢量栅格化函数-gdal_rasterize
  2. 自媒体可以去哪里找免费图片素材?
  3. 2021-10-31 九九乘法表
  4. 静态图片如何制作成gif动图?图片在线合成gif的方法
  5. 恋练有词考研英语高频词汇思维导图—Unit4
  6. DOTA2的英雄是如何打造出来的? DOTA 2美学原则解析
  7. bat 批处理文件 中if else 语句写法
  8. 推进700M产业链成熟,打响5G专网应用第一枪
  9. 带你一解那些词的格律
  10. Android Studio购买售卖系统