消费者可以从broker中读取数据。
一个消费者可以消费多个topic中的数据(其中一个partion)。
每个Consumer属于一个特定的Consumer Group。
可为每个Consumer指定group name,若不指定group name则属于默认的group。
KafkaConsumer从Kafka订阅Topic,并从订阅的Topic拉取消息。
Kafka的消费者属于消费者群组,一个群组的消费者订阅多个主题,每个消费者接收主题一部分分区的消息。
每个分区只能被消费者群组的一个消费者接收消息,如果一个消费者群组的消费者数多于一个主题的分区数,则多余的消费者会空闲。
如果主题T1有4个分区,那么消费者群组1有1个、2个、4个和5个消费者的话,与分区的连接情况分别如下:
分区的所有权从一个消费者转移到另一个消费者,这样的行为被称为再均衡。再均衡为Kafka的消息消费带来了高可用性和伸缩性,从而让我们可以放心地添加或者移除消费者,也能很好地处理单节点故障。
但是在再均衡期间,消费者无法读取消息,会造成整个群组的一小段时间不可用。另外,当分区被重新分配给另一个消费者时,消费者当前的读取状态会丢失,它可能还需要去刷新缓存,在它恢复状态之前会拖慢整个应用程序。因此,在正常情况下我们并不希望发生再均衡行为。
当一个新的消费者加入,原本从属其他消费者的分区可能分配到该消费者。
例如原本消费者群组只有一个消费者,那么分区0到分区3这4个都是从属这一个消费者的,如果第二个消费者加入,那么分区2和分区3就会分配给第二个消费者。相反地,如果发生消费者的关闭或者崩溃,也会由其他消费者来接手原本从属于这个消费者的分区。
消费者通过向被指派为群组协调器的broker发送心跳来维持它们和群组的丛书关系以及它们对分区的所有权关系。
消费者会在轮询(为了获取消息)或者提交偏移量的时候发送心跳,来证明自己是活跃的,如果消费者停止发送心跳的时间过长,那么会话就会过期,群组协调器认为它已经死亡,就会触发一次再均衡。
分配分区是怎样的一个过程,当消费者要加入群组时,它会向群组协调器发送 JoinGroup 请求。
第一个加入群组的消费者将成为“群主”。
群主从协调器那里获得群组的成员列表(列表中包含了所有最近发送过心跳的消费者,它们被认为是活跃的), 并负责给每一个消费者分配分区。
它使用一个实现了 PartitionAssignor 接口的类来决定哪些分区应该被分配给哪个消费者。
在消息中间件技术选型的时候有很多选择,Kafka为什么可以脱颖而出?主要是Kafka无与伦比的性能表现。
比如在某电商网站的线上活动中,Kafka 搭建的日志集群单个Topic可以达到几百万的TPS,而使用RocketMQ组件的核心业务集群,集群TPS只能达到几十万TPS。
但性能也并不是考虑技术选型的唯一标准
还有从功能性上来考虑,例如 RocketMQ 提供了丰富的消息检索功能、事务消息、消息消费重试、定时消息等。
从业务的角度考虑,通常在大数据、流式处理场景基本选用 Kafka,业务处理相关选择 RocketMQ。
Kafka 中文件的布局是以 Topic/partition ,每一个分区一个物理文件夹,在分区文件级别实现文件顺序写,如果一个 Kafka 集群中拥有成百上千个主题,每一个主题拥有上百个分区,消息在高并发写入时,其 IO 操作就会显得零散,其操作相当于随机 IO,即 Kafka 在消息写入时的 IO 性能会随着 topic 、分区数量的增长,其写入性能会先上升,然后下降。
RocketMQ 在消息写入时追求极致的顺序写,所有的消息不分主题一律顺序写入 commitlog 文件,并不会随着 topic 和 分区数量的增加而影响其顺序性。但通过笔者的实践来看一台物理机并使用 SSD 盘,但一个文件无法充分利用磁盘 IO 的性能。
两者文件组织方式,除了在磁盘的顺序写方面有所区别后,由于其粒度的问题,Kafka 的 topic 扩容分区会涉及分区在各个 Broker 的移动,其扩容操作比较重,而 RocketMQ 数据存储是基于 commitlog 文件的,扩容时不会产生数据移动,只会对新的数据产生影响,RocketMQ 的运维成本对 Kafka 更低。
最后 Kafka 的 ack 参数可以类比 RocketMQ 的同步复制、异步复制。
Kafka 的 ack 参数为 1/0 时,对比 RocketMQ 的异步复制;
-1 对标 RocketMQ 的 同步复制,而 -1 则对标 RocketMQ 消息发送方式的 oneway 模式。
Kafka 在消息发送方面比 RocketMQ 有一个显著的优势就是消息格式的组织是发生在客户端,这样会有一个大的优势节约了 Broker 端的 CPU 压力,客户端“分布式”的承接了其优势,其架构方式有点类似 shardingjdbc 与 MyCat 的区别。
Kafka 在消息发送端另外一个特点是引入了双端缓存队列,Kafka 无处不在追求批处理,这样显著的特点是能提高消息发送的吞吐量,但与之带来的是增大消息的响应时间,并且带来了消息丢失的可能性,因为 Kafka 追加到消息缓存后会返回成功,如果消息发送方异常退出,会带来消息丢失。
Kafka 中的 linger.ms = 0 可类比 RocketMQ 消息发送的效果。
但 Kafka 通过提供 batch.size 与 linger.ms 两个参数按照场景进行定制化,比 RocketMQ 灵活。
例如日志集群,通常会调大 batch.size 与 linger.ms 参数,重复发挥消息批量发送机制,提高其吞吐量;但如果对一些响应时间比较敏感的话,可以适当减少 linger.ms 的值。