“分类:MQ”的版本间差异
跳到导航
跳到搜索
(→关于) |
(→关于) |
||
第6行: | 第6行: | ||
=== 什么是MQ? === | === 什么是MQ? === | ||
MQ(Message Queue)是一种''' | <pre> | ||
消息队列(英语:Message queue)是一种进程间通信或同一进程的不同线程间的通信方式,软件的贮列用来处理一系列的输入,通常是来自用户。消息队列提供了异步的通信协议,每一个贮列中的纪录包含详细说明的数据,包含发生的时间,输入设备的种类,以及特定的输入参数,也就是说:消息的发送者和接收者不需要同时与消息队列互交。消息会保存在队列中,直到接收者取回它。 ——维基百科 | |||
</pre> | |||
MQ(Message Queue)是一种'''异步的服务间通信方式''',适用于无服务器和微服务架构。消息在被处理和删除之前一直存储在队列上。 | |||
* 通俗点说,就是一个先进先出的数据结构。 | |||
=== 为什么使用MQ?(使用场景)=== | === 为什么使用MQ?(使用场景)=== |
2021年5月15日 (六) 19:03的版本
消息中间件
关于
系统间通信方式?
一种是基于远程过程调用的方式(如 RPC 调用);另一种是基于消息队列的方式。
什么是MQ?
消息队列(英语:Message queue)是一种进程间通信或同一进程的不同线程间的通信方式,软件的贮列用来处理一系列的输入,通常是来自用户。消息队列提供了异步的通信协议,每一个贮列中的纪录包含详细说明的数据,包含发生的时间,输入设备的种类,以及特定的输入参数,也就是说:消息的发送者和接收者不需要同时与消息队列互交。消息会保存在队列中,直到接收者取回它。 ——维基百科
MQ(Message Queue)是一种异步的服务间通信方式,适用于无服务器和微服务架构。消息在被处理和删除之前一直存储在队列上。
- 通俗点说,就是一个先进先出的数据结构。
为什么使用MQ?(使用场景)
消息队列常见的使用场景很多,但是比较核心的有 3 个:解耦、异步、削峰。
常用的使用场景:
- 非实时性:当不需要立即获得结果,但是并发量又需要进行控制的时候,差不多就是需要使用消息队列的时候。主要解决了应用耦合、异步处理、流量削锋等问题。
- 应用耦合:多应用间通过消息队列对同一消息进行处理,避免调用接口失败导致整个过程失败;(如:订单->库存)
- 异步处理:多应用对消息队列中同一消息进行处理,应用间并发处理消息,相比串行处理,减少处理时间;(点对多场景,广播场景(注册发短信,发邮件)等等)
- 限流削峰:应用于秒杀或抢购活动中,避免流量过大导致应用系统挂掉的情况;(根据服务承受度设置队列大小,超过了就返回活动结束了,咱们经常各大商城秒杀,心里还没有点B数吗)减少压力,避免服务挂掉。
- 消息驱动的系统:系统分为消息队列、消息生产者、消息消费者,生产者负责产生消息,消费者(可能有多个)负责对消息进行处理;(分工处理(各自对应相应的队列),灵活应用(收到就处理/定时处理))
MQ有哪些缺点?
- 系统可用性降低:系统引入的外部依赖越多,越容易挂掉。本来你就是 A 系统调用 BCD 三个系统的接口就好了,人 ABCD 四个系统好好的,没啥问题,你偏加个 MQ 进来,万一 MQ 挂了咋整,MQ 一挂,整套系统崩溃的,你不就完了?
- 系统复杂度提高:硬生生加个 MQ 进来,你怎么保证消息没有重复消费?怎么处理消息丢失的情况?怎么保证消息传递的顺序性?头大头大,问题一大堆,痛苦不已。
- 一致性问题:A 系统处理完了直接返回成功了,人都以为你这个请求就成功了;但是问题是,要是 BCD 三个系统那里,BD 两个系统写库成功了,结果 C 系统写库失败了,咋整?你这数据就不一致了。
MQ 基础
消息中间件模式分类
- 点对点(PTP):使用 queue 作为通信载体。
- 消息被消费以后,queue中不再存储,所以消息消费者不可能消费到已经被消费的消息。 【不存在重复消费】
- Queue支持存在多个消费者,但是对一个消息而言,只会有一个消费者可以消费。【一个消息对应一个消费者】
- 发布/订阅(Pub/Sub):使用 topic 作为通信载体
- 和点对点方式不同,发布到topic的消息会被所有订阅者消费。【一个消息对应多个消费者】
消息推拉模式
- pull:(拉)主动权在于消费方,优点是按需消费(吃自助餐,能吃多少拿多少),而且服务端队列堆积的消息处理也相对简单。
- 缺点就是消息延迟(不知道啥时候去拉取更新)。
- push:(推)主动权就在服务方了,优点是实时性高,服务端可以统一管理来进行负载,不过也容易导致慢消费。
- 缺点就是发送消息的状态是集中式管理。
当然也可以根据实际情况,将二者结合使用来:1、提高消息的实时性;2、按需消费;
消息中间件常用协议
- AMQP 协议:
- AMQP 即 Advanced Message Queuing Protocol,一个提供统一消息服务的应用层标准高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计。基于此协议的客户端与消息中间件可传递消息,并不受客户端/中间件不同产品,不同开发语言等条件的限制。
- 优点:可靠、通用
- MQTT 协议
- MQTT(Message Queuing Telemetry Transport,消息队列遥测传输)是 IBM 开发的一个即时通讯协议,有可能成为物联网的重要组成部分。该协议支持所有平台,几乎可以把所有联网物品和外部连接起来,被用来当做传感器和致动器(比如通过Twitter让房屋联网)的通信协议。
- 优点:格式简洁、占用带宽小、移动端通信、PUSH、嵌入式系统
- STOMP 协议
- STOMP(Streaming Text Orientated Message Protocol)是流文本定向消息协议,是一种为MOM(Message Oriented Middleware,面向消息的中间件)设计的简单文本协议。STOMP提供一个可互操作的连接格式,允许客户端与任意STOMP消息代理(Broker)进行交互。
- 优点:命令模式(非topic\queue模式)
- XMPP 协议
- XMPP(可扩展消息处理现场协议,Extensible Messaging and Presence Protocol)是基于可扩展标记语言(XML)的协议,多用于即时消息(IM)以及在线现场探测。适用于服务器之间的准即时操作。核心是基于XML流传输,这个协议可能最终允许因特网用户向因特网上的其他任何人发送即时消息,即使其操作系统和浏览器不同。
- 优点:通用公开、兼容性强、可扩展、安全性高,但XML编码格式占用带宽大
- 其他基于 TCP/IP 自定义的协议:
- 有些特殊框架(如:redis、kafka、zeroMq等)根据自身需要未严格遵循MQ规范,而是基于TCP/IP自行封装了一套协议,通过网络 socket 接口进行传输,实现了MQ的功能。
MQ需要考虑的问题
怎么保证消息没有重复消费?
- 如果是拿这个消息做数据库 insert 操作(事实上 update 和 delete 重复也不影响)给这个消息做一个唯一主键,那么就算出现重复消费的情况,就会导致主键冲突,避免数据库出现脏数据。
- 当拿到这个消息做 redis 的 set 的操作,那就容易了,不用解决,因为你无论 set 几次结果都是一样的,set 操作本来就算幂等操作。
- 如果上面两种情况还不行,准备一个第三方存储,来做消费记录。以 redis 为例,给消息分配一个全局 id,只要消费过该消息,将 <id,message> 以 K-V 形式写入 redis。那消费者开始消费前,先去 redis 中查询有没消费记录即可。
怎么处理消息丢失的情况?
怎么保证消息传递的顺序性?
怎么保证多系统消息一致性?
选型
总的来说:
- 中小型软件公司,建议选 RabbitMQ;
- 大型软件公司,根据具体使用在 RocketMQ 和 Kafka 之间二选一。
- 根据业务场景选择,如果有大数据、日志采集功能,首选 Kafka。
有哪些MQ?
- ActiveMQ:是 Apache 出品的、采用 Java 语言编写的完全基于JMS1.1规范的面向消息的中间件,为应用程序提供高效的、可扩展的、稳定的和安全的企业级消息通信。
- 不过由于历史原因包袱太重,目前市场份额没有后面三种消息中间件多,其最新架构被命名为 Apollo,号称下一代 ActiveMQ,有兴趣的同学可行了解。
- RabbitMQ:是采用 Erlang 语言实现的 AMQP 协议的消息中间件,最初起源于金融系统,用于在分布式系统中存储转发消息。
- RabbitMQ 发展到今天,被越来越多的人认可,这和它在可靠性、可用性、扩展性、功能丰富等方面的卓越表现是分不开的。
- Kafka:起初是由 LinkedIn 公司采用 Scala 语言开发的一个分布式、多分区、多副本且基于 Zookeeper 协调的分布式消息系统,现已捐献给 Apache 基金会。
- 它是一种高吞吐量的分布式发布订阅消息系统,以可水平扩展和高吞吐率而被广泛使用。
- 目前越来越多的开源分布式处理系统,如:Cloudera、Apache Storm、Spark、Flink 等都支持与 Kafka 集成。
- RocketMQ:是阿里开源的消息中间件,目前已经捐献个 Apache 基金会,它是由 Java 语言开发的,具备高吞吐量、高可用性、适合大规模分布式系统应用等特点。
- 经历过双11的洗礼,实力不容小觑。
- ZeroMQ:号称史上最快的消息队列,基于 C 语言开发。
- ZeroMQ是一个消息处理队列库,可在多线程、多内核和主机之间弹性伸缩,虽然大多数时候我们习惯将其归入消息队列家族之中,但是其和前面的几款有着本质的区别,ZeroMQ本身就不是一个消息队列服务器,更像是一组底层网络通讯库,对原有的Socket API上加上一层封装而已。
不同MQ的特点对比?
没有最好的消息中间件,只有最合适的消息中间件:
- 性能小、量小,用什么都没有关系,性质是一样的,如果消息性能要求高 用 RocketMQ 与 Kafka 可以更优,二者各有利弊,看业务需要。
- ActiveMQ、RabbitMQ 与 Kafka、RocketMQ 有很大的区别就是前2个只支持主从模式,后2个是分布式消息系统,支持分布式。
Kafka 与 RocketMQ
官方提供了一些不同于kafka的对比差异:
ActiveMQ | Kafka | RocketMQ | |
---|---|---|---|
Client SDK | Java, .NET, C++ etc. | Java, Scala etc. | Java, C++, Go |
协议和规范 | 推送模型,支持OpenWire、STOMP、AMQP、MQTT、JMS | 拉模型,TCP协议支持 | 拉模型,支持TCP、JMS、OpenMessage |
消息有序 | 独占消费者或独占队列可以确保有序 | 确保分区内消息的顺序 | 确保消息严格有序,并可以正常扩展 |
定时消息 | 支持 | 不支持 | 支持 |
批量消息 | 不支持 | 支持,具有异步生产者(producer) | 支持,具有同步模式,可避免消息丢失 |
广播信息 | 支持 | 不支持 | 支持 |
消息过滤器 | 支持 | 支持,您可以使用Kafka流(Streams)来过滤消息 | 支持,基于SQL92的属性过滤器表达式 |
服务器触发的重新交付 | 不支持 | 不支持 | 支持 |
消息存储 | 使用 JDBC 以及高性能日志(例如levelDB,kahaDB),支持非常快速的持久性 | 高性能的文件存储 | 高性能和低延迟的文件存储 |
消息追溯 | 支持 | 支持偏移追溯 | 支持的时间戳和偏移量追溯 |
消息优先级 | 支持 | 不支持 | 不支持 |
高可用性和故障转移 | 支持,取决于存储,如果使用levelDB,则需要ZooKeeper服务器 | 支持,需要ZooKeeper服务器 | 支持,主从模式,无其他套件 |
消息跟踪 | 不支持 | 不支持 | 支持 |
配置 | 默认配置为低级别,用户需要优化配置参数 | Kafka使用键值对(key-value)格式进行配置。这些值可以通过文件或编程方式提供。 | 开箱即用,用户只需注意几个配置 |
管理和操作工具 | 支持 | 支持,使用终端命令显示核心指标 | 支持丰富的web和终端命令以显示核心指标 |
RocketMQ 具有以下特点:
- 能够保证严格的消息顺序
- 提供针对消息的过滤功能
- 提供丰富的消息拉取模式
- 高效的订阅者水平扩展能力
- 实时的消息订阅机制
- 亿级消息堆积能力
缺点:
- 社区活跃度一般
- 没有在 mq 核心中去实现JMS等接口,有些系统要迁移需要修改大量代码
Kafka 具有以下特点:
- 快速持久化:通过磁盘顺序读写与零拷贝机制,可以在O(1)的系统开销下进行消息持久化;
- 高吞吐:在一台普通的服务器上既可以达到10W/s的吞吐速率;
- 高堆积:支持topic下消费者较长时间离线,消息堆积量大;
- 完全的分布式系统:Broker、Producer、Consumer都原生自动支持分布式,依赖zookeeper自动实现复杂均衡;
- 支持Hadoop数据并行加载:对于像Hadoop的一样的日志数据和离线分析系统,但又要求实时处理的限制,这是一个可行的解决方案。
缺点:
- Kafka单机超过64个队列/分区,Load会发生明显的飙高现象,队列越多,load越高,发送消息响应时间变长
- 使用短轮询方式,实时性取决于轮询间隔时间;
- 消费失败不支持重试;
- 支持消息顺序,但是一台代理宕机后,就会产生消息乱序;