什么是MQ?
MQ(message queue),从字面意思上看,本质是个队列,FIFO先入先出,是一种通信方式,允许分布式系统中的不同组件通过消息传递进行通信。消息队列系统提供了一个缓冲区,通过该缓冲区可以存储和传递消息,确保消息在组件之间的可靠传递和处理。在互联网架构中,MQ是一种非常常见的上下游“逻辑解耦+物理解耦”的消息通信服务。使用了MQ之后,消息发送上游只需要依赖MQ,不用依赖其他服务。
MQ有什么好处?
异步通信
-
- 消息发送者和接收者不需要同时处于活跃状态。发送者可以将消息放入队列中,而接收者可以在方便的时候读取和处理消息。
有些服务间调用并不需要知道服务调用结果,是异步的,例如A执行完需要调用B,让B进行状态修改,B需要花费很长时间执行,但是A不需要知道B什么时候可以执行完也不需要B的执行结果,分布式系统中经常会使用A在执行完之后调用B的API方法,这种方式会阻塞A的执行,不是很优雅,A会等待B的调用结果,使用消息队列,可以很方便解决这个问题,A执行完业务之后,将消息发送到消息队列,B只需要拉取消息完成业务即可,并不会阻塞A的执行。这样A服务既不用循环调用B的查询api,也不用提供callback api。同样B服务也不用做这些操作。A服务还能及时的得到异步处理成功的消息。
同步调用优势:时效性强,等待到结果后才返回
同步调用问题:拓展性差,性能下降
异步调用优势:耦合度低,拓展性强;异步调用,无需等待,性能好;故障隔离,下游服务故障不影响上游业务;缓存消息,流量削峰填谷。
异步调用问题:不能立即得到调用结果,时效性差;不确定下游业务执行是否成功;业务安全依赖于broker 的可靠性。
解耦
-
- 生产者和消费者之间解耦,生产者只需知道消息队列的地址,而不需要知道消费者的具体信息。这使得系统的各个组件可以独立地演化和扩展。
以电商应用为例,应用中有订单系统、库存系统、支付系统。用户创建订单后,如果耦合调用库存系统、物流系统、支付系统,任何一个子系统出了故障,都会造成下单操作异常。当转变成基于消息队列的方式后,系统间调用的问题会减少很多,比如物流系统因为发生故障,需要几分钟来修复。在这几分钟的时间里,物流系统要处理的内存被缓存在消息队列中,用户的下单操作可以正常完成。当物流系统恢复后,继续处理订单信息即可 ,下单用户感受不到物流系统的故障,提升系统的可用性。
负载均衡
-
- 多个消费者可以从同一个队列中消费消息,实现负载均衡。消息队列系统会自动将消息分配给多个消费者,从而提高系统的处理能力。
-
持久化
-
- 消息可以持久化存储在磁盘中,确保在系统崩溃或网络故障时消息不会丢失。
-
顺序保证
-
- 可以保证消息在某些场景下按顺序处理,确保系统处理流程的正确性。
MQ分类
rabbit MQ:
优点:
- 支持多种消息传递模式
-
- RabbitMQ 支持点对点(queue-based)、发布/订阅(pub/sub)、工作队列(work queues)、路由(routing)和主题(topic)等多种消息传递模式,适用于不同的应用场景。
- 可靠性
-
- RabbitMQ 提供消息确认机制,确保消息在消费者成功处理后才从队列中删除。它还支持持久化消息和队列,保证在服务器重启后消息不会丢失。
- 灵活的路由功能
-
- RabbitMQ 使用交换机(exchange)和绑定(binding)机制,提供灵活的消息路由功能。通过不同类型的交换机(如 direct、topic、fanout 和 headers),可以实现复杂的路由逻辑。
- 可扩展性
-
- RabbitMQ 支持集群配置,通过将多个 RabbitMQ 节点组成集群,可以实现负载均衡和高可用性。同时,它还支持联邦模式(federation)和分布式交换(shovel)功能,跨数据中心同步消息。
- 多语言客户端支持
-
- RabbitMQ 提供了丰富的客户端库,支持多种编程语言(如 Java、Python、Ruby、.NET、PHP、Go 等),方便开发者集成到不同的应用中。
- 管理工具
-
- RabbitMQ 提供了强大的管理插件(RabbitMQ Management Plugin),通过 Web 界面可以方便地监控和管理 RabbitMQ 实例、队列、交换机和连接等信息。
- 插件系统
-
- RabbitMQ 拥有灵活的插件系统,支持自定义扩展。开发者可以根据需求编写和安装插件,增加 RabbitMQ 的功能。
缺点:
- 性能瓶颈
-
- 虽然 RabbitMQ 在处理大量小消息时表现良好,但在高吞吐量场景下(如处理每秒数百万条消息),性能可能会受到限制。Kafka 在这种高吞吐量场景下通常表现更好。
- 复杂性
-
- RabbitMQ 的配置和管理相对复杂,特别是在需要实现高可用性和分布式部署时。需要具备一定的专业知识来进行正确配置和优化。
- 内存消耗
-
- RabbitMQ 依赖内存来存储消息队列中的消息。如果消息积压严重,可能会导致内存消耗过高,从而影响系统性能。
- 延迟
-
- 在某些高性能和低延迟要求的场景下,RabbitMQ 的消息传递延迟可能无法满足需求。特别是在需要严格顺序保证的情况下,延迟可能会增加。
- 集群管理
-
- RabbitMQ 集群的管理和维护相对复杂,尤其是在集群节点数较多时。需要仔细规划和配置集群,以避免数据不一致和性能问题。
active MQ:
优点:
- 多协议支持
-
- ActiveMQ 支持多种消息协议,包括 AMQP、STOMP、MQTT、OpenWire 等,使其能够与多种不同的系统和客户端集成。
- 持久化和可靠性
-
- ActiveMQ 支持消息持久化,确保消息在服务器重启或崩溃后不会丢失。它还提供了多种可靠性保障机制,如消息确认、事务支持等。
- 灵活的消息模型
-
- 支持多种消息传递模型,包括点对点(Queue)、发布/订阅(Topic)、请求/响应等,满足不同应用场景的需求。
- 高可用性
-
- ActiveMQ 支持多种集群模式,包括主-备模式(Master-Slave)和共享存储模式,提供高可用性和故障转移能力。
- 易于管理和监控
-
- 提供了 JMX 支持和 Web 控制台,方便管理员监控和管理消息代理的运行状态、队列和主题的情况、连接信息等。
- 丰富的客户端支持
-
- ActiveMQ 提供了丰富的客户端库,支持多种编程语言和平台,如 Java、.NET、C++、Python 等,方便开发者集成。
- 成熟和稳定
-
- 作为一个老牌的消息队列系统,ActiveMQ 已经经过多年的发展和优化,社区活跃,文档齐全,可靠性和稳定性较高。
缺点:
- 性能
-
- ActiveMQ 在处理高吞吐量场景时可能表现不如一些新兴的消息队列系统,如 Kafka。在处理大规模消息传递时,性能可能成为瓶颈。
- 集群配置复杂
-
- 虽然 ActiveMQ 支持多种高可用性和集群模式,但其配置和管理相对复杂,需要一定的专业知识和经验来正确设置和维护。
- 内存消耗
-
- ActiveMQ 依赖内存来存储消息,在消息积压严重时,可能会导致内存消耗过高,从而影响系统性能。
- 顺序保证
-
- 在分布式环境中,保证消息的严格顺序处理可能比较困难,需要额外的配置和处理。
- 延迟
-
- ActiveMQ 在某些场景下的消息传递延迟可能较高,特别是在需要低延迟和高并发的场景中,可能无法完全满足需求。
rocketMQ:
优点:
- 高吞吐量和低延迟
-
- RocketMQ 经过优化,具有高吞吐量和低延迟的特点,能够在大规模分布式系统中高效处理消息。
- 水平扩展
-
- RocketMQ 支持水平扩展,可以通过增加更多的 Broker 节点来提升系统的处理能力,适应业务增长。
- 丰富的消息传递模型
-
- 支持点对点(Queue)和发布/订阅(Topic)模型,以及顺序消息、延迟消息、事务消息等多种消息传递方式,满足不同场景的需求。
- 高可用性
-
- RocketMQ 支持主从架构,通过主从复制实现高可用性。主节点故障时,从节点可以迅速接管,保证系统的连续性。
- 强一致性保证
-
- RocketMQ 提供了强一致性的消息投递,确保消息不会丢失或重复处理,适用于金融级别的可靠性要求。
- 灵活的消息路由
-
- 支持灵活的消息路由机制,可以通过 Tag 和 Key 实现精确的消息过滤和路由。
- 监控和管理
-
- 提供了丰富的监控和管理工具,可以通过控制台方便地查看消息堆积、消费延迟等指标,便于运维人员进行系统监控和故障排查。
- 事务消息
-
- 支持事务消息,能够保证在分布式事务场景下消息的一致性,适用于金融、支付等对事务一致性要求较高的业务场景。
缺点:
- 学习曲线
-
- 相对于一些老牌的消息队列系统,如 ActiveMQ 和 RabbitMQ,RocketMQ 的概念和配置可能对新手来说较为复杂,需要一定的学习和实践才能掌握。
- 社区和文档
-
- 虽然 RocketMQ 的社区和文档在不断完善,但相对于 Kafka 等更为成熟的开源项目,仍存在一定差距,特别是在一些高级特性和优化方面的资料可能较少。
- 生态系统
-
- 虽然 RocketMQ 提供了多语言客户端,但在一些边缘生态系统和工具的支持上,可能不如 Kafka 这样广泛应用的消息队列系统。
- 集群管理
-
- RocketMQ 的集群管理和运维需要一定的专业知识,特别是在大规模部署和高可用配置方面,可能需要更多的经验和技巧。
Kafka:
优点:
- 高吞吐量
-
- Kafka 设计用于高吞吐量的日志和事件数据流处理,可以每秒处理数百万条消息。它的性能得益于其顺序写入磁盘和高效的 IO 操作。
- 低延迟
-
- Kafka 能够在毫秒级别内处理消息,从而保证了低延迟的数据传输,这对于需要实时数据处理的应用场景非常关键。
- 水平扩展
-
- Kafka 支持通过增加更多的 Broker 节点来扩展系统的容量和处理能力。它的分区机制允许消息在多个 Broker 之间分布,实现高可用性和负载均衡。
- 高可靠性
-
- Kafka 提供了数据复制机制,确保数据在多个 Broker 节点之间冗余存储,保证了在节点故障时数据不丢失。
- 消息持久化
-
- Kafka 中的消息可以持久化存储在磁盘上,且持久化机制高效且可靠,支持消息的顺序读取和恢复。
- 灵活的消息消费模式
-
- Kafka 通过消费者组实现了灵活的消息消费模式,支持点对点和发布/订阅两种模式。消费者组内的消费者可以并行处理消息,实现负载均衡。
- 流处理能力
-
- Kafka 提供了 Kafka Streams 和 KSQL 等流处理工具,支持实时的数据流处理和复杂事件处理,满足了从消息传递到实时数据处理的需求。
- 强大的社区和生态系统
-
- 作为一个成熟的开源项目,Kafka 拥有一个活跃的社区和丰富的生态系统,提供了丰富的文档、工具和扩展支持。
缺点:
- 学习曲线陡峭
-
- Kafka 的概念和配置相对复杂,新手需要花费时间学习其架构、配置和最佳实践,才能充分利用 Kafka 的优势。
- 管理复杂
-
- Kafka 的管理和运维较为复杂,尤其是在集群的部署、监控、故障排查和优化方面,需要具备一定的专业知识和经验。
- 消息顺序
-
- Kafka 在分区级别保证消息的顺序性,但在跨分区的情况下无法保证全局顺序。如果应用需要严格的全局顺序处理,可能需要额外的设计和处理。
- 资源消耗
-
- Kafka 对硬件资源的消耗较高,特别是对磁盘 IO 和网络带宽有较高要求。需要为 Kafka 部署提供足够的硬件资源,以保证其高性能运行。
- 事务支持有限
-
- 虽然 Kafka 支持幂等生产者和事务性消息,但其事务支持相对有限,可能不适用于所有需要强事务性的应用场景。
场景选择:
RabbitMQ
适用场景:
- 企业应用集成:
-
- RabbitMQ 支持 AMQP 协议,适合需要与其他系统进行标准化集成的企业应用。
- 复杂的路由需求:
-
- RabbitMQ 提供灵活的路由功能,通过交换机和绑定可以实现复杂的消息路由逻辑。
- 需要可靠的消息传递:
-
- RabbitMQ 支持消息确认、持久化和事务,适用于需要高可靠性的应用,如订单处理、金融交易等。
- 轻量级任务队列:
-
- 适合用于处理轻量级的任务队列和工作队列。
为什么选择 RabbitMQ:
- 协议支持:支持 AMQP、STOMP、MQTT 等多种协议,适用于需要标准化协议的场景。
- 灵活性:强大的路由功能和插件系统,支持复杂的消息传递需求。
- 易用性:丰富的客户端库和管理工具,易于集成和使用。
ActiveMQ
适用场景:
- 企业级消息传递:
-
- ActiveMQ 支持多种协议(如 AMQP、STOMP、OpenWire 等),适合企业级应用集成和消息传递。
- 需要 JMS 兼容性:
-
- ActiveMQ 完全兼容 Java 消息服务(JMS),适用于使用 JMS API 的 Java 企业应用。
- 异构系统集成:
-
- 支持多种协议和客户端,适合需要集成异构系统的场景。
为什么选择 ActiveMQ:
- 协议和标准支持:支持多种消息协议,尤其是 JMS 兼容性,使其在 Java 企业应用中广泛使用。
- 成熟稳定:长期发展和成熟的社区支持,稳定可靠。
- 丰富的特性:提供持久化、事务、消息优先级等高级特性。
RocketMQ
适用场景:
- 高吞吐量和低延迟要求:
-
- RocketMQ 经过优化,适合处理高吞吐量和低延迟的消息传递,如实时数据处理、日志收集等。
- 分布式事务:
-
- RocketMQ 支持分布式事务消息,适用于需要分布式事务保证的金融、电商等业务场景。
- 大数据和流处理:
-
- 适合用于大数据处理和流处理场景,如实时分析、监控等。
为什么选择 RocketMQ:
- 性能优越:高吞吐量、低延迟,适用于高性能需求的场景。
- 事务支持:分布式事务消息支持,适用于需要强一致性保证的场景。
- 可扩展性:支持水平扩展,能够处理大规模分布式系统的消息需求。
Kafka
适用场景:
- 大数据和实时数据流处理:
-
- Kafka 设计用于高吞吐量和低延迟的数据流处理,适用于实时数据处理和分析场景。
- 日志和事件收集:
-
- Kafka 广泛用于日志收集和事件流处理,如网站活动跟踪、系统日志收集等。
- 消息持久化和回溯:
-
- Kafka 支持消息持久化和消费回溯,适用于需要持久化和历史数据处理的场景。
为什么选择 Kafka:
- 高吞吐量和低延迟:适用于大规模数据流处理和实时分析场景。
- 可扩展性:支持水平扩展,能够处理大规模数据流。
- 丰富的生态系统:提供 Kafka Streams、KSQL 等流处理工具,支持复杂的数据处理需求。
总结
选择 RabbitMQ:当需要灵活的路由、高可靠性和多协议支持时,特别是在企业应用集成和轻量级任务队列场景下。
选择 ActiveMQ:当需要 JMS 兼容性、多协议支持和企业级消息传递时,特别是在异构系统集成和传统企业应用中。
选择 RocketMQ:当需要高吞吐量、低延迟和分布式事务支持时,特别是在金融、电商和实时数据处理场景中。
选择 Kafka:当需要高吞吐量、低延迟、可扩展性和持久化消息支持时,特别是在大数据、实时数据流处理和日志收集场景中。
持久化区别:
RabbitMQ
持久化机制:
- 队列持久化:可以声明持久化队列(durable queue),确保队列在服务器重启后依然存在。
- 消息持久化:可以将消息标记为持久化(persistent),确保消息在服务器重启后不会丢失。
- 持久化存储:消息和队列元数据会写入磁盘,但这会增加写操作的延迟。
使用示例:
channel.queueDeclare("myQueue", true, false, false, null); // 创建持久化队列
channel.basicPublish("", "myQueue", MessageProperties.PERSISTENT_TEXT_PLAIN, "Hello World".getBytes()); // 发送持久化消息
ActiveMQ
持久化机制:
- 队列和主题持久化:ActiveMQ 支持持久化队列和主题,消息会存储到磁盘中。
- KahaDB:默认的持久化存储机制,优化了磁盘 IO 操作。
- JDBC 存储:支持将消息存储到关系数据库中。
- 持久化策略:可以通过配置文件设置不同的持久化策略。
使用示例:
ConnectionFactory factory = new ActiveMQConnectionFactory("tcp://localhost:61616");
Connection connection = factory.createConnection();
connection.start();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); Destination destination = session.createQueue("myQueue");
MessageProducer producer = session.createProducer(destination);
producer.setDeliveryMode(DeliveryMode.PERSISTENT); // 发送持久化消息 TextMessage
message = session.createTextMessage("Hello World"); producer.send(message);
RocketMQ
持久化机制:
- CommitLog:RocketMQ 使用 CommitLog 文件记录所有的消息,消息首先写入 CommitLog,然后异步刷盘到磁盘。
- 消费队列:消费队列存储消息的逻辑偏移量,用于加快消息消费速度。
- 消息索引:存储消息索引,以便快速检索消息。
- 同步和异步刷盘:支持同步刷盘和异步刷盘策略,以平衡性能和数据可靠性。
使用示例:
DefaultMQProducer producer = new DefaultMQProducer("ProducerGroupName");
producer.setNamesrvAddr("127.0.0.1:9876");
producer.start(); Message msg = new Message("TopicTest", "TagA", "OrderID001", "Hello world".getBytes());
msg.setFlag(1); // 设置消息的 flag 位
producer.send(msg);
producer.shutdown();
Kafka
持久化机制:
- 日志分段文件:Kafka 将消息写入日志分段文件(Log Segment),每个分段文件大小固定,当分段文件达到设定大小时,会创建新的分段文件。
- 多副本机制:Kafka 支持多副本机制,每个分区的消息可以复制到多个 Broker 上,提供高可用性和容错能力。
- 数据保留策略:可以配置消息的保留时间或保留大小,超出限制的旧消息会被删除。
使用示例:
Properties props = new Properties();
props.put("bootstrap.servers", "localhost:9092");
props.put("acks", "all");
props.put("retries", 0);
props.put("batch.size", 16384);
props.put("linger.ms", 1);
props.put("buffer.memory", 33554432);
props.put("key.serializer","org.apache.kafka.common.serialization.StringSerializer"); props.put("value.serializer","org.apache.kafka.common.serialization.StringSerializer");
Producer<String, String> producer = new KafkaProducer<>(props);
for (int i = 0; i < 100; i++) { producer.send(new ProducerRecord<>("myTopic", Integer.toString(i), Integer.toString(i)));
} producer.close();
总结
这四种消息队列系统都支持持久化,但其实现机制和适用场景有所不同:
RabbitMQ:适用于需要灵活路由和可靠消息传递的企业应用。
ActiveMQ:适用于需要 JMS 兼容性和多协议支持的企业级应用。
RocketMQ:适用于需要高吞吐量、低延迟和分布式事务支持的场景。
Kafka:适用于大规模数据流处理和实时分析场景,提供高吞吐量、低延迟和强持久化支持。
分布式:
RabbitMQ
分布式支持
- 集群模式:RabbitMQ 支持集群模式,可以将多个 RabbitMQ 节点组成一个集群,从而提高系统的可靠性和可扩展性。
- 高可用队列:RabbitMQ 提供镜像队列(Mirrored Queues),可以将队列的副本复制到集群中的其他节点,实现高可用性。
- 联邦模式和分布式交换机:RabbitMQ 支持联邦模式(Federation)和分布式交换机(Shovel),可以在跨数据中心或广域网中同步消息。
优缺点
- 优点:易于设置和管理,支持多种分布式模式,适用于中小规模的分布式系统。
- 缺点:在高吞吐量和低延迟场景下性能可能不如 Kafka 和 RocketMQ。
ActiveMQ
分布式支持
- 主从架构:ActiveMQ 支持主从架构,通过主从复制实现高可用性。当主节点故障时,从节点可以接管。
- 网络连接器:ActiveMQ 支持网络连接器(Network of Brokers),允许将多个 ActiveMQ 节点连接在一起,实现消息的分布式传递和负载均衡。
- 集群模式:支持通过共享文件系统或数据库实现集群部署。
优缺点
- 优点:JMS 兼容性强,适用于企业级应用,支持多种分布式部署模式。
- 缺点:集群管理和配置较复杂,性能在高吞吐量场景下可能不如 Kafka 和 RocketMQ。
RocketMQ
分布式支持
- 多副本机制:RocketMQ 支持多副本机制,每个分区的消息可以复制到多个 Broker 上,提供高可用性和容错能力。
- 水平扩展:RocketMQ 通过增加更多的 Broker 节点来扩展系统的容量和处理能力,适应业务增长。
- 高可用性:支持主从架构,通过主从同步和异步刷盘机制实现高可用性。
优缺点
- 优点:高吞吐量、低延迟,支持分布式事务,适用于金融、电商和实时数据处理等高性能需求的场景。
- 缺点:学习曲线较陡,集群管理和运维需要一定的专业知识。
Kafka
分布式支持
- 分区机制:Kafka 通过分区机制实现水平扩展,每个主题可以有多个分区,分区可以分布在不同的 Broker 上,实现负载均衡和高可用性。
- 多副本机制:Kafka 支持多副本机制,每个分区的消息可以复制到多个 Broker 上,确保数据的高可用性和容错能力。
- 数据保留策略:Kafka 支持数据持久化和保留策略,适用于大数据和实时数据流处理。
优缺点
- 优点:高吞吐量、低延迟,强大的水平扩展能力,适用于大规模数据流处理和实时分析场景。
- 缺点:学习曲线陡,管理和运维复杂,对硬件资源要求较高。
总结
这四种消息队列系统都支持分布式场景,但各有侧重:
- RabbitMQ:适用于中小规模分布式系统,支持多种分布式模式,易于设置和管理。
- ActiveMQ:适用于企业级应用,支持 JMS 兼容性和多种分布式部署模式,但集群管理较复杂。
- RocketMQ:适用于需要高吞吐量、低延迟和分布式事务支持的场景,适合金融、电商和实时数据处理。
- Kafka:适用于大规模数据流处理和实时分析场景,具有强大的水平扩展能力和高吞吐量、低延迟特性。