Kafka 与 RocketMQ 性能对比

一:文件存储

1、Kafka:

kafka和yarn的区别 kafka对比_kafka

  • 文件以 topic和分区进行存储,每一个 topic 可以创建多个分区,每一个分区包含单独的文件夹,并且是多副本机制。
  • topic 的每一个分区会有 Leader 与 Follow,并且 Kafka 内部有机制保证 topic 的某一个分区的 Leader 与 follow 不会存在在同一台机器,并且每一台 broker 会尽量均衡的承担各个分区的 Leader,当然在运行过程中如果不均衡,可以执行命令进行手动重平衡。
  • Leader 节点承担一个分区的读写,follow 节点只负责数据同步(数据备份)。
  • 如果Leader分区所在的Broker节点发生宕机,会触发主从节点的切换,会在剩下的 follow 节点中选举一个新的 Leader 节点

分区 Leader 收到客户端的消息发送请求时,什么时候返回发送成功,会直接影响消息发送端的时延,Kafka 提供了 ack 这个参数来进行策略选择:

  • ack = 0
    不等broker端确认就直接返回,即客户端将消息发送到网络中就返回发送成功。
  • ack = 1
    Leader 节点接受并存储后向客户端返回成功。
  • ack = -1
    Leader节点和所有的Follow节点接受并成功存储再向客户端返回成功。

2、RocketMQ

kafka和yarn的区别 kafka对比_个人开发_02

  • RocketMQ 所有topic的消息都会写入到 commitlog 文件中,然后基于 commitlog文件构建消息消费队列文件(Consumequeue),消息消费队列的组织结构按照 /topic/{queue} 进行组织。
  • RocketMQ 默认采取的是主从同步+异步刷盘、多副本机制,但其副本的粒度为 Commitlog 文件,上图中不同 master 节点之间的数据完成不一样(数据分片),而主从节点节点数据一致。

同样RocketMQ发送也有三种类型

  • 1、同步(syncSend方法),会在broker发回响应之后才发下一个msg。适用于msg很重要对响应时间不敏感的场景
  • 2、异步(asyncSend方法),发送之后不等broker响应,接着发下一个msg,需要实现异步发送回调的接口SendCallback,通过回调接口接收服务器的响应,并对响应结果进行处理,适用于msg很重要且对响应时间非常敏感的场景
  • 3、单向(sendOneWay方法),只负责发消息,不等服务器响应也没有回调,适用于对可靠性要求不高的场景比如日志收集

3、存储方式总结:

  • 1、Kafka 中是以 Topic/partition,每一个分区一个物理文件夹,在分区文件级别实现文件顺序写,如果分区过多上千个,消息在高并发写入时会变成随机IO。即 Kafka 在消息写入时的IO性能会随着 topic 、分区数量的增长,其写入性能会先上升,然后下降。而 RocketMQ则追求极致的顺序写所有的消息不分主题一律顺序写入 commitlog 文件,并不会随着 topic 和 分区数量的增加而影响其顺序性。
  • 2、Kafka 的 topic 扩容分区会涉及分区在各个 Broker 的移动,其扩容操作比较重,而 RocketMQ 数据存储是基于 commitlog 文件的,扩容时不会产生数据移动,只会对新的数据产生影响,所以RocketMQ 的运维成本比Kafka 更低
  • 3、Kafka 的 ack 参数可以类比 RocketMQ 的同步复制、异步复制,
  • Kafka 的 ack 参数为 1 时,对比 RocketMQ 的异步复制;
  • -1 对标 RocketMQ 的 同步复制;
  • 0 则对标 RocketMQ 消息发送方式的 oneway 模式。

二:消息写入

Kafka 消息写入时的零拷贝使用了FileChannel 的 transferTo 方法, 其内部机制是 sendfile 系统调用。
RocketMQ 的消息写入的零拷贝方式是内存映射, 其内部机制是 mmap

其实在RocketMQ 也是支持 FileChannel 方式写入,只不过写入时调用的 API 却并不是 transferTo,而是先调用 writer,然后定时 flush 刷写到磁盘。个人觉得 不直接调用 transerTo 方法是因为RocketMQ 需要在 Broker 对消息(顺序消息、延迟消息、事务消息)进行加工,然后持久化到磁盘。

三:消息发送

1、kafka

消息发送者发送消息时,消息会首先存入到一个双端队列中,双端队列中单个元素为 ProducerBatch,表示一个发送批次,其最大大小受参数 batch.size 控制,默认为 16K。然后会单独开一个 Send 线程,从双端队列中获取一个发送批次,将消息按批发送到 Kafka集群中,这里引入了 linger.ms 参数来控制 Send 线程的发送行为。如果linger.ms 设置为 0表示立即发送,。linger.ms>0 会增加响应时间,但有利于增加吞吐量。

Kafka 的消息发送,在写入 ProducerBatch 时会按照消息存储协议组织好数据(客户端),在服务端可以直接写入到文件中。

2、RocketMQ

RocketMQ 消息发送在客户端主要是根据路由选择算法选择一个队列,然后将消息发送到服务端,消息会在服务端按照消息的存储格式进行组织,然后进行持久化等操作。

3、消息发送总结

Kafka 在消息发送比 RokcetMQ 显著的优势就是消息格式的组织是发生在客户端,这样会有一个大的优势节约了 Broker 端的CPU压力,客户端“分布式”的承接了其优势,其架构方式有点类似 shardingjdbc 。

Kafka 通过提供 batch.size 与 linger.ms 两个参数按照场景进行定制化,比 RocketMQ 灵活,linger.ms = 0 就是RocketMQ 消息发送的效果。

四:性能对比总结

通过对比来看,Kafka 在性能上综合表现确实要比 RocketMQ 更加的优秀,但在消息选型过程中,我们不仅仅要参考其性能,还有从业务功能性上来考虑, RocketMQ 提供了丰富的消息检索功能、事务消息、消息消费重试、定时消息等。

个人认为通常在大数据、流式处理场景基本选用 Kafka,业务处理相关选择 RocketMQ。