消息队列概述
消息中间件是大型分布式应用中重要的组成部分,它可以实现关联系统在业务和部署上的解耦,各方无需相互等待,只需根据自身能力投递或消费。本文总结了JMS各元素、两种消息模型、主流的消息中间件 (Kafka/ActiveMQ/RabbitMQ/RocketMQ)各自的特点。
作者:王克锋
出处:https://kefeng.wang/2017/10/12/message-queue/
版权:自由转载-非商用-非衍生-保持署名,转载请标明作者和出处。
1.概述
https://zh.wikipedia.org/zh-cn/Java消息服务
1.1 概念
分布式系统中发送和接受消息的硬件或软件基础设施(通常是指软件),分布式消息中间件自身也是一个分布式系统。
不同于 RMI/RPC 等通信机制,消息队列(Message Queue)是应用间异步通信的机制。
流程: 消息生产者(producer) ==(异步)==> 消息队列(message queue, broker) ==> 消息消费者(consumer)
其中的 producer/consumer 都可以有多个,他们都不受限于特定平台。
消息的类型:
- 简单文本(TextMessage)、字节流(ByteMessage)、键值对(MapMessage)
- 流(StreamMessage)、可序列化的对象(ObjectMessage)、原始(Message)
1.2 JMS规范
Java消息服务(Java Message Service, JMS)是一个在 Java标准化组织(JCP)内开发的标准(代号JSR 914)。
2001年6月25日,发布 JMS 1.0.2b,
2002年3月18日,发布 JMS 1.1,统一了消息域。
JDBC 是 Java 数据库的统一接口规范;
类似地,JMS()是 Java 异步消息应该接口规范,它包括消息的创建、发送、接收与读取等,各消息组件厂商必须遵从该规范。
JMS元素包括:
- JMS提供者: 连接面向消息中间件的,JMS接口的一个实现。提供者可以是Java平台的JMS实现,也可以是非Java平台的面向消息中间件的适配器。
- JMS客户: 生产或消费消息的基于Java的应用程序或对象。
- JMS生产者: 创建并发送消息的JMS客户。
- JMS消费者: 接收消息的JMS客户。
- JMS消息: 包括可以在JMS客户之间传递的数据的对象
- JMS队列: 一个容纳那些被发送的等待阅读的消息的区域。队列暗示,这些消息将按照顺序发送。一旦一个消息被阅读,该消息将被从队列中移走。
- JMS主题: 一种支持发送消息给多个订阅者的机制。
1.2.1 点对点模型(P2P, 消息不分类)
- 发送时: producer 发送 {message} 给 broker,broker 把 message 放到队列中
- 接收时: 一旦有 consumer 接收消息,consumer 从队列中移出最早的 message,转交给该 consumer;其他 consumer 就不会收到同一个 message。
1.2.2 发布订阅模型(消息按主题分类)
- 接收者: 向 broker 订阅某些 topic;
- 发送时: producer 发送 message 给 broker 的某个 topic,broker 把 message 放到相应 topic 的队列中;
- 接收时: broker 把该 message 群发给订阅了该 topic 的所有在线的 consumer;已订阅该 topic 但已下线的 consumer,再次上线也不会收到该 message,除非该 consumer 开启了“持久订阅(Durable Subscription)”;后来才首次订阅该 topic 的 consumer,也不会收到该 message。
1.3 消息的优点
- 无需等待: producer 无需等待消息被投递,更无需等待消息被 consumer 接收和处理;
- 业务解耦: 以消息为中心,与外围系统在衔接接口上解耦;
- 位置独立: 以消息为中心,与外围系统在网络拓扑上解耦,可以很方便地增加 producer/consumer;
- 确保投递: 确保每个消息都会投递给 consumer,即使 consumer 暂时宕机,在恢复之后仍能收到遗漏的消息。
- 削峰填谷: 当 consumer 来不及处理时,缓存在消息系统中,待 consumer 高峰期过后再继续处理。
1.4 开源中间件
性能: Kafka > RocketMQ > RabbitMQ
架构: ActiveMQ / RabbitMQ 只支持主从模式,Kafka / RocketMQ 支持分布式;
持久化: ZeroMQ 不支持,ActiveMQ / RabbitMQ 都支持。
可靠性: RabbitMQ > ActiveMQ
1.4.1 Apache ActiveMQ
最新版本 5.15.2(2017-10-23)
可以部署于代理模式和P2P模式。
被誉为消息中间件的“瑞士军刀”。
1.4.2 Apache Kafka
由 LinkedIn 开发贡献给 Apache,主要特性:
- 不完全符合 JMS 规范,注重吞吐量(基于 Pull 的模式来处理消息消费),类似 TCP/UDP;
- 支持复制,不支持事务
- 对消息的重复、丢失、错误没有严格要求
- kafka 对数据不是百分之百保证的,会有数据丢失;而amq和rmq等通过设置有查询是否送达、可重发;
- 在吞吐量有提升 ,在这方面就得有牺牲, 所以kafka适合大数据量流转, 比如日志数据 比如用作统计的数据。
Kafka Broker 使用 Zookeeper 在群集中可靠地维护自己的状态。
1.4.3 Apache RocketMQ
由 Alibaba 开源并贡献给 Apache,纯Java开发。
- 思路源于 Kafka,具有高吞吐量、高可用性;
- 它对消息的可靠传输及事务性做了优化。
- 能够保证严格的消息顺序
- 提供丰富的消息拉取模式
- 高效的订阅者水平扩展能力
- 实时的消息订阅机制
- 亿级消息堆积能力
1.4.4 Pivotal RabbitMQ
Rabbit 公司采用 erlang 语言、基于 AMQP 协议开发。
Rabbit 公司 2010年4月被 VMware 旗下的 SpringSource 收购。
RabbitMQ 在 2013年5月成为 GoPivotal 的一部分。
主要特性:
- 面向消息、队列、路由(包括点对点和发布/订阅)、可靠性、安全。
- 对数据一致性、稳定性和可靠性要求很高的场景,对性能和吞吐量的要求还在其次。
- 可群集服务、消息持久化(内存持久化到硬盘,再从硬盘加载到内存)
4.消息集群(主从架构)
4.1 架构
全局排他锁可以存储于共享文件系统,或者共享数据库中;
各节点启动时,竞相获取排他锁,首先获得者为 Master,其他为 Slave(不对外提供服务,并尝试获取排他锁);
当 Master 宕机或连接中断时,排他锁被释放,并被某个 Slave 抢得而成为 Master 并对外提供服务;
而先前的 Master 再次恢复后,也只能作为 Slave 等待争夺排他锁。
客户端连接集群时,要同时指定所有节点。
4.2 扩展
- 垂直扩展: 提升硬件性能(CPU、内存等),改进 broker 节点的配置(NIO、JVM等);
- 水平扩展: 增加 broker,拆分存储不同的消息、主题。