调优Kafka集群
在软件工程领域,非功能性需求是依照某些条件判断系统运行情形或特性,而不是针对系统特定行为的需求,常见非功能需求如下
-
性能:最重要的非功能需求之一,大多数生产环境对集群性能有着严格的要求,不同的系统对于性能有不同的诉求,对于Kafka而言,性能一般指吞吐量和延时两方面
-
吞吐量:broker或clients应用程序每秒能处理多少字节或消息
-
延时:通常指producer端发送消息到broker端持久化保存消息之间的时间间隔。该概念也用于统计端到端的延时,比如producer端发送一条消息到consumer端消费这条消息的时间间隔
-
-
可用性:某段时间内,系统或组件正常运行的概率或时间上的比率。业界一般用N个9来量化可用性,如"年度4个9"指系统可用性达到99.99%,即一年中系统宕机时间不超过53分钟
-
持久性:确保已提交操作产生的效果会被永久保持,即使系统出现崩溃,对Kafka来说,持久性意味着已提交的消息需要被持久化到broker底层物理日志而不能发生丢失
Kafka集群调优流程,通常是一个迭代过程,需要用户不断地优化系统设置、参数配置甚至应用架构,直到满足预期目标
确定调优目标
实现非功能性目标的第一步就是确定调优目标,确定目标后才能明确调优的方向,我们需要从以下4个方面来考量调优目标:吞吐量、延时、持久性、可用性。明确目标后才能做出取舍,因为调优目标彼此之间可能是矛盾的,要根据需求明确目标,做出权衡选择。例如Kafka吞吐量和延时就是一对矛盾指标,假设produce每发送一条消息需要花费2毫秒,那么producer的吞吐量就是500条/秒,吞吐量与延时关系似乎可以用TPS=1000/Latency(毫秒)来表示,但实际并非如此。假设仍然以2毫秒延时发送消息,每次只发送一条,TPS就是500条/秒,但如果producer按批发送,假设producer每次发送前会等待8毫秒,8毫秒后producer缓存了1000条消息,总延时变为10毫秒,此时TPS等于1000/0.01=100000 条/秒,可见延时增加4倍,TPS却增加近200倍
上面场景可以看出批次化及微批次化能大幅增加吞吐量,实际场景中通过增加较小延时换取TPS的显著提升是不错的选择。在Kafka中producer端可以通过参数linger.ms设置等待时间,producer积累消息仅仅指将消息发送到内存中的缓冲区。
集群基础调优
配置合理的操作系统参数能显著提升Kafka集群性能、阻止错误发送,OS级错误总是会降低系统性能,甚至影响其他非功能性需求指标,Kafka中经常碰到的操作系统级别错误可能包括
-
connection refused
-
too many open files
-
address in use: connect
禁止atime更新
由于Kafka大量使用物理磁盘进行消息持久化,文件系统的选择是重要的调优步骤,对Linux系统上任何文件系统,Kafka都推荐用户挂载文件系统时设置noatime,取消文件atime属性更新,避免inode访问时间的写入操作,极大减少文件系统写操作数,提升集群性能,用户可以使用mount -o noatime命令进行设置
Linux平台当前有很多文件系统,最常见的便是EXT4和XFS,EXT4由EXT3演变而来,EXT4目前是大部分Linux发行版本的默认文件系统,由于EXT4是最标准的文件系统,EXT4的适配性是最好的,兼容性EXT4也要优于其他文件系统
XFS作为高性能、高伸缩的64位日志文件系统,特别适用于生产服务器,特别是大文件操作,很多存储类的应用都适合XFS作为底层文件系统
以上两种文件系统都能很好的与Kafka集群进行适配,使用时每一种文件系统都有一些特定的配置。对于EXT4用户而言,Kafka建议设置以下选项
-
设置data=writeback:默认data=ordered,所有数据在其元数据被提交到日志前,都必须依次保存到文件系统;data=writeback则不需要维持写操作顺序。数据可能会在元数据提交之后才被写入文件系统,这是提升吞吐量的好方法,同时也维持了内部文件系统的完整性。但是该选项如果文件系统从崩溃恢复后过期数据可能出现在文件中,不过对于不执行覆盖操作且默认提供最少一次处理语义的Kafka而言,这是可以容忍的,用户需要修改/etc/fstab和使用tune2fs命令来设置该选项
-
禁掉记日志操作:日志化是一个权衡,它能极大降低系统从奔溃中恢复的速度,同时也引入了锁竞争导致写操作性能下降。对于不在乎启动速度但想降低写操作延时的用户而言,禁止日志化是一个不错的选择。可以执行tune2fs -O ^has_journal <device_name>来禁止journaling
-
commit=N_secs:该选项设置每N秒同步一次数据和元数据,默认5秒。该值如果设置较低,可以减少崩溃发生时带来的数据丢失;若设置较大,会提升整体吞吐量以及降低延时。鉴于Kafka已经在软件层面提供冗余机制,故实际生产环境中推荐用户设置一个较大值,如1~2分钟
-
nobh:只有当data=writeback时该值才生效,它将阻止缓存头部与数据页文件之间的关联,进一步提升吞吐量。可以通过修改/etc/fstab中的mount属性,如noatim,data=writeback,nohub,errors=remount-ro设置
对于XFS,推荐以下参数
-
largeio:该参数影响stat调用返回的I/O大小,对于大数据量的磁盘写入操作而言,能提升一定性能,largeio时标准的mount属性,可使用与nobh相同设置方式
-
nobarrier:禁止使用数据块层的写屏障(write barrier)。大多数存储设备底层都提供基于电池的写缓存,设置nobarrier可以禁用阶段性的"写冲刷"操作,从而提高写性能。自RHEL6开始,nobarrier已不推荐,因为write barrier对系统的性能几乎可以忽略不计,启用write barrier带来的收益大于其负面影响。对于RHEL5用户,可以考虑设置此mount选项
设置swapiness
一般在Linux发行版本中将该值默认设置为60,该值越低,表示尽量多的使用物理内存,如果使用交换分区则会影响系统性能,但并不建议将该值设置为0。如果Kafka用掉了所有物理内存,用户还可以通过swap定位应用并及时处理。但如果完全禁用掉swap,当系统耗尽所有内存,Linux OOM killer将会开启并根据一定规则选取一个进程杀掉,这个过程对用户不可见。这就意味着当出现OOM时可能丢失一些进程数据。因此我们禁用swap前提是要确保永远不会出现OOM,但对于Kafka集群而言,通常是无法保证的。建议将swap限定在1~10之间。临时修改swapiness可以使用sudo sysctl vm.swappiness=N;永久生效则需要修改/etc/sysctl.conf文件增加vm.swappiness=N,然后重启机器
JVM设置
Kafka并未大量使用堆上内存,而是使用堆外内存,因此不需要为Kafka设置太大的堆空间,生产环境中6GB通常就足够了,参照领英1500+台的Kafka集群规模,其JVM设置也是6GB堆大小,同时垃圾回收器推荐使用G1,以下是一份调优后的JVM配置清单
-Xmx6g -Xms6g -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=128m -XX:+UseG1GC -XX:MaxGCPauseMillis= 20
-XX:InitiatingHeapOccupancyPercent= 35 -XX:G1HeapRegionSize=16M -XX: MinMetaspaceFreeRatio=50
-XX:MaxMetaspaceFreeRatio=85
其他调优
使用Kafka的用户有时候会碰到"too many fies open"错误,这需要broker所在机器调优最大文件部署符上限。可参考如下公司:broker上可能的最大分区数 *(每个分区平均数据量/平均日志段大小 + 3),3指索引文件的个数。假设某个broker规划要放置最多20个分区,每个分区总的数据量大致在100GB,每个日志段大小为1GB,则这台broker所在机器最大文件部署符大小大概为20 * (100 / 1 + 3) = 2060,broker所在机器还会打开多个Socket资源,实际都会将该值设置的很大,如100000
在实际线上Linux环境中,如果单台broker上topic数过多,用户可能碰到OOM: Map failed的严重错误,这是因为大量创建topic将极大消耗操作系统内存,用于内存映射操作。在这种情况下用户需要调整vm.max_map_count参数,可以使用/sbin/sysctl -w vm.max_map_count = N来设置,该参数默认值为65536,可以为线上环境设置更大的值
如果broker所在机器有多块物理磁盘,推荐配置Kafka全部使用这些磁盘,即设置broker端参数log.dirs指定所有磁盘上的不同路径,这样Kafka可以同时读/写多块磁盘上数据,以提升系统吞吐量,当前Kafka根据每个日志路径上分区数而非磁盘容量做负载均衡,实际生产环境中容易出现磁盘A有大量剩余空间但Kafka却将新增分区日志放置到磁盘B情形,用户需要实时监控各个路径上分区数,尽量保证不要出现过度倾斜,如发生上述情形,用户需要执行bin/kafka-ressign-partitions.sh脚本,手动的分区迁移把占用空间多的分区移动到其他broker上来缓解这种不平衡
调优吞吐量
调优分区数
要调优TPS,需要同时调优producer、broker、consumer,以便在相同时间内传输更多数据。Kafka基本的并行单元是分区,producer在设计是要求能同时向多个分区发送消息,这些消息也要能被写入多个broker中供多个consumer同时消费,通常分区数越多TPS就越高,但并非无限制增加分区
过多的分区可能导致server/clients端占用更多的内存,producer默认使用缓冲区为每个分区缓存消息,一旦满足条件producer会批量发出缓存的信息。由于该参数是分区级别,因此如果分区很多,这部分缓存的内存占用也会变大;在broker端,每个broker内部都维护了很多分区级别的元数据,如controller、副本管理器、分区管理器等,分区数越多,缓存成本越大
每个分区在底层系统都有专属目录,除3个索引文件外还会保存日志段文件。通常生产环境日志段文件可能有多个,保守估计一个分区占用十几个甚至几十个句柄,当Kafka打开文件便不会显示关闭文件,因此文件句柄不会被释放,随着分区数的增加,系统文件句柄数也会相应增长
每个分区通常会有若干个副本,不同副本保存在不同broker上,当leader副本挂掉,controller会自动检测到,在ZooKeeper帮助下选择新的leader。若分区数很多,当broker挂掉后,需要进行leader选举的分区数就会很多。而controller是单线程处理事件,所以controller只能一个一个地处理leader变更请求,可能会拉长整体系统恢复时间
用户需要结合自身的实际环境基于吞吐量等指标进行一系列测试来确定需要多少分区数。用户可以遵循下面的步骤来尝试确定分区数
-
创建单分区topic,在实际生产机器上分别测试producer和consumer的TPS,分别为Tp和Tc
-
目标TPS是Tt,分区是大致可以确定为Tt/max(Tp, Tc)
Kafka提供专门的脚本kafka-producer-perf-test.sh和kafka-consumer-perf-test.sh用于计算Tp和Tc。测试topic的TPS很容易,只需要将消息发送到broker就好。但测试consumer端TPS则与应用关系很大,应用处理消息的逻辑越快,TPS也会越高。测试consumer TPS需要使用真实的消息处理逻辑,才能准确反映线上环境
producer端调优
producer是批量发送消息,它会将消息缓存起来在一个发送请求中统一发送。我们可以通过调优批量发送的性能参数:批次大小、批次发送间隔,即Java版本producer参数batch.size和linger.ms调优吞吐量。通常增加这两个参数值都会提升producer端TPS,更大的batch size可以令更多的消息封装进同一个请求,发送给broker端总请求数减少,producer的负载减少,broker端CPU请求处理开销也降低了;更大linger.ms使producer等待更长时间才发送消息,能缓存更多的消息填满batch,提升整体的TPS,但这样也会导致消息的延迟增加
producer端comperssion.type也是调优TPS的重要手段。对消息进行压缩可以极大减少网络传输量,降低网络I/O开销,从而提升TPS。压缩是针对batch操作,batch效率直接影响压缩率,一般batch缓存消息越多,压缩率越好。当前Kafka支持GZIP、Snappy、LZ4等压缩
producer发送消息给broker时,消息被发送到对应分区leader副本所在broker上。默认情况下,producer会等待leader broker返回发送结果,这时才能知晓这条消息是否发送成功,consumer端只能消费那些已发送成功的消息。等待leader返回发送消息结果也会影响producer端TPS,lead broker返回结果越快,producer就能更快发送下一条消息。producer端可以通过acks控制这种行为,默认值为1表示leader broker把消息写入底层文件系统即返回,无需等待follower副本应答。用户也可以将acks设置为0,表示producer端不需要broker端的响应即开启下一条消息发送,这种设置是以牺牲消息持久化为代价,提升producer的TPS
当设置acks不等于0,一旦发送失败,producer端会根据retries参数设置的值进行指定次数的重试。如果应用程序能忍受偶发的消息丢失,可以将reties设置为0,producer TPS也会提升,但需要用户显示捕获leader broker发回的异常自行处理发送失败
对于Java版本producer而言,其会创建一定大小的缓冲区来缓存消息。当缓冲区被填满,producer将立即进入阻塞状态直到有空闲内存被释放,这段阻塞等待时间最长不会超过producer端参数max.block.ms设置的值,一但超过该值producer会抛出TimeoutException,因此确保不会抛出此异常的关键在于设置合理的缓存区大小,默认该值大小为32MB,通常用户是不需要调整的,但如果实际使用过程中发现producer在高负载情况下经常抛出TimeoutException,则需要考虑增加此参数的值。由于Java版producer中KafkaProducer是线程安全的,在生产环境中可能多个线程共享一个KafkaProducer实例,缓存区更容易被快速填满,这种情况就更需要增加buffer.memory了。增加此值后,producer阻塞情况将得到缓解,比之前缓存更多分区数据,整体上提升TPS
对于Java版本consumer,用户可以调整leader副本所在broker每次返回的最小数据量间接影响TPS,通过consumer端fetch.min.bytes可设置。该参数指定leader副本每次返回consumer的最小数据字节数,通过增加该参数值,Kafka broker端会为每个FETCH请求的response填入更多数据,以减少网络开销提升TPS。但在提升TPS的同时也增加了consumer延时,这是因为增加该参数后,broker端必须花费更多时间积累足够数据返回
在机器和资源足够情况下,可以运行多个consumer实例共同消费多分区数据,能显著提升consumer端TPS,推荐启动与待消费分区数相同的实例数,以保证每个实例都能分配一个具体的分区进行消费
对于broker建议用户增加参数num.replica.fetchers的值,该值控制broker端follower副本从leader副本处获取消息的最大线程数。默认1表示follower副本只使用一个线程去拉取leader的最新消息。对于将ack=all的producer,主要延时可能都在follower与leader同步的过程,增加该值能缩短同步的时间间隔,间接提升producer端TPS
JVM垃圾回收对TPS的影响。用户需要特别关注GC的停顿时间,确保不要经常性的长停顿,如果使用的是CMS垃圾收集器,确保不要频繁抛出concurrent mode failure错误;如果使用G1垃圾收集器,需要确保不出现Evacuation Failure。这两种情况都将导致GC采用单线程进行一次Full GC,此时所有的线程都将被暂停,包括Kafka的所有线程,极大降低TPS。并且对于老版本的consumer更加显著,因为老版本consumer依赖ZooKeeper来管理consume信息,长时间GC会导致ZooKeeper会话超时,导致对分组进行rebalance
综上所诉
-
broker端
-
适当增加num.replica.fetchers,但不要超过CPU核数
-
调优GC避免经常性Full GC
-
-
producer端
-
适当增加batch.size
-
适当增加linger.ms
-
设置compression.type=lz4
-
acks=0或1
-
retries=0
-
若多线程共享producer或分区数很多,增加buffer.memory
-
-
consumer端
-
采用多consumer实例
-
增加fetch.min.bytes
-
调优延时
从不同角度看延时的定义是不一样的。在producer看来,延时主要是producer发送PRODUCE请求到broker端返回请求response的时间间隔;对于consumer而言,延时主要是consumer发送FETCH请求到broker端返回请求response的时间间隔;对于消息发送端与消息消费端而言,延时指从producer发送消息到consumer收到消息的时间间隔
适当增加分区数会提升TPS,但大量分区的却会大幅增加延时,分区数越多,导致broker端需要更多时间实现follower与leader的同步。当acks=all时,producer端需要等到broker端所有follower都实现同步之后接收到leader broker的反馈信息才算完成消息发送,而consumer端是无法消费未提交成功的消息,这样既增加了producer端延时又增加了consumer端延时。若要调优延时,则必须限制单台broker上的总分区数
-
不要创建有超多分区的topic
-
适当增加集群broker数分散分区
-
增加num.replica.fetchers参数提升broker端I/O并行度
调优延时要求producer端尽量不要缓存信息,而是尽快将消息发送出去,这意味着最好将linger.ms参数设置为0,不要让producer花费额外时间去缓存待发送消息
不设置压缩类型,压缩是时间换空间的一种优化方式,为减少网络I/O传输,推荐启用消息压缩,但为降低延时,不推荐启用消息压缩
producer端acks参数也是优化延时重要手段之一,leader broker越快地发送response,producer端就能越快的发送下一批消息。该参数设置为1已是一种不错的设置,但如果用户对于延时有较高要求,并可以容忍偶发的消息发送丢失,可以考虑将acks设置为0,这种情况下producer不会关心broker端的response,便进行下一批消息的发送
consumer端用户需要调整leader副本返回的最小数据量来间接影响consumer延时,即fetch.min.bytes参数,对于延时来说,默认值1已是一个不错的配置
综上
-
broker端
-
适度增加num.replica.fetchers
-
避免创建过多topic分区
-
-
producer端
-
设置linger.ms=0
-
设置compression.type=none
-
设置acks=1或0
-
-
consumer端
- 设置fetch.min.bytes=1
调优持久性
持久性定义了Kafka集群中消息不容易丢失的程度,持久性越高表明Kafka越不会丢失消息,持久性通常由冗余来实现,而Kafka实现冗余手段就是备份机制,保证kafka每条消息会保存在多台broker上,这样即使单台broker崩溃,数据依然可用
对于有高持久性需求的用户来说,保证topic数据不丢失最主要的设置就是设置topic的备份数,根据Hadoop的三备份原则,用户可以设置数为3,保证即使在两台broker奔溃情况下依然不会造成数据丢失。除创建topic指定副本数,Kafka默认支持自动创建topic,当producer向一个不存在的topic发送消息,Kafka首先创建这个topic,分区数和副本数有broker端参数num.partitions和default.replication.factor指定,这两个参数默认值都是1,因此如果用户有自动创建topic场景,推荐首先在server.properties文件设置这两个参数值。用户也可以通过auto.create.topic.enable=false,禁止自动创建topic
新版本consumer已把位移信息从ZooKeeper移到内部topic __consumer_offsets,虽然此内置topic副本数也受default.replication.factor约束,但在0.11.0.0版本之前这种约束不是强制的。在0.11.0.0版本之前即使当前broker数小于default.replication.factor,__consumer_offsets也可以创建,并且设置其副本数为broker数,在0.11.0.0之前需要确保在开始消费前保证broker数不小于default.replication.factor。在0.11.0.0之后Kafka会强制要求__consumer_offsets创建时必须满足default.replication.factor参数指定的副本数才能创建
高持久性与acks的设置息息相关,acks的设置对于调优TPS和延时都有一定作用,但acks参数最核心的功能是控制producer的持久性。需要达到最高持久性需要设置acks=all或-1,强制leader副本等待ISR中所有副本都响应消息后发送response给producer。ISR副本全部响应消息写入表示ISR中所有副本都已将消息写入日志,只要ISR还有副本存活消息就不会丢失
producer发送失败后,producer视错误情况有选择性的自动重试发送消息,由于网络抖动造成发送消息失败,一个较大的retries值能更好规避这种瞬时问题。但重试次数设置较大也有副作用
当producer重试时,待发送消息可能已经发送成功。假设网络在消息被写入到broker底层日志与broker发送response给producer之间发生故障,response不能顺利返回给producer,导致producer重复发送消息,结果一条消息被写入多次。对于这种情况一种方式是consumer端做幂等处理,但这样会增加系统复杂性;另一种方式,对于0.11.0.0版本之后,Kafka提供幂等性producer,通过设置enable.idempotence=true开启幂等producer可以实现精确一次处理语义
由于重试发生的时机不固定,可能出现这种情况,当producer发送消息m1和m2,m1写入失败但m2写入成功,当producer重试m1发送成功后,m1就位于m2后面,造成消息乱序,对于有顺序要求的应用而言,可以设置max.in.flight.requests.per.connection=1来规避这个问题,此参数可控制producer在单个broker连接上任意时刻只处理一个请求,若管道中存在未完成请求, producer不会发送新的请求,设置该参数可能会拉低producer端TPS
unclean.leader.election.enable参数控制当broker端发生奔溃是,若ISR副本所在broker全部宕机时是否从非ISR副本中选举leader。此参数设置为true可以保证kafka的高可用性,但却可能造成消息丢失,毕竟未完成与leader副本同步的非ISR副本消息是落后与leader副本的。在0.11.0.0默认此参数是true,但随着人们对数据安全性和完整性越来越严格,0.11.0.0之后此参数默认为false
min.insync.replicas参数设置某条消息成功写入必须等待响应完成的最少ISR副本数,该参数虽然是在broker端配置,但却必须配合producer端acks设置为all或-1才能生效。实际场景中推荐设置acks=all或-1,若replication-factor=3,可设置min.insync.replicas=2
自0.10.0.0开始,Kafka仿照Hadoop引入机架属性信息(rack),通过broker.rack设置,用户为每台broker设置机架信息,Kafka集群后台收集所有机架信息并创建分区时根据机架信息将分区分散到不同机架上,这样即使某个机架所有机器都宕机。数据持久性依然能得到保证
log.flush.interval.ms和log.flush.interval.message两个参数,分别从时间维度和空间维度,设置Kafka将消息刷到磁盘的时机。前者表示Kafka多长时间执行一次消息落盘;后者设置Kafka写入多少条消息后执行落盘操作。默认log.flush.interval.ms是空,log.flush.interval.message为Long.MAX_VALUE,表明Kafka不会自动执行消息落盘,而是将这个操作交有操作系统来完成,由OS控制页缓存数据到物理文件的同步
consumer端控制持久性的主要手段是设置位移提交的方式。位移决定了consumer的消费进度,因此何时提交位移就很重要,consumer不能在消息处理前提交位移,一旦consumer提交消息后但后续处理消息奔溃,将导致consumer重启后无法再消费该消息,造成消息丢失。建议用户关闭自动提交位移,设置auto.commit.enable=false。默认该参数为true,表示consumer会定期自动提交位移,手动提交建议用户使用commitSync提交位移,而不是commitAsync方法
综上
-
broker端
-
unclean.leader.election.enable=false
-
auto.create.topic.enable=false
-
replication.factor=3, min.insync.replicas=replication.factor-1
-
default.replication.factor=3
-
broker.rack属性分散分区到不同机架
-
设置log.flush.interval.message和log.flush.interval.ms为一个较小值
-
-
producer端
-
acks=all或-1
-
retries设为一个较大值,如10~30
-
设置max.in.flight.requests.per.connection=1,保证消息顺序性
-
enable.idempotence=true启用幂等性
-
-
consumer端
-
auto.commit.enable=false
-
消息消费成功后调用commitSync提交位移
-
调优可用性
可用性反映出Kafka集群对应对奔溃的能力。无论broker、producer、 consumer发生崩溃,Kafka服务依然能保持可用状态。调优可用性就是要让Kafka更快地从崩溃中恢复。分别从topic、producer、broker、consumer讨论如何调优可用性
topic分区数并非越多越好,过多的分区数将导致leader副本选举便慢,从而恢复的时间就越慢。当leader副本所在broker发生故障,Kafka会进行leader选举,正常情况leader选举时间很短,大概几毫秒,但controller处理请求是单线程,大量的leader选举请求将会进行排队,逐一处理,并且在leader副本未选出,topic为恢复正常工作前producer、consumer都是无法工作的。因此分区数越多只会拖慢恢复可用状态的时间
producer端,acks设置为all或-1,broker端参数min.insync.replicas的设置值会影响producer端的可用性,该参数越大,Kafka会强制越多的follower副本同步写入日志,当出现ISR缩减到小于min.insync.replicas时,producer停止对对应分区发送消息。如果该参数设置的很小,则producer能容忍更多的副本被踢出ISR,只要剩余的min.insync.replicas即可
broker端,broker奔溃后leader选举有两种:1.从ISR选举 2.根据unclean.leader.election.enable决定是否从非ISR副本中选举leader,若为true将能保证Kafka始终可以选举出leader副本恢复到可用状态,但用户需要能承受带来的数据丢失。另一个重要参数num.recovery.threads.per.data.dir参数能控制broker加载磁盘日志的线程数。当broker崩溃重启后,broker首先扫描并加载底层的分区数据执行清理和与其他broker的同步任务,这一过程被称为日志加载或日志恢复,默认每个broker只会使用一个线程来做日志恢复,但broker端log.dirs可以配置多个日志目录,每个日志目录加载互不影响,如果设置多个线程并行加载日志文件,将大幅缩短加载日志时间,提升服务从奔溃中恢复的速度。建议该参数设置为broker机器的物理磁盘数
consumer端高可用性由组管理的consumer group实现,当group下某个或某些consumer挂掉了,group coordinator能够自动检测到崩溃并开始rebalance将这些崩溃consumer负责消费的分区分配给其他存活的consumer实例。通过session.timeout.ms可以设置coordinator检查出崩溃的时间不会超过此参数设置值。为了实现高可用,可以将此参数设置的较低,如5~10秒
consumer挂掉其实分为两种情况,一种是崩溃,如consumer实例所在机器掉电或外部kill -9,coordinator只能保证在session.timeout.ms时间段内检测出这种情况,第二种是软件或consumer应用问题导致,比如消息处理时间过长导致超时,此时consumer停止发送心跳,并显示告知coordinator它要离开组,对于这种情况用户可以增加max.poll.interval.ms参数给consumer更多的时间处理消息,从而维护consumer高可用性,此参数在0.10.1.0引入对于之前的版本需要将max.partition.fetch.bytes设置的小一些
综上
-
broker端
-
避免创建过多分区
-
unclean.leander.election.enable=true
-
min.insync.replicas=1
-
num.recovery.threads.per.data.dir=broker端参数log.dirs中设置的目录数
-
-
producer端
- acks=1,若设置为all,则遵循上面broker端的min.insync.replicas配置
-
consumer端
-
设置session.timeout.ms为较低值,如10000
-
0.10.1.0及之后版本,设置max.poll.interval.ms比消息平均处理时间稍大
-
0.10.1.0之前版本,设置max.poll.records和max.partition.fetch.bytes减少consumer处理消息的总时长,避免频繁rebalance
-