历史性难题——如何为Kafka挑选合适的分区数?
如何为Kafka挑选合适的分区数?很多人都为这个问题伤过脑筋。
从吞吐量方面考虑,增加合适的分区数可以很大程度上提升整体吞吐量,但是超过对应的阈值之后吞吐量不升反降。如果应用对吞吐量有着一定程度上的要求,建议在投入生产环境之前对同款硬件资源做一个完备的吞吐量相关的测试,以找到合适的分区数阈值期间。
在创建完主题之后,虽然我们还是能够增加分区的个数,但是基于key计算的主题需要严谨对待。当生产者向Kafka中写入基于key的消息时,Kafka通过消息的key来计算出消息将要写入到哪个具体的分区中,这样具有相同key的数据可以写入到同一个分区中。Kafka的这一功能对于一部分应用是即为重要的,比如日志压缩。
再比如对于同一个key的所有消息,消费者需要按消息的顺序进行有序的消费,如果分区的数量发生变化,那么有序性就得不到保证。在创建主题时,最好能够确定好分区数,这样也可以省去后期增加所带来的多余操作。尤其对于与key高关联的应用,在创建主题时可以适当地多创建一些分区,以满足未来的需求。通常情况下,可以根据未来2年内的目标吞吐量来设定分区数。当然如果应用与key弱关联,并且也具备便捷的增加分区数的操作接口,那么也可以不用考虑那么长远的目标。
有些应用场景会要求主题中的消息都能保证顺序性,这种情况下在创建主题时可以设定分区数为1,这样通过分区有序性的这一特性来达到主题有序性的目的。
当然分区数也不能一昧地增加,分区数会占用文件描述符,而一个进程所能支配的文件描述符是有限的,这个也是我们通常意义上所说的文件句柄的开销。虽然我们可以通过修改配置来增加可用文件描述符的个数,但是凡事总有一个上限,在选择合适的分区数之前,最好再考量一下当前Kafka进程中已经使用的文件描述符的个数。
分区数的多少还会影响系统的可用性。
Kafka通过多副本机制来实现集群的高可用和高可靠,每个分区都会有一至多个副本,每个副本分别存在于不同的broker节点上,并且只有leader副本对外提供服务。在Kafka集群的内部,所有的副本都采用自动化的方式进行管理,并确保所有的副本中的数据都能保持一定程度上的同步。当broker发生故障时,对于leader副本所宿主的broker节点上的所有分区将会暂时处于不可用的状态,此时Kafka会自动的在其他的follower副本中选举出新的leader用于接收外部客户端的请求,整个过程由Kafka控制器负责完成。分区进行leader角色切换的过程中会变得不可用,不过对于单个分区来说这个过程非常的短暂,对于用户而言可以忽略不计。但是如果集群中的某个broker节点宕机,那么就会有大量的分区需要同时进行leader角色切换,这个切换的过程将会耗费一笔可观的时间,并且在这个时间窗口内这些分区也会变得不可用。
假如,一个3节点的Kafka集群中存在3000个分区,每个分区拥有3个数据副本。当其中一个broker节点宕机时,所有1000个分区同时变得不可用。假设每一个分区恢复时间是5ms,那么1000个分区的恢复时间将会花费5秒钟。因此,在这种情况下,用户将会观察到系统存在5秒钟的不可用时间窗口。可以适当地增加一些broker节点来减少单broker节点所负荷的分区,进而降低单broker节点故障引起的短期服务不可用的影响。
如果宕机的broker节点恰好又是Kafka集群的控制器时,在控制器被重新选举到新的broker节点之前这些分区leader角色切换的过程是不会开始进行的。虽说控制器的恢复(重新选举新的控制器)也是自动进行的,整体上不会有太大的问题,但是新的控制器需要加载集群中所有的元数据信息,其中就包括了所有的分区信息,分区数越多加载的耗时就会越长,进而拖慢了控制器的恢复进度,最终也就拖慢了分区服务的恢复进度。
分区数越多也会让Kafka的正常启动和关闭的耗时变得越长,与此同时,主题的分区数越多不仅会增加日志清理的耗时,而且在被删除时也会耗费更多的时间。对于旧版的生产者和消费者客户端而言,分区数越多也会增加它们的开销,不过这一点在新版的生产者和消费者客户端中有效地得到了抑制。
如何选择合适的分区数?
从某种意思来说,考验的是决策者的实战经验,更透彻地来说,是对Kafka本身、业务应用、硬件资源、环境配置等多方面的考量而做出的抉择。在设定完分区数,或者更确切的说是创建完主题之后,还要对其追踪、监控、调优以求更改更好的利用它。读者看到本文的内容之前或许没有对分区数有太大的困扰,可能看完之后反而困惑了起来,其实大可不必太过惊慌,一般情况下,根据预估的吞吐量以及是否与key相关的规则来设定分区数即可,后期可以通过增加分区数、增加broker或者分区重分配等手段来进行改进。如果一定要给一个准则的话,笔者给的一个建议是分区数设定为集群中broker的倍数,即假定集群中有3个broker节点,可以设定分区数为3、6、9等,至于倍数的选定可以参考预估的吞吐量。不过,如果集群中的broker节点数有很多,比如大几十或者上百、上千,这种准则也不太适用,在选定分区数时进一步的可以引入基架等参考因素。
对于这个问题,网上也有很多的资料,笔者也看过,由于版本更迭,现在只能赞同其中的部分内容。本文也是笔者对分区数抉择的小小认知,如果你对此问题有相同或者相反的意见,欢迎在留言区探讨。
欢迎工作一到五年的Java工程师朋友们加入Java程序员开发: 854393687
群内提供免费的Java架构学习资料(里面有高可用、高并发、高性能及分布式、Jvm性能调优、Spring源码,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多个知识点的架构资料)合理利用自己每一分每一秒的时间来学习提升自己,不要再用"没有时间“来掩饰自己思想上的懒惰!趁年轻,使劲拼,给未来的自己一个交代!