为什么在美团的二面中需要消息队列以及如何进行合理的消息队列选型:深入分析Kafka、RabbitMQ、RocketMQ和ActiveMQ的特点与应用场景
文章目录
消息队列基础
什么是消息队列?
消息队列是一个在消息传输过程中暂存消息的容器,主要用于接收和存储消息。一个消息队列可以有一个或多个消费者进行消费,其构成主要包括三个元素:
- Producer(生产者):负责生产并发送消息到消息中间件。
- Broker(消息处理中心):负责存储消息、确认接收和重试机制,通常包含多个消息队列。
- Consumer(消费者):从Broker中获取消息并进行相应处理。
消息队列模式
- 点对点模式:在这种模式下,多个生产者可以向同一消息队列发送消息,但每条消息只能被一个消费者消费。
- 发布/订阅模式:在这一模式下,单个消息可以被多个订阅者并行获取和处理。
消息队列应用场景
- 应用解耦:消息队列降低了服务间的耦合性,为不同服务之间提供了沟通的桥梁,而无需关注彼此的实现细节。
- 异步处理:消息队列的特性使得接收者可以在消息发送后很长时间才取回消息。
- 流量平滑:在上下游系统处理能力差异时,消息队列充当通用载体,将消息平滑分发到下游处理。
- 日志处理:消息队列在日志处理中的应用,诸如Kafka,可以帮助解决大量日志传输的问题。
- 消息通讯:具备高效通信机制的消息队列可用于实现点对点的消息传递或聊天室等应用。
- 消息广播:使用消息队列后,新业务方接入时只需关注消息是否送达队列,极大地减少了开发和调试的工作量。
常用消息队列
由于ActiveMQ 5.x的维护逐渐减少,因此本文主要探讨Kafka、RabbitMQ和RocketMQ。
Kafka
Apache Kafka最初由LinkedIn公司设计,后来成为Apache项目的一部分。其被誉为大数据的核心工具,在数据采集、传输和存储中发挥着重要作用。Kafka是一个分布式、支持多分区和多副本的消息流平台,基于Zookeeper进行管理。
重要概念
- 主题(Topic):代表消息类别,相当于对消息的分类。
- 分区(Partition):每个主题可分为多个分区,分区可部署在不同机器上以实现扩展性。
- 批次:指一组消息,为了提高效率,消息会批量写入Kafka。
- 消费者组(Consumer Group):由一个或多个消费者组成的群体。
- Broker:接收生产者消息并将其存储的Kafka服务器。
- Broker集群:由一个或多个Broker组成的集群。
Kafka架构
一个典型的Kafka集群包括Producer、Broker、Consumer Group以及Zookeeper。Zookeeper负责集群配置管理,选举Leader,以及在Consumer Group变动时进行重新平衡,Producer通过推送模式将消息发送到Broker,而Consumer则使用拉取模式从Broker获取消息。
Kafka工作原理
经过序列化的消息会通过分区策略找到对应的分区。相同主题和分区的消息存放于同一批次,由独立线程发送到Kafka Broker。
分区策略包括顺序轮询、随机轮询和Key Hash等。分区是Kafka数据读写的最小粒度。通过分区,Kafka能够实现水平扩展。
Kafka的消费是通过消费组完成的,一个消费者组中的消费者可以消费多个分区,但每个分区只能被一个消费者消费。
当消费者增加时,会触发重新平衡过程。
不同的消费者组互不干扰,例如下图中两个消费组可以独立消费这四个分区的消息。
RocketMQ
RocketMQ是阿里巴巴开源的消息中间件,纯Java开发,具备高性能、高可靠性和高实时性,适用于大规模分布式系统。它虽然源于Kafka,但并非简单复制,而是在可靠传输和事务性方面进行了优化。
重要概念
- Name服务器(NameServer):类似Kafka中的Zookeeper,充当注册中心。
- Broker:独立的RocketMQ服务器,负责接收生产者消息。
- 主题(Topic):每条消息必须有主题。
- 子主题(Tag):为同一业务模块不同目的的消息提供标识。
- 分组(Group):可以订阅多个Topic的组,包括生产者组和消费者组。
- 队列(Queue):类似于Kafka的分区。
RocketMQ工作原理
RocketMQ中的消息模型基于主题模型实现,包括Producer Group、Topic、Consumer Group三个角色。
为了提高并发能力,一个Topic包含多个Queue,生产者组根据主题将消息放入相应的Topic。
RocketMQ的消费群组和Queue与Kafka中的消费群组和Partition相似:不同消费者组不互相干扰。
消费Queue时,通过偏移量记录消费进度。
RocketMQ架构
RocketMQ架构包含四种角色:NameServer、Broker、Producer和Consumer。Broker用于存放Queue,一个Broker可以配置多个Topic,每个Topic可以包含多个Queue。
为了处理大量消息,应该为某个Topic配置多个Queue,并将其分散在不同的Broker上,以减轻单个Broker的压力。
Broker通过集群部署,并提供主从结构,Slave定期从Master同步数据。
RabbitMQ
RabbitMQ是2007年发布的开源消息队列系统,使用Erlang开发,基于AMQP协议。AMQP的特点是面向消息、队列、路由、可靠性和安全性,适用于对数据一致性、稳定性和可靠性要求较高的场景。
重要概念
- 信道(Channel):消息读写等操作通过信道进行,客户端可以建立多个信道。
- 交换器(Exchange):接收消息并根据路由规则将消息发送到一个或多个队列。
- 路由键(RoutingKey):用于指定消息的路由规则,指导交换器发送到哪个队列。
- 绑定(Binding):交换器与消息队列之间的虚拟连接,包含一个或多个RoutingKey。
RabbitMQ工作原理
AMQP协议模型由生产者、消费者和服务端组成,执行流程如下:
- 生产者连接到Server,建立连接并开启信道。
- 生产者声明交换器和队列,并设置相关属性,通过路由键进行绑定。
- 消费者建立连接并开启信道以接收消息。
- 生产者发送消息至服务端的虚拟主机。
- 虚拟主机中的交换器根据路由键选择路由规则,将消息发送到对应队列。
- 订阅消息队列的消费者获取并消费消息。
常用交换器
RabbitMQ支持的常用交换器类型包括direct、topic、fanout和headers,具体使用方法可参考官网。
官网入口:RabbitMQ 官方文档
消息队列对比
Kafka
优点:
- 高吞吐、低延迟:Kafka的最大特点是消息处理速度快,能够每秒处理数十万条消息,延迟低至几毫秒。
- 高扩展性:每个主题可以分为多个分区,分区可分布在不同主机上。
- 高稳定性:分布式架构支持数据多副本,确保即使某节点宕机,集群仍能正常运作。
- 持久性、可靠性、可回溯性:支持数据持久化存储和数据备份。
- 消息有序:通过控制可以确保消息的消费顺序。
- 强大的第三方管理工具:例如Kafka-Manager,在日志管理方面较为成熟。
缺点:
- 单机超过64个队列/分区时,负载显著上升,消息发送响应时间增加。
- 不支持消息路由、延迟发送和消息重试。
- 更新社区较慢。
RocketMQ
优点:
- 高吞吐量:受益于Kafka的设计,单个队列能处理百万级消息。
- 高扩展性:灵活的分布式横向扩展架构,与Kafka相似。
- 高容错性:通过ACK机制确保消息正常消费。
- 持久化和可回溯:支持消息持久化和回溯。
- 消息有序性:确保同一队列中的消息按先进先出(FIFO)顺序传递。
- 支持发布/订阅和点对点消息模型。
- 提供Docker镜像,便于测试和云集群部署,功能丰富的Dashboard用于监控。
缺点:
- 不支持消息路由,支持的客户端语言有限,主要为Java和不成熟的C++。
- 消息有序性部分支持,需将同类消息哈希到同一队列,以确保顺序。
- 社区活跃度一般。
RabbitMQ
优点:
- 广泛的语言支持:支持Java、C、C++、C#、Ruby、Perl、Python、PHP等多种语言。
- 灵活的消息路由:支持不同类型消息的路由。
- 消息时序:支持延迟队列和过期时间TTL。
- 容错处理:通过交付重试和死信交换器处理消息故障。
- 用户友好的界面:便于监控和管理消息Broker。
- 活跃的社区支持。
缺点:
- Erlang开发,源码难懂,不利于二次开发和维护,需依赖社区维护和修复Bug。
- 吞吐量较低,因实现机制较重。
- 不支持消息有序性,持久化效果不佳,伸缩性一般。
消息队列选型
- Kafka:适合追求高吞吐量的场景,尤其是日志收集和数据传输,建议大型公司使用,如果有日志采集功能,Kafka是首选。
- RocketMQ:特别适用于对可靠性要求高的金融互联网应用,尤其在电商场景中表现出色,如果业务场景涉及高并发,RocketMQ是理想选择。
- RabbitMQ:由于其较好的性能和活跃的社区支持,适合数据量不大且需要快速实现的小型企业,功能完备且易于使用,适合小公司。
- ActiveMQ:目前维护较少,适用于小规模项目,不推荐在大规模场景中使用。