Kafka集群稳定
GC调优
调GC是门手艺活,幸亏Java 7引进了G1 垃圾回收,使得GC调优变的没那么难。G1主要有两个配置选项来调优:MaxGCPauseMillis 和 InitiatingHeapOccupancyPercent,具体参数设置可以参考Google,这里不赘述。
Kafka broker能够有效的利用堆内存和对象回收,所以这些值可以调小点。对于 64Gb内存,Kafka运行堆内存5Gb,MaxGCPauseMillis 和 InitiatingHeapOccupancyPercent 分别设置为 20毫秒和 35。Kafka的启动脚本使用的不是 G1回收,需要在环境变量中加入。
Kafka Broker个数决定因素
磁盘容量:首先考虑的是所需保存的消息所占用的总磁盘容量和每个broker所能提供的磁盘空间。如果Kafka集群需要保留 10 TB数据,单个broker能存储 2 TB,那么我们需要的最小Kafka集群大小5个broker。此外,如果启用副本参数,则对应的存储空间需至少增加一倍(取决于副本参数)。这意味着对应的Kafka集群至少需要 10 个broker。
请求量:另外一个要考虑的是Kafka集群处理请求的能力。这主要取决于对Kafka client请求的网络处理能力,特别是,有多个consumer或者网路流量不稳定。如果,高峰时刻,单个broker的网络流量达到80%,这时是撑不住两个consumer的,除非有两个broker。再者,如果启用了副本参数,则需要考虑副本这个额外的consumer。也可以扩展多个broker来减少磁盘的吞吐量和系统内存。
主要是启动脚本和log4j基本参数的设置和优化,这些参数藏的比较深。
1、JVM参数配置优化
如果使用的CMS GC算法,建议JVM Heap不要太大,在4GB以内就可以。JVM太大,导致Major GC或者Full GC产生的“stop the world”时间过长,导致broker和zk之间的session超时,比如重新选举controller节点和提升follow replica为leader replica。
JVM也不能过小,否则会导致频繁地触发gc操作,也影响Kafka的吞吐量。另外,需要避免CMS GC过程中的发生promotion failure和concurrent failure问题。CMSInitiatingOccupancyFraction=70可以预防concurrent failure问题,提前出发Major GC。
Kafka JVM参数可以直接修改启动脚本bin/kafka-server-start.sh
中的变量值。下面是一些基本参数,也可以根据实际的gc状况和调试GC需要增加一些相关的参数。
1 | export KAFKA_HEAP_OPTS="-Xmx8G -Xms8G -Xmn4G -XX:PermSize=64m -XX:MaxPermSize=128m -XX:SurvivorRatio=6 -XX:CMSInitiatingOccupancyFraction=70 -XX:+UseCMSInitiatingOccupancyOnly" |
需要关注gc日志中的YGC时间以及CMS GC里面的CMS-initial-mark和CMS-remark两个阶段的时间,这些GC过程是“stop the world”方式完成的。
jdk1.8 优化的话会提示MaxPermSize=128m,PermSize=64m 字面意思是MaxPermSize不需要我们配置了,jdk1.8 版本功能其实已不需要这个优化参数:
1 | [jollybi@kafka3 kafka_2.10-0.8.2.1]$ /data/tools/kafka_2.10-0.8.2.1/bin/kafka-server-start.sh /data/tools/kafka_2.10-0.8.2.1/config/server.properties & |
2、打开JMX端口
1 | 主要是为了通过JMX端口监控Kafka Broker信息。可以在bin/kafka-server-start.sh中打开JMX端口变量。 |
3、调整log4j的日志级别
如果集群中topic和partition数量较大时,因为log4j的日志级别太低,导致进程持续很长的时间在打印日志。日志量巨大,导致很多额外的性能开销。特别是contoller日志级别为trace级别,这点比较坑。
Tips 通过JMX端口设置log4j日志级别,不用重启broker节点
1 | 设置日志级别: |
4、性能优化技巧
4.1、配置合适的partitons数量。
这似乎是kafka新手必问得问题。首先,我们必须理解,partiton是kafka的并行单元。从producer和broker的视角看,向不同的partition写入是完全并行的;而对于consumer,并发数完全取决于partition的数量,即,如果consumer数量大于partition数量,则必有consumer闲置。所以,我们可以认为kafka的吞吐与partition时线性关系。partition的数量要根据吞吐来推断,假定p代表生产者写入单个partition的最大吞吐,c代表消费者从单个partition消费的最大吞吐,我们的目标吞吐是t,那么partition的数量应该是t/p和t/c中较大的那一个。实际情况中,p的影响因素有批处理的规模,压缩算法,确认机制和副本数等,然而,多次benchmark的结果表明,单个partition的最大写入吞吐在10MB/sec左右;c的影响因素是逻辑算法,需要在不同场景下实测得出。
这个结论似乎太书生气和不实用。我们通常建议partition的数量一定要大于等于消费者的数量来实现最大并发。官方曾测试过1万个partition的情况,所以不需要太担心partition过多的问题。下面的知识会有助于读者在生产环境做出最佳的选择:
1 | a、一个partition就是一个存储kafka-log的目录。 |
我们建议的做法是,如果是3个broker的集群,有5个消费者,那么建议partition的数量是15,也就是broker和consumer数量的最小公倍数。当然,也可以是一个大于消费者的broker数量的倍数,比如6或者9,还请读者自行根据实际环境裁定。