在这种情况下,在订阅者 未连接时,发布的消息将在订阅者 重新连接 时 重新发布,如下图所示:
特性:
每个消息可以有多个订阅者;客户端只有订阅后才能接收到消息;持久订阅和非持久订阅。注意:
发布者和订阅者有时间依赖:接受者和发布者只有建立订阅关系才能收到消息;持久订阅:订阅关系建立后,消息就不会消失,不管订阅者是否都在线;非持久订阅:订阅者为了接受消息,必须一直在线。 当只有一个订阅者时约等于点对点模式5. 消息队列应用场景
当你需要使用 消息队列 时,首先需要考虑它的必要性。可以使用消息队列的场景有很多,最常用的几种,是做
5.1. 异步处理
非核心 流程 异步化,减少系统 响应时间,提高 吞吐量。例如:短信通知、终端状态推送、App 推送、用户注册 等。
消息队列 一般都内置了
应用案例
网站用户注册,注册成功后会过一会发送邮件确认或者短息。
5.2. 系统解耦
系统之间不是 强耦合的,消息接受者 可以随意增加,而不需要修改 消息发送者的代码。消息发送者 的成功不依赖 消息接受者(比如:有些银行接口不稳定,但调用方并不需要依赖这些接口)。不强依赖 于非本系统的核心流程,对于 非核心流程,可以放到消息队列中让 消息消费者5.3. 最终一致性
最终一致性 不是 消息队列 的必备特性,但确实可以依靠 消息队列 来做 最终一致性 的事情。
先写消息再操作,确保操作完成后再修改消息状态。定时任务补偿机制 实现消息 可靠发送接收、业务操作的可靠执行,要注意 消息重复 与 幂等设计。所有不保证 100% 不丢消息 的消息队列,理论上无法实现 最终一致性。像 Kafka 一类的设计,在设计层面上就有 丢消息 的可能(比如 定时刷盘
5.4. 广播
生产者/消费者 模式,只需要关心消息是否 送达队列,至于谁希望订阅和需要消费,是 下游 的事情,无疑极大地减少了开发和联调的工作量。
5.5. 流量削峰和流控
当 上下游系统 处理能力存在差距的时候,利用 消息队列 做一个通用的 “漏斗”,进行 限流控制。在下游有能力处理的时候,再进行分发。
举个例子:用户在支付系统成功结账后,订单系统会通过短信系统向用户推送扣费通知。 短信系统 可能由于 短板效应,速度卡在 网关 上(每秒几百次请求),跟 前端的并发量 不是一个数量级。 于是,就造成 支付系统 和 短信系统 的处理能力出现差异化。
然而用户晚上个半分钟左右收到短信,一般是不会有太大问题的。如果没有消息队列,两个系统之间通过
所以,利用中间系统转储两个系统的通信内容,并在下游系统有能力处理这些消息的时候,再处理这些消息,是一套相对较通用的方式。
应用案例
把消息队列当成可靠的 消息暂存地,进行一定程度的 消息堆积;定时进行消息投递,比如模拟 用户秒杀5.6. 日志处理
将消息队列用在 日志处理 中,比如 Kafka 的应用,解决 海量日志 传输和缓冲的问题。
应用案例
把日志进行集中收集,用于计算 PV、
5.7. 消息通讯
消息队列一般都内置了 高效的通信机制,因此也可以用于单纯的 消息通讯,比如实现 点对点消息队列 或者 聊天室 等。
6. 消息队列的推拉模型
6.1. Push推消息模型
消息生产者 将消息发送给 消息队列,消息队列 又将消息推给 消息消费者。
6.2. Pull拉消息模型
消费者 请求 消息队列 接受消息,消息生产者 从 消息队列 中拉该消息。
6.3. 两种类型的区别
7. 消息队列技术对比
本部分主要介绍四种常用的消息队列(ActiveMQ / RabbitMQ / RocketMQ / Kafka)的主要特性、优点、缺点。
7.1. ActiveMQ
ActiveMQ 是由 Apache 出品,ActiveMQ 是一个完全支持JMS1.1 和 J2EE 1.4 规范的 JMS Provider 实现。它非常快速,支持 多种语言的客户端 和 协议,而且可以非常容易的嵌入到企业的应用环境中,并有许多高级功能。
(a) 主要特性
服从JMS规范:JMS 规范提供了良好的标准和保证,包括:同步 或 异步 的消息分发,一次和仅一次的消息分发,消息接收 和 订阅 等等。遵从 JMS 规范的好处在于,不论使用什么 JMS 实现提供者,这些基础特性都是可用的;连接灵活性:ActiveMQ 提供了广泛的 连接协议,支持的协议有:HTTP/S,IP 多播,SSL,TCP,UDP 等等。对众多协议的支持让 ActiveMQ 拥有了很好的灵活性;支持的协议种类多:OpenWire、STOMP、REST、XMPP、AMQP;持久化插件和安全插件:ActiveMQ 提供了 多种持久化 选择。而且,ActiveMQ 的安全性也可以完全依据用户需求进行 自定义鉴权 和 授权(b) 部署环境
ActiveMQ 可以运行在 Java 语言所支持的平台之上。使用 ActiveMQ 需要:
Java JDKActiveMQ 安装包(c) 优点
跨平台 (JAVA 编写与平台无关,ActiveMQ 几乎可以运行在任何的 JVM 上);可以用 JDBC:可以将 数据持久化 到数据库。虽然使用 JDBC 会降低 ActiveMQ 的性能,但是数据库一直都是开发人员最熟悉的存储介质;支持 JMS 规范:支持 JMS 规范提供的(d) 缺点
社区活跃度不及 RabbitMQ 高;根据其他用户反馈,会出莫名其妙的问题,会 丢失消息;目前重心放到 activemq 6.0 产品 Apollo,对 5.x 的维护较少;不适合用于 上千个队列 的应用场景;7.2. RabbitMQ
RabbitMQ 于 2007 年发布,是一个在 AMQP (高级消息队列协议)基础上完成的,可复用的企业消息系统,是当前最主流的消息中间件之一。
(a) 主要特性
可靠性:提供了多种技术可以让你在 性能 和 可靠性 之间进行 权衡。这些技术包括 持久性机制、投递确认、发布者证实 和 高可用性机制;灵活的路由:消息在到达队列前是通过 交换机 进行 路由 的。RabbitMQ 为典型的路由逻辑提供了 多种内置交换机 类型。如果你有更复杂的路由需求,可以将这些交换机组合起来使用,你甚至可以实现自己的交换机类型,并且当做 RabbitMQ 的 插件 来使用;消息集群:在相同局域网中的多个 RabbitMQ 服务器可以(b) 部署环境
RabbitMQ 可以运行在 Erlang 语言所支持的平台之上,包括 Solaris,BSD,Linux,MacOSX,TRU64,Windows 等。使用 RabbitMQ 需要:
ErLang 语言包RabbitMQ 安装包(c) 优点
由于 Erlang 语言的特性,消息队列性能较好,支持 高并发;健壮、稳定、易用、跨平台、支持 多种语言、文档齐全;有消息 确认机制 和 持久化机制,可靠性高;高度可定制的 路由;管理界面 较丰富,在互联网公司也有较大规模的应用,社区活跃度高。(d) 缺点
尽管结合 Erlang 语言本身的并发优势,性能较好,但是不利于做 二次开发和维护;实现了 代理架构,意味着消息在发送到客户端之前可以在7.3. RocketMQ
RocketMQ 出自 阿里 的开源产品,用 Java 语言实现,在设计时参考了 Kafka,并做出了自己的一些改进,消息可靠性上 比 Kafka 更好。RocketMQ 在阿里内部被广泛应用在 订单,交易,充值,流计算,消息推送,日志流式处理,binglog 分发 等场景。
(a) 主要特性
(b) 部署环境
RocketMQ 可以运行在 Java 语言所支持的平台之上。使用 RocketMQ 需要:
Java JDK安装 git、MavenRocketMQ 安装包(c) 优点
单机 支持 1 万以上 持久化队列;RocketMQ 的所有消息都是(d) 缺点
支持的 客户端语言 不多,目前是 Java 及 C++,其中 C++ 还不成熟;RocketMQ 社区关注度及成熟度也不及前两者;没有 Web 管理界面,提供了一个 CLI (命令行界面) 管理工具带来7.4. Kafka
Apache Kafka 是一个 分布式消息发布订阅 系统。它最初由 LinkedIn 公司基于独特的设计实现为一个 分布式的日志提交系统 (a distributed commit log),之后成为 Apache 项目的一部分。Kafka 性能高效、可扩展良好 并且 可持久化。它的 分区特性,可复制 和 可容错 都是其不错的特性。
(a) 主要特性
快速持久化:可以在 O(1) 的系统开销下进行 消息持久化;高吞吐:在一台普通的服务器上既可以达到 10W/s 的 吞吐速率;完全的分布式系统:Broker、Producer 和 Consumer 都原生自动支持 分布式,自动实现 负载均衡;支持 同步 和 异步 复制两种 高可用机制;支持 数据批量发送 和 拉取;零拷贝技术(zero-copy):减少 IO 操作步骤,提高 系统吞吐量;数据迁移、扩容(b) 部署环境
使用 Kafka 需要:
Java JDKKafka 安装包(c) 优点
客户端语言丰富:支持 Java、.Net、PHP、Ruby、Python、Go 等多种语言;高性能:单机写入 TPS 约在 100 万条/秒,消息大小 10 个字节;提供 完全分布式架构,并有 replica 机制,拥有较高的 可用性 和 可靠性,理论上支持 消息无限堆积;支持批量操作;消费者 采用 Pull 方式获取消息。(d) 缺点
Kafka 单机超过 64 个 队列/分区 时,Load 时会发生明显的飙高现象。队列 越多,负载 越高,发送消息 响应时间变长;使用 短轮询方式,实时性 取决于 轮询间隔时间;消费失败 不支持重试;支持 消息顺序,但是 一台代理宕机 后,就会产生 消息乱序;社区更新较慢。7.5. 几种消息队列对比
这里列举了上述四种消息队列的差异对比:
Kafka 在于 分布式架构,RabbitMQ 基于 AMQP 协议 来实现,RocketMQ 的思路来源于 Kafka,改成了 主从结构,在 事务性 和 可靠性 方面做了优化。广泛来说,
小结
本文介绍了消息队列的特点,消息队列的 传递服务模型,消息的 传输方式,消息的 推拉模式。然后介绍了 ActiveMQ,RabbitMQ,RocketMQ 和 Kafka 几种常见的消息队列,阐述了 各种消息队列 的 主要特点 和 优缺点。通过本文,对于消息队列及相关技术选型,相信你会有了更深入的理解和认识。更多细节和原理性的东西,还需在实践中见真知!