消息中间件概述

MQ全称为Message Queue,消息队列是应用程序和应用程序之间的通信方法。是在消息的传输过程中保存消息的容器。多用于分布式系统之间进行通信。

  • 为什么使用MQ
    在项目中,可将一些无需即时返回且耗时的操作提取出来,进行异步处理,而这种异步处理的方式大大的节省了服务器的请求响应时间,从而提高了系统的吞吐量。

  • 开发中消息队列通常有如下应用场景:

    • 任务异步处理
      将不需要同步处理的并且耗时长的操作由消息队列通知消息接收方进行异步处理。提高了应用程序的响应时间。
    • 应用程序解耦合
      MQ相当于一个中介,生产方通过MQ与消费方交互,它将应用程序进行解耦合。
    • 削峰填谷
      如订单系统,在下单的时候就会往数据库写数据。但是数据库只能支撑每秒1000左右的并发写入,并发量再高就容易宕机。低峰期的时候并发也就100多个,但是在高峰期时候,并发量会突然激增到5000以上,这个时候数据库肯定卡死了。
      消息被MQ保存起来了,然后系统就可以按照自己的消费能力来消费,比如每秒1000个数据,这样慢慢写入数据库,这样就不会卡死数据库了。
      但是使用了MQ之后,限制消费消息的速度为1000,但是这样一来,高峰期产生的数据势必会被积压在MQ中,高峰就被“削”掉了。但是因为消息积压,在高峰期过后的一段时间内,消费消息的速度还是会维持在1000QPS,直到消费完积压的消息,这就叫做“填谷”

MQ 的劣势

  • 系统可用性降低
    系统引入的外部依赖越多,系统稳定性越差。一旦 MQ 宕机,就会对业务造成影响。如何保证MQ的高可用?
  • 系统复杂度提高
    MQ 的加入大大增加了系统的复杂度,以前系统间是同步的远程调用,现在是通过 MQ 进行异步调用。如何保证消息没有被重复消费?怎么处理消息丢失情况?那么保证消息传递的顺序性?
  • 一致性问题
    A 系统处理完业务,通过 MQ 给B、C、D三个系统发消息数据,如果 B 系统、C 系统处理成功,D 系统处理失败。如何保证消息数据处理的一致性?

既然 MQ 有优势也有劣势,那么使用 MQ 需要满足什么条件呢?

  • 生产者不需要从消费者处获得反馈。引入消息队列之前的直接调用,其接口的返回值应该为空,这才让明明下层的动作还没做,上层却当成动作做完了继续往后走,即所谓异步成为了可能。
  • 容许短暂的不一致性。
  • 确实是用了有效果。即解耦、提速、削峰这些方面的收益,超过加入MQ,管理MQ这些成本。

AMQP 和 JMS

MQ是消息通信的模型;实现MQ的大致有两种主流方式:AMQP、JMS。

AMQP

AMQP是一种协议,更准确的说是一种binary wire-level protocol(链接协议)。这是其和JMS的本质差别,AMQP不从API层进行限定,而是直接定义网络交换的数据格式。

AMQP,即 Advanced Message Queuing Protocol(高级消息队列协议),是一个网络协议,是应用层协议的一个开放标准,为面向消息的中间件设计。基于此协议的客户端与消息中间件可传递消息,并不受客户端/中间件不同产品,不同的开发语言等条件的限制。2006年,AMQP 规范发布。类比HTTP。

2007年,Rabbit 技术公司基于 AMQP 标准开发的 RabbitMQ 1.0 发布。RabbitMQ 采用 Erlang 语言开发。
Erlang 语言由 Ericson 设计,专门为开发高并发和分布式系统的一种语言,在电信领域使用广泛。

JMS

JMS即Java消息服务(JavaMessage Service)应用程序接口,是一个Java平台中关于面向消息中间件(MOM)的API,用于在两个应用程序之间,或分布式系统中发送消息,进行异步通信。

JMS 是 JavaEE 规范中的一种,类比JDBC

很多消息中间件都实现了JMS规范,例如:ActiveMQ。RabbitMQ 官方没有提供 JMS 的实现包,但是开源社区有

AMQP 与 JMS 区别

  • JMS是定义了统一的接口,来对消息操作进行统一;AMQP是通过规定协议来统一数据交互的格式
  • JMS限定了必须使用Java语言;AMQP只是协议,不规定实现方式,因此是跨语言的。
  • JMS规定了两种消息模式;而AMQP的消息模式更加丰富

消息队列产品

市场上常见的消息队列有如下:

  • ActiveMQ:基于JMS
  • ZeroMQ:基于C语言开发
  • RabbitMQ:基于AMQP协议,erlang语言开发,稳定性好
  • RocketMQ:基于JMS,阿里巴巴产品
  • Kafka:类似MQ的产品;分布式消息系统,高吞吐量

RabbitMQ

RabbitMQ 中的相关概念:

  • Broker:接收和分发消息的应用,RabbitMQ Server就是 Message Broker
  • Virtual host:出于多租户和安全因素设计的,把 AMQP 的基本组件划分到一个虚拟的分组中,类似于网络中的 namespace 概念。当多个不同的用户使用同一个 RabbitMQ server 提供的服务时,可以划分出多个vhost,每个用户在自己的 vhost 创建 exchange/queue 等
  • Connection:publisher/consumer 和 broker 之间的 TCP 连接
  • Channel:如果每一次访问 RabbitMQ 都建立一个 Connection,在消息量大的时候建立 TCP Connection的开销将是巨大的,效率也较低。Channel 是在 connection 内部建立的逻辑连接,如果应用程序支持多线程,通常每个thread创建单独的 channel 进行通讯,AMQP method 包含了channel id 帮助客户端和 message broker 识别 channel,所以 channel 之间是完全隔离的。Channel 作为轻量级的 Connection 极大减少了操作系统建立 TCP connection 的开销
  • Exchange:message 到达 broker 的第一站,根据分发规则,匹配查询表中的 routing key,分发消息到queue 中去。常用的类型有:direct (point-to-point), topic (publish-subscribe) and fanout(multicast)
  • Queue:消息最终被送到这里等待 consumer 取走
  • Binding:exchange 和 queue 之间的虚拟连接,binding 中可以包含 routing key。Binding 信息被保存到 exchange 中的查询表中,用于 message 的分发依据

RabbitMQ是由erlang语言开发,基于AMQP(Advanced Message Queue 高级消息队列协议)协议实现的消息队列,它是一种应用程序之间的通信方法,消息队列在分布式系统开发中应用非常广泛。

RabbitMQ官方地址:http://www.rabbitmq.com/

RabbitMQ提供了6种模式:简单模式,work模式,Publish/Subscribe发布与订阅模式,Routing路由模式,Topics主题模式,RPC远程调用模式(远程调用,不太算MQ;暂不作介绍);

官网对应模式介绍:https://www.rabbitmq.com/getstarted.html

RabbitMQ入门

pom.xml文件中添加如下依赖:

            <dependency><groupId>com.rabbitmq</groupId><artifactId>amqp-client</artifactId><version>5.6.0</version></dependency>
编写生产者
    public class Producer {static final String QUEUE_NAME = "simple_queue";public static void main(String[] args) throws Exception {//创建连接工厂ConnectionFactory connectionFactory = new ConnectionFactory();//主机地址;默认为 localhostconnectionFactory.setHost("localhost");//连接端口;默认为 5672connectionFactory.setPort(5672);//虚拟主机名称;默认为 /connectionFactory.setVirtualHost("/wanyuan");//连接用户名;默认为guestconnectionFactory.setUsername("wanyuan");//连接密码;默认为guestconnectionFactory.setPassword("wanyuan");//创建连接Connection connection = connectionFactory.newConnection();// 创建频道Channel channel = connection.createChannel();// 声明(创建)队列/*** 参数1:队列名称* 参数2:是否定义持久化队列* 参数3:是否独占本次连接* 参数4:是否在不使用的时候自动删除队列* 参数5:队列其它参数*/channel.queueDeclare(QUEUE_NAME, true, false, false, null);// 要发送的信息String message = "你好;赵丽颖!";/*** 参数1:交换机名称,如果没有指定则使用默认Default Exchage* 参数2:路由key,简单模式可以传递队列名称* 参数3:消息其它属性* 参数4:消息内容*/channel.basicPublish("", QUEUE_NAME, null, message.getBytes());System.out.println("已发送消息:" + message);// 关闭资源channel.close();connection.close();}}

在执行上述的消息发送之后;可以登录rabbitMQ的管理控制台,可以发现队列和其消息

编写消费者

抽取创建connection的工具类

    public class ConnectionUtil {public static Connection getConnection() throws Exception {//创建连接工厂ConnectionFactory connectionFactory = new ConnectionFactory();//主机地址;默认为 localhostconnectionFactory.setHost("localhost");//连接端口;默认为 5672connectionFactory.setPort(5672);//虚拟主机名称;默认为 /connectionFactory.setVirtualHost("/itcast");//连接用户名;默认为guestconnectionFactory.setUsername("heima");//连接密码;默认为guestconnectionFactory.setPassword("heima");//创建连接return connectionFactory.newConnection();}  }

编写消息的消费者

    public class Consumer {public static void main(String[] args) throws Exception {Connection connection = ConnectionUtil.getConnection();// 创建频道Channel channel = connection.createChannel();// 声明(创建)队列/*** 参数1:队列名称* 参数2:是否定义持久化队列* 参数3:是否独占本次连接* 参数4:是否在不使用的时候自动删除队列* 参数5:队列其它参数*/channel.queueDeclare(Producer.QUEUE_NAME, true, false, false, null);//创建消费者;并设置消息处理DefaultConsumer consumer = new DefaultConsumer(channel){@Override/*** consumerTag 消息者标签,在channel.basicConsume时候可以指定* envelope 消息包的内容,可从中获取消息id,消息routingkey,交换机,消息和重传标志(收到消息失败后是否需要重新发送)* properties 属性信息* body 消息*/public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {//路由keySystem.out.println("路由key为:" + envelope.getRoutingKey());//交换机System.out.println("交换机为:" + envelope.getExchange());//消息idSystem.out.println("消息id为:" + envelope.getDeliveryTag());//收到的消息System.out.println("接收到的消息为:" + new String(body, "utf-8"));}};//监听消息/*** 参数1:队列名称* 参数2:是否自动确认,设置为true为表示消息接收到自动向mq回复接收到了,mq接收到回复会删除消息,设置为false则需要手动确认* 参数3:消息接收到后回调*/channel.basicConsume(Producer.QUEUE_NAME, true, consumer);//不关闭资源,应该一直监听消息//channel.close();//connection.close();}}

总结

上述的入门案例中中其实使用的是如下的简单模式:

在上图的模型中,有以下概念:

  • P:生产者,也就是要发送消息的程序
  • C:消费者:消息的接受者,会一直等待消息到来。
  • queue:消息队列,图中红色部分。类似一个邮箱,可以缓存消息;生产者向其中投递消息,消费者从其中取出消息。

【消息中间件】浅谈中间件优缺RabbitMQ基本使用相关推荐

  1. 浅谈swagger优缺劣势,以及替代品

    平时不太关注的swagger, 最近拿到一个优化需求,需要把springboot 项目启动优化一下,于是开始了打怪埋坑的道路.先将讲一讲swagger 的原理实现以及优缺点. springfox-sw ...

  2. led手电筒烧灯珠_浅谈务优LED手电筒灯珠型号与区别技巧

    原标题:浅谈务优LED手电筒灯珠型号与区别技巧 LED灯珠有多种型号规格: LED灯珠的型号太多了,有直插和贴片式的,还有大功率灯珠,灯珠电流从几十毫安到几安的都有,电压就比较一致,大多都在三点几伏. ...

  3. 浅谈每日优鲜的私域运营

    每日优鲜现在企微私域用户已至百万级,按照预估,2021年企业微信的用户活跃度,相比2020年可能会再涨10倍. 这个团队有着非常非常强的方法论和理论支撑体系.不仅是上佳的方法.技巧学习对象,还是很好的 ...

  4. 普歌-浅谈RabbitMQ

    浅谈RabbitMQ 一.mq简介 mq(Message Queue),一种提供消息队列服务的中间件,也称消息中间件,提供消息生产.存储.消费全过程API软件系统. 二.常见的MQ ActiveMQ, ...

  5. 浅谈消息队列及常见的分布式消息队列中间件

    背景 分布式消息队列中间件是是大型分布式系统不可缺少的中间件,通过消息队列,应用程序可以在不知道彼此位置的情况下独立处理消息,或者在处理消息前不需要等待接收此消息.所以消息队列主要解决应用耦合.异步消 ...

  6. 浅谈Django的中间件与Python的装饰器

    浅谈Django的中间件 与Python的装饰器 一.原理 1.装饰器是Python的一种语法应用,利用闭包的原理去更改一个函数的功能,即让一个函数执行之前先到另外一个函数中执行其他需求语句,在执行该 ...

  7. 【JVM调优】JVM内存管理调优浅谈

    什么是JVM Java Virtual Machine,Java虚拟机 Java虚拟机有自己完善的硬件架构,如处理器.堆栈等,还具有相应的指令系统. Java虚拟机本质上就是一个程序,当它在命令行上启 ...

  8. 浅谈Spark应用程序的性能调优

    浅谈Spark应用程序的性能调优 :http://geek.csdn.net/news/detail/51819 下面列出的这些API会导致Shuffle操作,是数据倾斜可能发生的关键点所在  1. ...

  9. 浅谈tomcat中间件的优化【转】

    今天来总结一下tomcat的一些优化的方案,由于本人才疏学浅,写的不好,勿喷! tomcat对于大多数从事开发工作的童鞋应该不会很陌生,通常做为默认的开发环境来为大家服务,不过tomcat默认的一些配 ...

最新文章

  1. 为什么Control类提供了Invoke和BeginInvoke机制
  2. CodeForces - 1407E Egor in the Republic of Dagestan(最短路+dp)
  3. 发送结构化网络数据Server端
  4. python歌星大奖赛_在歌星大奖赛中,有10个评委为参赛选手打分,分数为1到100分。...
  5. sqlalchemy_SQLAlchemy使ETL变得异常简单
  6. git 查看自己秘钥_gitlab配置ssh密钥及简单使用
  7. 高度为5的3阶b树含有的关键字个数_第15期:索引设计(索引组织方式 B+ 树)
  8. tortoiseGit的SHH秘钥设置
  9. 单页面与多页面的优缺点
  10. phantomjs 安装使用
  11. 比尔盖茨 27 年婚姻破裂,8000 亿财产咋分配?
  12. 学堂在线计算机网络工程实践答案,计算机网络实验(本科生2017年春)
  13. java 到异常_java编程中遇到的异常以及异常的一些处理
  14. linux系统uptime解读,Linux中的uptime命令详解
  15. java递归用for实现_用java实现的经典递归算法
  16. (2)安装宝塔与docker及docker镜像下载加速
  17. 【Go】dep使用介绍
  18. java 代码块 构造函数_Java学习笔记之------构造函数,静态关键字,静态代码块,构造代...
  19. Android系统判断CPU是32位还是64位
  20. Android评论工具类,实现QQ空间文字评论效果

热门文章

  1. 自然语言处理常用工具
  2. Oracle的LINUX安装
  3. Lync日常维护之四:部分管理操作
  4. document.getElementsByTagName()方法的返回值
  5. 抽象工厂+反射+依赖注入 实现对数据访问层和业务逻辑层的优化
  6. django--静态文件路径和模板路径配置
  7. 在Mac下安装使用OpenCV
  8. 入门Qt——hello, world
  9. 相机上的AE AF AWB AEB都表示的是什么?
  10. rabbitmq一:基本概念