Kafka严重依赖文件系统来存储和缓存消息,所有到来的数据都会立即写入日志,但是不一定刷新到磁盘,正常会写入内核的Page Cache
中,现代操作系统会尽量利用物理内存空间来建立文件系统缓存,同时在回收时也几乎没有性能损失。
对于Kafka的堆内存空间设置不应该太大,任何时候都不要超过6GB,应该将大部分内存留给文件系统缓存使用,堆内存用来保存临时的读取写入缓冲,可以基于缓冲时间大致估算需要的堆内存空间,推荐值是设置为4GB。
建议Kafka部署的节点至少具有64GB内存,较小的内存会带来过多的交换导致性能降低,同等条件下选择较少数量的大内存机器(64~128GB)比选择较多数量的低内存机器(8~32GB)要更具备优势。
Kafka对CPU的要求不高,在启用SSL的情况下CPU的占用会高很多,建议普通集群部署中使用2颗12核24线程的机器,同等条件下选择较多核的CPU要比主频更高的CPU带来的提升更大,多核可以快速提高Kafka的并发性,但是高主频带来的提升很小。
尽量使用多个存储设备来提升吞吐量,并且不要让其他程序和Kafka共用同一块存储设备,否则延迟会提高,实际配置中存储设备的大小和规格尽量一致,Kafka中每个Partition只会分布在1个目录中,所以在多个Topic的情况下新的分区会自动选择当前分区比较少的设备创建,最终保持整体的平衡,所以要比较精细地根据业务进行调整。如果Topic数量只有1个或很少,也可以将分区数量和设备数量配置成相同的,但是这样会导致1个节点故障出现多个分区不可用的情况,需要提升副本数量来保证可用性,其实和RAID的原理是相似的。
一定不要使用NAS等网络存储,NAS通常很慢,延迟很大并且可靠性低,而且容易出现单点故障,导致整个系统的稳定性降低,所以要避免使用网络存储。
快速而且可靠的网络是分布式系统中必不可少的基础设施,低延迟可以保证节点实时通信,高带宽有助于生产和消费的吞吐、分片复制和恢复等,现代数据中心中大多配备10Gbps(万兆)的网络,完全可以满足Kafka的需求,根据不同业务场景的要求也不同,但是最低带宽也不要小于1Gbps(千兆)。
文件系统选择常规的ext4或者xfs都可以,推荐ext4
Kafka集群不建议采用过多的小型机器构建比较大的规模,因为规模比较大的时候,开销会非常明显。同时不建议使用太高配的机器,会导致资源不平衡或者浪费,比如很多CPU都在空闲着。
按照基础环境配置中的内核参数调优,调整Kafka的最大文件数以及mmap数量,在Kafka中所有的.index
文件都会被建立mmap映射,可以进入Kafka的数据目录统计当前至少产生的文件映射数量:
# 假设数据目录是:/data/kafka-logs
cd /data/kafka-logs
find . -name '*index' | wc -l
服务器在开启交换分区的情况下,如果文件系统缓存页面使用过多,操作系统不会优先淘汰页面,而是可能会使用交换空间,由于磁盘和内存的巨大差距,频繁换页会带来较大的性能开销,可以关闭分区或者降低交换倾向,通过参数内核vm.swappiness
可以控制交换分区的激活时机,默认是60,表示内存可用空间低于60%时就会启动交换分区,对于服务器这显然不太合适,建议设置为0以禁用交换:
sysctl -w vm.swappiness=0 >> /etc/sysctl.conf
# 查看修改的文件内容
sysctl -p
禁用交换会提升Kafka集群整体的性能。
为了保证高可用性和副本容错性,建议默认复制因此至少为2,避免客户端自动创建Topic时只产生1个副本,即使其中1个节点出现故障甚至数据全部丢失,也可以从副本节点中恢复数据。
消费者的偏移量默认保存在名为__consumer_offsets
的Topic中,这些元数据占用的空间不大,单独使用参数offsets.topic.replication.factor
来指定复制因子,对于消费者启动时会先读取元数据中的消费者组的偏移状态,如果此时存在节点故障,无法读取到完整的元数据,那么即使数据可用,也是无法消费的,所以这个值在生产环境集群规模大于3个的情况下至少要配置为3,从而确保较高的可用性。
通常1个节点分配1~2个分区,但是如果机器的CPU核数较多,可以支撑更多的并发,则可以适当提升分区数量,同时注意硬盘I/O的开销,如果硬盘读写存在瓶颈,过多的分区会带来更大的延迟,如果是多个存储设备的情况下可以配置多个分区,但注意分区不要过多,否则Kafka的响应也会降低。
每个目录的线程数用于在启动时读取数据恢复日志以及在停止服务时将数据刷新到磁盘使用,默认每个目录只有1个,如果数据目录对应的底层是RAID,可以增大这个值提升读取或写入的效率。
在Kafka同一个分区的多个副本之间,也存在leader和follower的关系,所有的follower都会从leader实时拷贝消息,消息fetcher的线程数由当前参数控制,默认为1,建议在生产环境中副本较多的情况下调大从而提升复制的吞吐量以及同步的实时性,例如修改为4.
Reference: