持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第11天,点击查看活动详情
前言
今天是我 Kafka 学习的第 12 天,今天学习的内容是 Kafka 的延时操作。
ACK 参数
首先我们先回顾一下 ACK 参数设置。
acks 参数用来指定分区中必须要有多少个副本收到这条消息,之后生产者才会认为这条消息是成功写入的。acks 参数目前有三种值,即 1、0 和 -1。接下来我们分别来看看这个参数具体含义。
acks=1:·acks的默认值即为1。生产者发送消息之后,只要分区的 leader 副本成功写入消息,那么它就会收到来自服务端的成功响应。如果消息无法写入 leader 副本,比如在 leader 副本崩溃、重新选举新的 leader 副本的过程中,那么生产者就会收到一个错误的响应,为了避免消息丢失,生产者可以选择重发消息。acks设置为 1,是消息可靠性和吞吐量之间的折中方案。acks=0:生产者发送消息之后不需要等待任何服务端的响应。如果在消息从发送到写入 Kafka 的过程中出现某些异常,导致 Kafka 并没有收到这条消息,那么生产者也无从得知,消息也就丢失了。在其他配置环境相同的情况下,acks设置为 0 可以达到最大的吞吐量。acks=-1或acks=all:生产者在消息发送之后,需要等待 ISR(In-Sync Replicas,同步副本集) 中的所有副本都成功写入消息之后才能够收到来自服务端的成功响应。在其他配置环境相同的情况下,acks设置为-1(all)可以达到最强的可靠性。但这并不意味着消息就一定可靠,因为 ISR 中可能只有 leader 副本,这样就退化成了acks=1的情况。
延时操作
如果在使用生产者客户端发送消息的时候将 acks 参数设置为 -1,那么就意味着需要等待 ISR 集合中的所有副本都确认收到消息之后才能正确地收到响应的结果,或者捕获超时异常。
那么等待消息写入副本和返回相应的响应结果给客户端这个动作是由谁来执行的呢?答案是 在将消息写入 leader 副本的本地日志文件之后,Kafka会创建一个延时的生产操作(DelayedProduce),用来处理消息正常写入所有副本或超时的情况,以返回相应的响应结果给客户端。
在 Kafka 中有多种延时操作,比如延时生产,延时拉取(DelayedFetch)、延时数据删除(DelayedDeleteRecords)等。延时操作需要延时返回响应的结果,首先它必须有一个超时时间(delayMs),如果在这个超时时间内没有完成既定的任务,那么就需要强制完成以返回响应结果给客户端。其次,延时操作不同于定时操作,定时操作是指在特定时间之后执行的操作,而延时操作可以在所设定的超时时间之前完成,所以 延时操作能够支持外部事件的触发。
延时操作创建之后会被加入延时操作管理器(DelayedOperationPurgatory)来做专门的处理。延时操作有可能会超时,每个延时操作管理器都会配备一个定时器(SystemTimer)来做超时管理,定时器的底层就是采用时间轮(TimingWheel)实现的。
延时生产
对于延时生产操作而言,它的外部事件是 写入消息的某个分区的 HW(高水位)发生增长。也就是说,随着 follower 副本不断地与 leader 副本进行消息同步,进而促使 HW 进一步增长,HW 每增长一次都会检测是否能够完成此次延时生产操作,如果可以就执行以此返回响应结果给客户端;如果在超时时间内始终无法完成,则强制执行。
延时拉取
延时拉取操作同样是由 超时触发 或 外部事件触发 而被执行的。
超时触发很好理解,就是等到超时时间之后触发第二次读取日志文件的操作。
外部事件触发就稍复杂了一些,因为拉取请求不单单由 follower 副本发起,也可以由消费者客户端发起,两种情况所对应的外部事件也是不同的。如果是 follower 副本的延时拉取,它的外部事件就是消息追加到了 leader 副本的本地日志文件中;如果是消费者客户端的延时拉取,它的外部事件可以简单地理解为 HW 的增长。
参考文档
- 《深入理解 Kafka:核心设计与实践原理》—— 朱忠华