RocketMQ是如何做到比Kafka支持更多队列

1,319 阅读3分钟

Kafka与RocketMQ

Kafka是一个分布式流平台,它源自于日志聚合案例,它不需要太高的并发性。在阿里巴巴的一些大型案例中,发现原来的模式已经不能满足实际需求。因此,开发了一个名为RocketMQ的消息中间件,它可以处理广泛的场景,从传统的发布/订阅场景到要求高容量、不允许消息丢失的实时事务系统等。

Kafka的分区设计

  • 生产者并行写的性能受到分区数量的限制。
  • 消费者并行消费的能力也受分区数限制。假设分区数量是20,那么最大的并发消费者数量是20。
  • 每个主题由固定数量的分区组成,分区数量决定单个Broker在不会显著影响性能的情况下,可以拥有的主题最大数量。

如何选择Kafka集群中Topic分区数量请参考文章: www.confluent.io/blog/how-ch…

为什么Kafka不能支持更多的分区?

  • 每个分区存储整个消息数据。虽然每个分区都是有序地写入磁盘的,但是随着并发写入分区的增加,从操作系统的角度来看,写入变得随机。
  • 由于数据文件分散,很难使用Linux IO组提交机制。

RocketMQ 是如何支持更多的分区的?

RocketMQ生产消费机制

  • 所有消息数据都存储在提交日志文件中,所有写入都是完全连续的,而读取是随机的。
  • ConsumeQueue存储用户实际消费的位置信息,这些信息也按顺序刷新到磁盘。

优势:

  1. 每个消费队列都变得轻量化,并且包含有限数量的元数据(数据量变少)。
  2. 对磁盘的访问是完全连续的,这样可以避免磁盘锁争夺,并且在创建大量队列时不会导致高磁盘IO等待。

劣势:

  1. 消费消息将首先读取消费队列,然后提交日志,在最坏的情况下,过程会带来一定的成本。
  2. 提交日志和使用队列需要逻辑一致,这会给编程模型带来额外的复杂性。

RocketMQ设计的动机

  1. 随机读:尽可能多地读取以增加页面缓存命中率,并减少读取IO操作。所以在大内存情况下是仍然是适合的。如果积压了大量的消息,读取的性能会严重下降吗?答案是否定的。

原因如下:

  • 即使消息大小只有1KB,系统也会提前读取更的数据(缓存数据预取:参考 PAGECACHE prefetch(en.wikipedia.org/wiki/Cache_…
  • 从磁盘随机访问CommitLog,如果在SSD的情况下将I/O调度器设置为NOOP,那么读取QPS的速度将大大加快,比其他操作系统调度算法快得多。
  1. 由于ConsumeQueue只存储固定大小的元数据,主要用于记录消费过程,因此支持随机读取。利用页面缓存预取,即使是在大量消息积压的情况下,访问ConsumeQueue的速度与访问主内存一样快。因此,ConsumeQueue不会带来明显的读取性能影响。

  2. CommitLog几乎存储所有信息,包括消息数据。与关系数据库的重做日志类似,只要存在提交日志,就可以完全恢复使用队列、消息键索引和所有其他所需数据。


最后欢迎大家点赞、收藏、评论,转发!

欢迎大家关注我的微信公众号!微信搜索:进击的Matrix

欢迎大家关注我的知乎!可乐

微信公众号-进击的Matrix