一、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设计。