前言: 通常对于初创企业或者初创业务团队来说,对于开源组件的使用都会显的比较随意,而这种情况会随着业务量级的增长和时间的推移导致开源服务的滥用和乱用,进而造成的结果就是整体业务的稳定性和可靠性相对较差,而此时,扩容的行为是边际效应递减的,如果此时不对整体业务以及开源服务进行规划和改造,那么风险和成本将是同比增长的,因此在开始阶段,需要对开源组件,特别是分布式组件进行场景规划和调优。
在我过去的工作经历中,经历过类似服务的有Redis集群
,ElasticSearch
集群,虽然整体改造后并不一定将成本降到最低,但是可以将服务的可用性和可靠性提高很多,而且根据业务场景以及使用方式来规划集群后会使得整体的边际成本呈递减状态。
笔者目前所处的团队所管理的kafka集群
也处于该种状态,集群当前规模大约为20+ECS,总数据量大约400T,其中承接的Topic服务主要分为日志收集
、数据管道
、流式计算
、业务事件存储
几种大场景,我们需要知道,以上几种使用场景对于kafka集群的的可用性
,可靠性
,数据一致性
要求其实是不同的,如果将所有场景耦合到同一个集群,在数据量较大的情况下,任何的小异常点都可能造成整体服务受到影响,并且整个集群的恢复周期会很长,如果业务没有及时的降级策略很可能影响核心业务的处理。
鉴于以前对开源分布式服务的规划和改造经验,本篇文章将根据官方文档以及经验来分享一些关于Kafka生产集群规划和运维管理相关的知识.
一、Kafka集群运维和规划
其实任何开源的分布式系统在开始规划时,就需要考虑到业务场景,以及生产环境的周边可观测系统,比如如下几个方面:
-
规划和部署生产级别的集群(包含官方最佳实践以及一些针对不停场景推荐的配置项变更) -
执行一些部署后的操作(比如滚动重启集群,集群备份,数据迁移等等) -
集群的可观测性(监控重要统计数据,理解kafka内部行为的具体含义以及是否需要报警通知)
二、集群规划
本节主要介绍,kafka集群在生产环境部署前的一些规划,包含硬件配置选择,网络以及文件系统和其他考虑的选型.
1.硬件和OS
注意:
通常对于分布式的开源服务来将对于硬件本身没有太高的要求,但当需要承载一定量级的业务时,我们需要考虑一些硬件是否能够支撑对应的业务场景,并且通常来讲针对不同的业务场景选择不同的硬件(如果可选择),也许会适当降低资源成本。
1.0 OS
一般来说,对于运行Linux中的kafka集群不需要过多的OS以及kernel参数调整,但如下几种情况可以根据具体情况进行参考:
-
文件描述符(fd)
: broker节点上fd限制可以参考(number_of_partitions)*(partition_size/segment_size)
公式 -
套接字缓冲区(socket buffer)
: 该参数可以增加多数据中心之间的数据传输(一般异地集群备份建议调整以增加吞吐) -
最大内存映射区域数(vm.max_map_count)
: 当kafka broker节点拥有太多分区时应该密切关注系统级别的该参数,默认为65535。每一个日志段,分配的分区,都需要一对index/timeindex
文件,而每个文件都会消耗一个内存区域(一个日志段使用2个内存映射区域),因此一个分区至少需要2个内存区域,一个broker上拥有50000分区时,将会消耗100000个内存区域,此时默认的参数就会导致broker 以OutOfMemoryError
方式crash掉。
注意:
每个分区的日志段的数量取决于段(segment)的大小,负载,以及保留策略
kafka使用大量的文件以及socket和客户端进行通讯,我们都知道,在Linux下,一切皆文件,因此系统需要设置更多的可用文件描述符>。
在大多数的默认系统配置中,单个进程可用使用1024个文件描述符,对于kafka来说太小了,建议调整到至少100000
,但是通常和操作 系统以及发行版本有关系,需要根据具体的OS进行调整。
可用通过计算Kafka数据目录中的.index
文件来计算当前的mmap编号。.index
文件大多数代表了内存映射文件。
# 1.统计.index文件个数
$ find . -name '*index' | wc -l
2.为每个session设置vm.max_map_count参数,这将计算当前内存映射文件的数量,mmap限制的最小值就是打开文件的ulimit限制
该值要远大于index的数量
$ sysctl -w vm.max_map_count=262144
3.持久化mmap参数
$ echo ‘vm.max_map_count=262144’ >> /etc/sysctl.conf
$ sysctl -p
1.1 内存
Kafka严重依赖文件系统来存储和缓存消息。
所有数据都会立即写入文件系统上的持久日志中,而不必刷新到磁盘。实际上,这仅意味着将其转移到内核的页面缓存pagecache
中。 当回收内存时,操作系统会将可用内存转移到磁盘缓存中,而对性能的影响很小。
同时,Kafka非常小心地使用堆空间heap space
,不需要将堆大小设置为超过6 GB,这样将会在32G内存的机器上缓存28-30G的数据到文件系统。
因此,生产集群需要足够的内存来缓存活动的reader和writer。在Confluent的使用建议中,提出了对内存需求的粗略估计方式,比如需要缓冲30s,那么内存需求大概为write_throughput * 30
。
通常来讲64G
内存配置的机器是一个不错的选择.
1.2 CPU
大多数的kafka集群对于cpu的要求不是那么高,因此对于CPU的配置没有像其他资源那么重要(但是通常同等资源都是由一定比例配比的)。
注意:
如果开启了SSL,那么可能对集群的整体性能有一定影响,且对cpu有一定要求,具体需要考虑到cpu的类型以及具体的JVM实现细节(通常来讲内部服务均不会开启SSL,因为管理成本很高,且性能上略有损失,安全上可以通过整体的IT安全进行要求和管控)
通常情况下建议使用较新的多核处理器,通用集群可以设置为24
核心。
如果需要在更快的CPU或更多的内核之间进行选择,请选择更多的内核,因为多核提供的额外并发性将远远超过稍快的时钟速度。
1.3 Disk
生产集群建议使用多块磁盘来最大化整体的吞吐,不要与应用程序日志或其他OS文件系统活动共享用于Kafka数据的相同驱动器,以确保良好的延迟。
在官方的最佳实践中建议,可以将多块磁盘构建成RAID
,或者直接将独立的多块磁盘
作为kafka的数据存储,也就是JBOD方案(Just Bunch Of Disks)。
备注:
如果软RAID的话其实会在存储方面增加一层数据均衡,增加了集群的复杂度,因此一般可用选择后者,而且RAID主要用于提供冗余,对于开源分布式服务来讲,在软件层面上基本都会保证数据的冗余。
不过在实际的场景中,具体选择使用多块盘做RAID还是直接使用多块盘挂载,以下有几种场景可以考虑:
如果配置多个数据目录,则Broker将在路径中放置一个新分区,该分区中当前存储的分区数最少。每个分区将完全位于数据目录之一中,如果分区之间的数据不平衡,就会导致磁盘之间的负载不平衡
。
RAID在平衡磁盘之间的负载方面做得更好,它能在较低的水平上平衡负载。RAID的主要缺点是减少了可用的磁盘空间(RAID0除外),好处是可以容忍磁盘故障(RAID1,RAID5等)。
在生产中强烈不建议使用RAID 5 or RAID 6 ,会严重影响到写吞吐的性能,并且在磁盘故障时会有重建阵列的I/O成本(RAID0下也存在重建I/O的成本
)
如果额外的成本可以接受,建议使用RAID10(容量减半,多一份冗余),否则,建议Kafka服务器配置多个日志目录,每个目录都安装在单独的驱动器上。
linked使用8x7200转的sata磁盘,一般来说,磁盘吞吐量是性能瓶颈,磁盘越多越好。
kafka官方文档中其实建议使用多个驱动器以获得良好的吞吐量,因为每个路径都独立挂载在不同的磁盘上,这使得多块物理磁盘磁头同时执行物理I/O写操作,可以极大地加速Kafka消息生产的速度。
注意:
通常在使用本地盘时,容量可能会比较大,当磁盘容量超过2T时,Linux下默认的MBR分区就不能满足容量的要求了,此时需要在分区时进行GPT分区,否则等线上业务真正上线后会发现超过2T的空间就被浪费了。
另外一个问题就是,磁盘容量规划的问题,虽然kafka默认为全部的日志数据设置了7天保留时间,但是往往在海量的数据消费场景中,单天的数据量也可能达到好几个T,这就导致了需要提前对业务的场景和使用方式进行提前规划,并提前计算最少的存储量。
但一般对于磁盘空间的规划可以根据消息量大概估算,比如一天7亿条消息,单条1kb,消息副本为3(可保证2节点同时挂),那么大概的存储空间为7亿*3*1KB/1000/1000=2100G
,也就是这种规模下的数据,一天产生2T的数据,实际使用数据为700G,1400G数据为冗余数据,此时我们在规划磁盘容量时就需要考虑到单天数据量的大小,以及数据的保留时间。
注意:
如果客户端开启了消息压缩,整体的数据能再相对小一些,可以根据具体情况来考虑
1.4 Network
在分布式系统中,快速可靠的网络是性能的一个重要组成部分(因此通常分布式系统中建议在同机房
)。
低延迟确保节点可以轻松通信,而高带宽有助于集群节点之前的副本移动和恢复(往往在kafka集群中优先瓶颈点都是带宽
)。
目前大多数的数据中心基本都是千兆(1 GbE)或万兆网络(10 GbE),对于大多数集群通常都是足够的。
应该尽量避免集群跨越多个数据中心,即使数据中心在很近的距离同地区,也要避免跨越巨大地理距离的集群。
备注:
实际上在分布式系统中分区是肯定会发生的,通过避免跨机房部署能够降低分区的概率
Kafka集群假设所有节点都是相等的,较大的延迟可能会加剧分布式系统中的问题,并使调试和解决变得更加困难。
注意:
如果业务上需要异地进行数据读写,推荐的方法是在每个数据中心中部署一个本地Kafka集群,每个数据中心中的应用程序实例只与它们的本地集群交互,并在集群之间进行镜像(kafka提供了mirror-maker工具)。