RocketMQ

一、MQ对比

性能 ActiveMQ RabbitMQ RocketMQ Kafka
单机吞吐量 万级 万级 十万级 十万级
Topic数量对吞吐量的影响 Topic可以达到几百、几千个的级别,吞吐量会有小幅下降 Topic从几十个到几百个的时候,吞吐量会大幅下降
时效性 ms µs级 ms级 ms级以内
可用性 高,主从架构 高,主从架构 非常高,分布式架构 非常高,分布式架构
消息可靠性 有较低的概率丢失数据 经过参数配置,可以做到零丢失 经过参数配置,可以做到零丢失
负载均衡 支持 不支持 支持 支持
优势 非常成熟,功能强大,文档丰富,支持多语言 erlang语言开发,延时很低,管理界面友好,支持多语言,社区活跃 接口简单易用,分布式扩展方便,社区活跃,支持大规模的Topic,支持多种消费方式 极高的可用性和可靠性,分布式扩展方便
劣势 偶尔有较低概率丢失消息,社区活跃度不高 erlang语言开发不容易进行定制开发,集群动态扩展麻烦 只支持Java,接口不是按照标准JMS规范走的,有的系统迁移要修改大量的代码 大量topic下吞吐量降低。

RocketMQ和kafka对比:

性能:差不多,都支持10万级别。但是kafka在topic达到几百的时候性能下降严重,RocketMQ略微会有下降。

稳定性:都是分布式架构,稳定性较高。

可靠性:都可以做到零丢失

其他:RocketMQ支持消息重试、死信队列,kafka不支持,kafka主要用于大数据。

 

为什么选RocketMQ:高吞吐单机可以达10万,分布式架构,服务稳定,消息可靠,可以做到0丢失。

二、RocketMQ介绍

1.整体架构

 

 

Name Server:为 Producer 和 Consumer 提供路由信息。路由到Broker的信息。可以理解成是Broker的发现和注册。保存Topic和Broker的关系,即哪个Topic哪个Queue在哪个Broker上。

Producer:生产消息。

Consumer:消费消息。

Broker:存储消息的地方。

Topic:消息的逻辑分类,是生产者在发送消息和消费者在拉取消息的类别。

2.四种消息类型

  • 普通消息:没有什么特殊的地方,就是普通消息
  • 延迟消息:延迟特定的时间间隔后消息才会被消费者消费。目前只支持特定级别的延时消息(1s到2h多个级别),每一个延迟级别单独有一个定时器,定时(每隔1秒)拉取对应延迟级别的消费队列。
  • 顺序消息:对于指定的一个 Topic,Producer保证消息顺序的发到一个队列中,消费的时候需要保证队列的数据只有一个线程消费。
  • 事务消息:通过两阶段提交、状态定时回查来保证消息一定发到broker。

3.三种消息发送方式

消息发送方式 介绍 优点 缺点
同步发送 消息发出后,在收到接收方发回响应之后才发下一个数据包 简单 耗时高
异步发送 发出数据后,不等接收方发回响应,接着发送下个数据包。 (需要用户实现异步发送回调接口(SendCallback),在回调接口中对发送结果进行处理) 耗时短 需要实现SendCallback接口
单向发送 发送方只负责发送消息,不等待服务器回应且没有回调函数触发,即只发送请求不等待应答。 耗时短,微秒级别 可靠性会降低

4.消息发送流程

5.消息存储

  • CommitLog:存消息的文件(采用文件系统存储),单个Broker下的所有队列共用一个CommitLog。
  • ConsumeQueue:是消息消费队列文件,消息达到commitlog文件后将被异步转发到消息消费队列,供消息消费者消费;
  • IndexFile:消息索引文件,记录key和offset的对应关系。提供了一种可以通过key和时间区间来查询消息的方法。

总结一下:所有消息都记录在CommitLog,生产者生产完一个消息后,会dispatch到对应的某个ConsumeQueue中,然后消费者来当前Queue消费消息时,根据对于的偏移量到CommitLog找到对应的消息进行消费。IndexFile只是提供了可以根据key和对应时间来找对应消息的一种方法。

注:只要消息写入了CommitLog,那么这个消息就不会丢失了。

6.Consumer消费方式

有拉取式消费(Pull Consumer)以及推动式消费(Push Consumer)两种方式。pull就是消费者定时轮询Broker,push就是Broker收到消息时主动推送给消费者。

7.消息刷盘

同步刷盘:只有消息真正持久化到磁盘,Broker才会给Producer一个成功的ack响应。消息可靠性有保障,但是性能会有影响。

异步刷盘:只要消息写入PageCache即给Producer一个成功的ack响应,消息刷盘采用后台异步线程提交的形式进行。

三、常见问题

1.RocketMq快的原因

RocketMq与Kafka在写消息与发送消息上,继续沿用了Kafka的这两个方面:顺序写和零拷贝

1)顺序写

从磁盘读数据时,需要找到数据在磁盘上的地址(寻址),再进行读写,寻址需要的时间会比较长。但Kafka 的数据存储在磁盘上面,依然性能很好,这是因为,Kafka采用的是顺序写,直接追加数据到末尾。实际上,磁盘顺序写的性能极高,基本和内存速度一致,磁盘的顺序写这一机制,极大地保证了Kafka本身的性能
2)零拷贝
读取文件,再用socket发送出去这一过程,传统方式需要先读取再发送,会经过以下四次复制:
1、将磁盘文件,读取到操作系统内核缓冲区Read Buffer
2、将内核缓冲区的数据,复制到应用程序缓冲区Application Buffer
3、将应用程序缓冲区Application Buffer中的数据,复制到socket网络发送缓冲区
4、将Socket buffer的数据,复制到网卡,由网卡进行网络传输


第2次和第3次数据的复制过程,不仅没有任何帮助,反而带来了巨大的开销。使用零拷贝,就是说,直接由内核缓冲区Read Buffer将数据复制到网卡,省去第二步和第三步的复制。

注:RocketMq的存储消息的文件CommitLog的大小规定为1G。是因为零拷贝技术有限制,传输的文件不能超过2G。

2.消息有序是怎么实现的

全局有序:将Topic配置成只有一个MessageQueue队列。

局部有序:将有序的一组消息都存入同一个MessageQueue。(发送消息时可以指定MessageSelector对象,可以发到对应的MessageQueue)

注:因为有MessageQueue存在,消费者会从多个MessageQueue消费数据,所以不管全局有序还是局部有序,都是利用的MessageQueue的FIFO设计。