本文来源丨https://www.jianshu.com/p/5aa8776868bb
1、Consumer与Consumer Group
consumer group是kafka提供的可扩展且具有容错性的消费者机制。组内可以有多个消费者或消费者实例(consumer instance),它们共享一个公共的ID,即group ID。组内的所有消费者协调在一起来消费订阅主题(subscribed topics)的所有分区(partition)。
consumer group下可以有一个或多个consumer instance,consumer instance可以是一个进程,也可以是一个线程
group.id是一个字符串,唯一标识一个consumer group
consumer group下订阅的topic下的每个分区只能分配给某个group下的一个consumer(当然该分区还可以被分配给其他group)
2、Coordinator介绍
Coordinator一般指的是运行在broker上的group Coordinator,用于管理Consumer Group中各个成员,每个KafkaServer都有一个GroupCoordinator实例,管理多个消费者组,主要用于offset位移管理和Consumer Rebalance。
对于每个Consumer Group,Coordinator会存储以下信息:- 对每个存在的topic,可以有多个消费组group订阅同一个topic(对应消息系统中的广播)
- 对每个Consumer Group,元数据如下:订阅的topics列表Consumer Group配置信息,包括session timeout等组中每个Consumer的元数据。包括主机名,consumer id每个正在消费的topic partition的当前offsetsPartition的ownership元数据,包括consumer消费的partitions映射关系
确定consumer group位移信息写入__consumers_offsets这个topic的哪个分区。具体计算公式:__consumers_offsets partition# = Math.abs(groupId.hashCode() % groupMetadataTopicPartitionCount) 注意:groupMetadataTopicPartitionCount由offsets.topic.num.partitions指定,默认是50个分区。
该分区leader所在的broker就是被选定的coordinator
3、offset位移管理
消费者在消费的过程中需要记录自己消费了多少数据,即消费位置信息。在Kafka中这个位置信息有个专门的术语:位移(offset)。(1)、很多消息引擎都把这部分信息保存在服务器端(broker端)。这样做的好处当然是实现简单,但会有三个主要的问题:
1. broker从此变成有状态的,会影响伸缩性;
2. 需要引入应答机制(acknowledgement)来确认消费成功。
3. 由于要保存很多consumer的offset信息,必然引入复杂的数据结构,造成资源浪费。
而Kafka选择了不同的方式:每个consumer group管理自己的位移信息,那么只需要简单的一个整数表示位置就够了;同时可以引入checkpoint机制定期持久化,简化了应答机制的实现。
(2)、Kafka默认是定期帮你自动提交位移的(enable.auto.commit = true),你当然可以选择手动提交位移实现自己控制。
(3)、另外kafka会定期把group消费情况保存起来,做成一个offset map,如下图所示: 图中表明了test-group这个组当前的消费情况
老版本的位移是提交到zookeeper中的,目录结构是:/consumers//offsets//,但是zookeeper其实并不适合进行大批量的读写操作,尤其是写操作。
因此kafka提供了另一种解决方案:增加__consumeroffsets topic,将offset信息写入这个topic,摆脱对zookeeper的依赖(指保存offset这件事情)。__consumer_offsets中的消息保存了每个consumer group某一时刻提交的offset信息。依然以上图中的consumer group为例,格式大概如下: __consumers_offsets topic配置了compact策略,使得它总是能够保存最新的位移信息,既控制了该topic总体的日志容量,也能实现保存最新offset的目的。 offset提交消息会根据消费组的key(消费组名称)进行分区. 对于一个给定的消费组,它的所有消息都会发送到唯一的broker(即Coordinator) Coordinator上负责管理offset的组件是Offset manager。负责存储,抓取,和维护消费者的offsets. 每个broker都有一个offset manager实例. 有两种具体的实现: ZookeeperOffsetManager: 调用zookeeper来存储和接收offset(老版本的位移管理)。 DefaultOffsetManager: 提供消费者offsets内置的offset管理。 通过在config/server.properties中的offset.storage参数选择。 DefaultOffsetManager 除了将offset作为logs保存到磁盘上,DefaultOffsetManager维护了一张能快速服务于offset抓取请求的consumer offsets表。这个表作为缓存,包含的含仅仅是”offsets topic”的partitions中属于leader partition对应的条目(存储的是offset)。 对于DefaultOffsetManager还有两个其他属性: “offsets.topic.replication.factor和”offsets.topic.num.partitions”,默认值都是1。这两个属性会用来自动地创建”offsets topic”。 offset manager接口的概要: Offset Commit提交过程: 消费端 一条offset提交消息会作为生产请求.当消费者启动时,会为”offsets topic”创建一个消费者. 下面是内置的生产者的一些属性: 可以使用异步.但是使用同步可以避免延迟的生产请求(因为是批量消息),并且我们需要立即知道offset消息是否被broker成功接收 |request.required.acks|-1|确保所有的replicas和leader是同步的,并且能看到所有的offset消息 |key.serializer.class|StringEncoder|key和payload都是strings 注意我们没有对提交的offset消息进行压缩,因为每条消息本身大小是很小的,如果压缩了反而适得其反. 目前key和offset的值通过纯文本方式传递. 我们可以转换为更加紧凑的二进制协议,而不是把 Long类型的offset和Int类型的partition作为字符串. 当然在不断演进时还要考虑版本和格式协议. broker端 broker把接收到的offset提交信息当做一个正常的生产请求,对offset请求的处理和正常的生产者请求处理方式是一样的. 一旦将数据追加到leader的本地日志中,并且所有的replicas都赶上leader.leader检查生产请求是”offsets topic”, (因为broker端的处理逻辑针对offset请求和普通生产请求是一样的,如果是offset请求,还需要有不同的处理分支) 它就会要求offset manager添加这个offset(对于延迟的生产请求,更新操作会在延迟的生产请求被完成的时候). 因为设置了acks=-1,只有当这些offsets成功地复制到ISR中的所有brokers,才会被提交给offset manager.3、Consumer Reblance
什么是rebalance?
rebalance本质上是一种协议,规定了一个consumer group下的所有consumer如何达成一致来分配订阅topic的每个分区。比如某个group下有20个consumer,它订阅了一个具有100个分区的topic。正常情况下,Kafka平均会为每个consumer分配5个分区。这个分配的过程就叫rebalance。Kafka新版本consumer默认提供了两种分配策略:range和round-robin。
rebalance的触发条件有三种:
组成员发生变更(新consumer加入组、已有consumer主动离开组或已有consumer崩溃了——这两者的区别后面会谈到)
订阅主题数发生变更——这当然是可能的,如果你使用了正则表达式的方式进行订阅,那么新建匹配正则表达式的topic就会触发rebalance
订阅主题的分区数发生变更