- Kafaka消费者组
- 多个实例共同订阅若干个主题,实现共同消费。
- 同一个组下的每个实例都配置有 相同的组 ID,订阅不同的分区。
- 当某个实例挂掉的时候,其他实例会自动地承担起 它负责消费的分区。
- 扩展: offset原理
- 扩展: 消费者组与 Broker 之间的交互
- 在 Kafka 中,ZooKeeper 的作用
- Kafka 2.8.0之后,可以脱离 ZooKeeper 独立运行
- Kafka 使用 ZooKeeper 存放集群元数据、成员管理、Controller 选举,以及其他一些管理类任务
- 存放元数据”是指主题 分区的所有数据都保存在 ZooKeeper 中,且以它保存的数据为权威,其他“人”都要与它 保持对齐。
- “成员管理”是指 Broker 节点的注册、注销以及属性变更
- “Controller 选举”是指选举集群 Controller,而其他管理类任务包括但不限于主题 删除、参数配置等。
- 更新之后是 基于 Raft 的共识算法, 替代 ZooKeeper,实现 Controller 自选举。
- www.cnblogs.com/yogoup/p/14…
- 位移(offset)
- 每个 主题分区下的每条消息都被赋予了一个唯一的 ID 数值,用于标识它在分区中的位置。这个 ID 数值,就被称为位移,或者叫偏移量。一旦消息被写入到分区日志,它的位移值将不能 被修改
- Broker 底层日志写入的逻辑,消息在日志中的存放格式
- Log Cleaner 组件都不能影响offset
- 位移值和消费者位移值之间的区别
- leader 和 follower
- 只有 Leader 副本才能 对外提供读写服务,响应 Clients 端的请求
- Follower 副本只是采用拉(PULL)的方 式,被动地同步 Leader 副本中的数据,并且在 Leader 副本所在的 Broker 宕机后,随时 准备选举 Leader
- Follower 副本也能对外提供读服务。自 Kafka 2.4 版本开始,社区通过引入新的 Broker 端参数,允许 Follower 副本有限度地提供读服务
- Leader 和 Follower 的消息序列在实际场景中不一致。很多原因都可能造成 Leader 和 Follower 保存的消息序列不一致,比如程序 Bug、网络问题等。这是很严重 的错误,必须要完全规避。你可以补充下,之前确保一致性的主要手段是高水位机制, 但高水位值无法保证 Leader 连续变更场景下的数据一致性,因此,社区引入了 Leader Epoch 机制,来修复高水位值的弊端
- 如何设置 Kafka 能接收的最大消息的大小
- 除了要回答消费者端的参数设置之外,一定要加上 Broker 端的设置,这样才算完整
- Broker 端参数:message.max.bytes、max.message.bytes(主题级别)和 replica.fetch.max.bytes。
- Consumer 端参数:fetch.message.max.bytes
- Leader 总是 -1,怎么破?
- 在生产环境中,你一定碰到过“某个主题分区不能工作了”的情形。使用命令行查看状态的 话,会发现 Leader 是 -1,于是,你使用各种命令都无济于事,最后只能用“重启大 法”。
- 删除 ZooKeeper 节点 /controller,触发 Controller 重选举。 Controller 重选举能够为所有主题分区重刷分区状态,可以有效解决因不一致导致的 Leader 不可用问题。
- LEO、LSO、AR、ISR、HW 都表示什么含义?
- LEO:Log End Offset。日志末端位移值或末端偏移量,表示日志下一条待插入消息的 位移值
- ISR:In-Sync Replicas。Kafka 中特别重要的概念,指代的是 AR 中那些与 Leader 保 持同步的副本集合
- 关于 ISR,还有一个常见的面试题目是如何判断副本是否应该属于 ISR。目前的判断 依据是:Follower 副本的 LEO 落后 Leader LEO 的时间,是否超过了 Broker 端参数 replica.lag.time.max.ms 值。如果超过了,副本就会被从 ISR 中移除。
- Kafka 能手动删除消息吗?
- Kafka 不需要用户手动删除消息。它本身提供了留存策略,能够自动删除过期消息。 当然,它是支持手动删除消息的。因此,你最好从这两个维度去回答
- 对于设置了 Key 且参数 cleanup.policy=compact 的主题而言,我们可以构造一条 <Key,null> 的消息发送给 Broker,依靠 Log Cleaner 组件提供的功能删除掉该 Key 的消息。
- 对于普通主题而言,我们可以使用 kafka-delete-records 命令,或编写程序调用 Admin.deleteRecords 方法来删除消息。这两种方法殊途同归,底层都是调用 Admin 的 deleteRecords 方法,通过将分区 Log Start Offset 值抬高的方式间接删除消息
- __consumer_offsets 是做什么用的
- 它是一个内部主题,无需手动干预,由 Kafka 自行管理。当然,我们可以创建该主题。
- 它的主要作用是负责注册消费者以及保存位移值。该主题也是保存消费者元数据的地方
- Kafka 的 GroupCoordinator 组件提供对该主题完整的管理功能,包括该主题的创建、 写入、读取和 Leader 维护等。
- 分区 Leader 选举策略有几种?
- Kafka 的哪些场景中使用了零拷贝
- 体现 Zero Copy 使用场景的地方有两处:基于 mmap 的索引和日志文件读写所用的 TransportLayer
- 先说第一个。索引都是基于 MappedByteBuffer 的,也就是让用户态和内核态共享内核态 的数据缓冲区,此时,数据不需要复制到用户态空间。不过,mmap 虽然避免了不必要的 拷贝,但不一定就能保证很高的性能。在不同的操作系统下,mmap 的创建和销毁成本可 能是不一样的。很高的创建和销毁开销会抵消 Zero Copy 带来的性能优势。由于这种不确 定性,在 Kafka 中,只有索引应用了 mmap,最核心的日志并未使用 mmap 机制。
- 再说第二个。TransportLayer 是 Kafka 传输层的接口。它的某个实现类使用了 FileChannel 的 transferTo 方法。该方法底层使用 sendfile 实现了 Zero Copy。对 Kafka 而言,如果 I/O 通道使用普通的 PLAINTEXT,那么,Kafka 就可以利用 Zero Copy 特 性,直接将页缓存中的数据发送到网卡的 Buffer 中,避免中间的多次拷贝。相反,如果 I/O 通道启用了 SSL,那么,Kafka 便无法利用 Zero Copy 特性了
- Kafka 为什么不支持读写分离
- 最初为了避免不一致性的问题,而采用了让 Leader 统一提供服 务的方式。
- 自 Kafka 2.4 之后,Kafka 提供了有限度的读写分离,也就是说,Follower 副本能够对外提供读服务
- 场景不适用。读写分离适用于那种读负载很大,而写操作相对不频繁的场景
- 同步机制。Kafka 采用 PULL 方式实现 Follower 的同步,因此,Follower 与 Leader 存 在不一致性窗口。如果允许读 Follower 副本,就势必要处理消息滞后(Lagging)的问题。
-
如何调优 Kafka?
- 优化 Kafka 的 TPS
- Producer 端:增加 batch.size、linger.ms,启用压缩,关闭重试等。
- Broker 端:增加 num.replica.fetchers,提升 Follower 同步 TPS,避免 Broker Full GC 等。
- Consumer:增加 fetch.min.bytes 等
-
Controller 发生网络分区(Network Partitioning)时,Kafka 会怎 么样?
- 一旦发生 Controller 网络分区,那么,第一要务就是 查看集群是否出现“脑裂”,即同时出现两个甚至是多个 Controller 组件。这可以根据 Broker 端监控指标 ActiveControllerCount 来判断
-
现在,我们分析下,一旦出现这种情况,Kafka 会怎么样。
由于 Controller 会给 Broker 发送 3 类请求,即LeaderAndIsrRequest、 StopReplicaRequest 和 UpdateMetadataRequest,因此,一旦出现网络分区,这些请求将不能顺利到达 Broker 端。这将影响主题的创建、修改、删除操作的信息同步,表现为 集群仿佛僵住了一样,无法感知到后面的所有操作。因此,网络分区通常都是非常严重的问 题,要赶快修复。 16. Java Consumer 为什么采用单线程来获取消息
- Java Consumer 是双线程的设计。一 个线程是用户主线程,负责获取消息;另一个线程是心跳线程,负责向 Kafka 汇报消费者 存活情况。将心跳单独放入专属的线程,能够有效地规避因消息处理速度慢而被视为下线 的“假死”情况。
- 单线程获取消息的设计能够避免阻塞式的消息获取方式。单线程轮询方式容易实现异步非阻塞式,这样便于将消费者扩展成支持实时流处理的操作算子。因为很多实时流处理操作算子都不能是阻塞式的。另外一个可能的好处是,可以简化代码的开发。多线程交互的代码是非常容易出错的。
- Follower 副本消息同步的完整流程
- 首先,Follower 发送 FETCH 请求给 Leader。接着,Leader 会读取底层日志文件中的消 息数据,再更新它内存中的 Follower 副本的 LEO 值,更新为 FETCH 请求中的 fetchOffset 值。最后,尝试更新分区高水位值。Follower 接收到 FETCH 响应之后,会把 消息写入到底层日志,接着更新 LEO 和 HW 值。
Leader 和 Follower 的 HW 值更新时机是不同的,Follower 的 HW 更新永远落后于 Leader 的 HW。这种时间上的错配是造成各种不一致的原因