文章目录
- fetch.min.bytes
- fetch.max.wait.ms
- fetch.max.bytes
- max.poll.records
- max.partition.fetch.bytes
- session.timeout.ms和heartbeat.interval.ms
- max.poll.interval.ms
- request.timeout.ms
- auto.offset.reset
- enable.auto.commit
- partition.assignment.strategy
- 区间(range)
- 轮询(roundRobin)
- 黏性(sticky)
- 协作黏性(cooperative sticky)
fetch.min.bytes
这个属性指定了消费者从服务器获取记录的最小字节数,默认是1字节。broker在收到消费者的获取数据请求时,如果可用数据量小于fetch.min.bytes指定的大小,那么它就会等到有足够可用数据时才将数据返回。这样可以降低消费者和broker的负载,因为它们在主题流量不是很大的时候(或者一天里的低流量时段)不需要来来回回地传输消息。如果消费者在没有太多可用数据时CPU使用率很高,或者在有很多消费者时为了降低broker的负载,那么可以把这个属性的值设置得比默认值大。但需要注意的是,在低吞吐量的情况下,加大这个值会增加延迟。
fetch.max.wait.ms
通过设置fetch.min.bytes,可以让Kafka等到有足够多的数据时才将它们返回给消费者,feth.max.wait.ms则用于指定broker等待的时间,默认是500毫秒。如果没有足够多的数据流入Kafka,那么消费者获取数据的请求就得不到满足,最多会导致500毫秒的延迟。如果要降低潜在的延迟(为了满足SLA),那么可以把这个属性的值设置得小一些。如果fetch.max.wait.ms被设置为100毫秒,fetch.min.bytes被设置为1 MB,那么Kafka在收到消费者的请求后,如果有1 MB数据,就将其返回,如果没有,就在100毫秒后返回,就看哪个条件先得到满足。
fetch.max.bytes
这个属性指定了Kafka返回的数据的最大字节数(默认为50 MB)。消费者会将服务器返回的数据放在内存中,所以这个属性被用于限制消费者用来存放数据的内存大小。需要注意的是,记录是分批发送给客户端的,如果broker要发送的批次超过了这个属性指定的大小,那么这个限制将被忽略。这样可以保证消费者能够继续处理消息。值得注意的是,broker端也有一个与之对应的配置属性,Kafka管理员可以用它来限制最大获取数量。broker端的这个配置属性可能很有用,因为请求的数据量越大,需要从磁盘读取的数据量就越大,通过网络发送数据的时间就越长,这可能会导致资源争用并增加broker的负载。
max.poll.records
这个属性用于控制单次调用poll()方法返回的记录条数。可以用它来控制应用程序在进行每一次轮询循环时需要处理的记录条数(不是记录的大小)。
max.partition.fetch.bytes
这个属性指定了服务器从每个分区里返回给消费者的最大字节数(默认值是1 MB)。当KafkaConsumer.poll()方法返回ConsumerRecords时,从每个分区里返回的记录最多不超过max.partition.fetch.bytes指定的字节。需要注意的是,使用这个属性来控制消费者的内存使用量会让事情变得复杂,因为你无法控制broker返回的响应里包含多少个分区的数据。因此,对于这种情况,建议用fetch.max.bytes替代,除非有特殊的需求,比如要求从每个分区读取差不多的数据量。
session.timeout.ms和heartbeat.interval.ms
session.timeout.ms指定了消费者可以在多长时间内不与服务器发生交互而仍然被认为还“活着”,默认是10秒。如果消费者没有在session.timeout.ms指定的时间内发送心跳给群组协调器,则会被认为已“死亡”,协调器就会触发再均衡,把分区分配给群组里的其他消费者。session.timeout.ms与heartbeat.interval.ms紧密相关。heartbeat.interval.ms指定了消费者向协调器发送心跳的频率,session.timeout.ms指定了消费者可以多久不发送心跳。因此,我们一般会同时设置这两个属性,heartbeat.interval.ms必须比session.timeout.ms小,通常前者是后者的1/3。如果session.timeout.ms是3秒,那么heartbeat.interval.ms就应该是1秒。把session.timeout.ms设置得比默认值小,可以更快地检测到崩溃,并从崩溃中恢复,但也会导致不必要的再均衡。把session.timeout.ms设置得比默认值大,可以减少意外的再均衡,但需要更长的时间才能检测到崩溃。
max.poll.interval.ms
这个属性指定了消费者在被认为已经“死亡”之前可以在多长时间内不发起轮询。前面提到过,心跳和会话超时是Kafka检测已“死亡”的消费者并撤销其分区的主要机制。我们也提到了心跳是通过后台线程发送的,而后台线程有可能在消费者主线程发生死锁的情况下继续发送心跳,但这个消费者并没有在读取分区里的数据。要想知道消费者是否还在处理消息,最简单的方法是检查它是否还在请求数据。但是,请求之间的时间间隔是很难预测的,它不仅取决于可用的数据量、消费者处理数据的方式,有时还取决于其他服务的延迟。在需要耗费时间来处理每个记录的应用程序中,可以通过max.poll.records来限制返回的数据量,从而限制应用程序在再次调用poll()之前的等待时长。但是,即使设置了max.poll.records,调用poll()的时间间隔仍然很难预测。于是,设置max.poll.interval.ms就成了一种保险措施。它必须被设置得足够大,让正常的消费者尽量不触及这个阈值,但又要足够小,避免有问题的消费者给应用程序造成严重影响。这个属性的默认值为5分钟。当这个阈值被触及时,后台线程将向broker发送一个“离开群组”的请求,让broker知道这个消费者已经“死亡”,必须进行群组再均衡,然后停止发送心跳。
request.timeout.ms
这个属性指定了消费者在收到broker响应之前可以等待的最长时间。如果broker在指定时间内没有做出响应,那么客户端就会关闭连接并尝试重连。它的默认值是30秒。不建议把它设置得比默认值小。在放弃请求之前要给broker留有足够长的时间来处理其他请求,因为向已经过载的broker发送请求几乎没有什么好处,况且断开并重连只会造成更大的开销。
auto.offset.reset
这个属性指定了消费者在读取一个没有偏移量或偏移量无效(因消费者长时间不在线,偏移量对应的记录已经过期并被删除)的分区时该做何处理。它的默认值是latest,意思是说,如果没有有效的偏移量,那么消费者将从最新的记录(在消费者启动之后写入Kafka的记录)开始读取。另一个值是earliest,意思是说,如果没有有效的偏移量,那么消费者将从起始位置开始读取记录。如果将auto.offset.reset设置为none,并试图用一个无效的偏移量来读取记录,则消费者将抛出异常。
enable.auto.commit
**这个属性指定了消费者是否自动提交偏移量,默认值是true。**你可以把它设置为false,选择自己控制何时提交偏移量,以尽量避免出现数据重复和丢失。如果它被设置为true,那么还有另外一个属性auto.commit.interval.ms可以用来控制偏移量的提交频率。本章后续部分将深入介绍与提交偏移量相关的其他内容。
partition.assignment.strategy
我们知道,分区会被分配给群组里的消费者。PartitionAssignor根据给定的消费者和它们订阅的主题来决定哪些分区应该被分配给哪个消费者。Kafka提供了几种默认的分配策略。
区间(range)
这个策略会把每一个主题的若干个连续分区分配给消费者。假设消费者C1和消费者C2同时订阅了主题T1和主题T2,并且每个主题有3个分区。那么消费者C1有可能会被分配到这两个主题的分区0和分区1,消费者C2则会被分配到这两个主题的分区2。因为每个主题拥有奇数个分区,并且都遵循一样的分配策略,所以第一个消费者会分配到比第二个消费者更多的分区。只要使用了这个策略,并且分区数量无法被消费者数量整除,就会出现这种情况。
轮询(roundRobin)
这个策略会把所有被订阅的主题的所有分区按顺序逐个分配给消费者。如果使用轮询策略为消费者C1和消费者C2分配分区,那么消费者C1将分配到主题T1的分区0和分区2以及主题T2的分区1,消费者C2将分配到主题T1的分区1以及主题T2的分区0和分区2。一般来说,如果所有消费者都订阅了相同的主题(这种情况很常见),那么轮询策略会给所有消费者都分配相同数量(或最多就差一个)的分区。
黏性(sticky)
设计黏性分区分配器的目的有两个:一是尽可能均衡地分配分区,二是在进行再均衡时尽可能多地保留原先的分区所有权关系,减少将分区从一个消费者转移给另一个消费者所带来的开销。如果所有消费者都订阅了相同的主题,那么黏性分配器初始的分配比例将与轮询分配器一样均衡。后续的重新分配将同样保持均衡,但减少了需要移动的分区的数量。如果同一个群组里的消费者订阅了不同的主题,那么黏性分配器的分配比例将比轮询分配器更加均衡。
协作黏性(cooperative sticky)
这个分配策略与黏性分配器一样,只是它支持协作(增量式)再均衡,在进行再均衡时消费者可以继续从没有被重新分配的分区读取消息。可以参考4.1.2节了解更多有关协作再均衡的内容。需要注意的是,如果你从Kafka 2.3之前的版本开始升级,并希望使用协作黏性分配策略,则需要遵循特定的升级路径,具体请参看相关升级指南。
可以通过partition.assignment.strategy来配置分区策略,默认值是org.apache.kafka.clients.consumer.RangeAssignor,它实现了区间策略。你也可以把它改成org.apache.kafka.clients.consumer.RoundRobinAssignor、org.apache.kafka.clients.consumer.StickyAssignor或org.apache.kafka.clients.consumer.CooperativeStickyAssignor。还可以使用自定义分配策略,如果是这样,则需要把partition.assignment.strategy设置成自定义类的名字。