因Kafka具有吞吐量大,低延迟,高伸缩,高可靠性,高并发等特性,深受各大公司的喜爱,可以作为削峰填谷神器。
但是Kafka“入门容易精通难”,它的很多默认配置,非常保守,像是给笔记本电脑用的,不是给服务器用的。
因此,用好Kafka,可以从以下几个方面进行优化。
关闭Swap
JVM 最怕什么?最怕内存不够用,操作系统把它的内存页置换到 Swap 分区去。那一瞬间,GC 停顿时间(Stop The World)能长到让你怀疑人生。Kafka 是跑在 JVM 上的,一旦发生 Swap,Broker 就算没挂,延迟也得飙到好几秒。
sysctl -w vm.swappiness=1
别设成 0,设成 1,告诉内核,除非内存真的真的枯竭了,否则别动我的 Swap。最好直接在 /etc/fstab 里把 swap 这一行注释掉,永绝后患。
设置文件句柄数(File Descriptors)
Kafka 个狂暴的写手。它会打开无数个 Socket 连接,还会打开无数个日志分段文件(Segment Logs)。Linux 默认的 1024 个句柄,远远不够Kafka消耗的。
修改 /etc/security/limits.conf,参照系统条件调整,例如下面的参数:
soft nofile 100000
hard nofile 100000设置合理的存储位置
Kafka 追求的是极致的顺序写盘速度。必须用物理盘! SSD 当然爽,但其实普通的 HDD 机械硬盘做 RAID 10 也完全够用,因为 Kafka 是顺序写,机械盘的顺序写性能并不差。
但是不要把Kafka的数据目录挂载到网络存储NFS。也不要使用RAID 5级别的盘。
RAID 5 的写性能惩罚太重了。不如直接用 JBOD(Just a Bunch of Disks),配置多个 log.dirs,让 Kafka 自己去把数据分摊到不同的盘上。这样坏一块盘,只丢一部分数据(靠副本恢复),总比 RAID 重建的时候整个阵列性能拖垮要强。
合理配置ZooKeeper
虽然现在的 Kafka 推出了 Kraft 模式(去 ZK 模式),但在生产环境,暂时还是使用 Zookeeper 保险一些。Kraft 虽好,但还得再跑个一两年才敢说是真的稳。
ZK 集群搭建没啥好说的,节点数必须是奇数,3 个或者 5 个。为啥?为了防脑裂,过半数机制嘛。
适当优化tickTime:默认是 2000ms。如果网络环境稍微抖一下,或者 GC 稍微卡一下,ZK 就会觉得节点挂了。稍微调大点,比如 3000ms 甚至 tickTime=2000 配合 initLimit 和 syncLimit 调大倍数,给网络抖动留点面子。
ZK 的 dataLogDir 最好和 dataDir 分开,放在不同的磁盘上。ZK 对事务日志的写入延迟非常敏感,别让它跟快照文件抢磁盘 IO。
优化server.properties配置
1. broker.id
这个不用说了吧,每个节点必须不一样。
2. listeners 和 advertised.listeners
这是新手最大的噩梦,没有之一。 多少人死在这上面,外网死活连不上,或者内网通了外网不通。
listeners 是你耳朵听哪里的声音。比如 PLAINTEXT://0.0.0.0:9092,意思是只要是发到这台机器 9092 端口的,我都听。
advertised.listeners 是你对外发出去的名片。告诉客户端:“嘿,你要找我,请打这个电话”。
如果你在云服务器上,内网有个 IP 192.168.0.2,外网有个公网 IP 8.8.8.8。
listeners 你就写内网 IP 或者 0.0.0.0。
advertised.listeners 你必须写客户端能访问到的那个 IP。如果你的生产者在公网,这儿就得填 8.8.8.8。如果你填了内网 IP,客户端连上一看:“哦,去连 192.168.0.2”,然后它根本访问不到这个内网 IP,直接超时报错。
3. num.partitions
默认是 1。很多教程让你改大点,但是建议不要修改。
这个是全局默认配置。你把它改成 100,以后随便建个测试 Topic 都是 100 个分区,成千上万个分区会把 ZK 和 Controller 累死的。
保持默认 1 或者 3 就行了。真正重要的 Topic,建的时候手动指定分区数。
4. log.retention.hours
默认 168 小时(7天)。
问问你们的存储预算。如果流量巨大,7天的数据能把你磁盘撑爆。我就见过因为日志没清掉,磁盘满了,Kafka 直接宕机的。对于很多日志类业务,保留 48 小时甚至 24 小时通常就够了。
配合 log.retention.bytes 使用效果更佳,比如限制每个分区最大 1GB,双保险。
5. min.insync.replicas
这是数据安全的核心。
默认是 1。这太危险了。如果是 1,只要 Leader 自己活着,它就敢告诉你“写入成功”。万一 Leader 下一秒挂了,副本还没同步过去,数据就丢了。
建议设成 2。也就是说,至少得有两个节点(Leader + 一个 Follower)确认收到了消息,才算成功。
当然,这得配合生产者的 acks=all 使用。
如果你设了 min.insync.replicas=2,但是你的集群一共只有 2 个节点,那只要挂一台,你的集群就变成“只读”了,写入会全部失败。所以,3 节点集群是起步价。
JVM相关设置
Kafka 的设计理念非常特别。它极度依赖操作系统的 Page Cache(页缓存)。它读写文件,其实都是在跟操作系统的内存打交道,然后由操作系统异步刷到盘里。
如果给 JVM 堆内存分了 30G,那留给操作系统的 Page Cache 就少了 30G。Kafka 反而会变慢。
对于 Kafka Broker 来说,堆内存(Heap)通常 6G 到 10G 就绰绰有余了。它不需要在堆里缓存大量数据,它只是做个搬运工。剩下的几十 G 内存,全部留给操作系统去做 Page Cache,这才是性能起飞的秘密。
修改启动脚本 kafka-server-start.sh,找到 KAFKA_HEAP_OPTS,改成:
-Xmx6G -Xms6G
记得加上 G1 垃圾回收器,JDK 1.8 以后 G1 的表现还是很稳的:
-XX:+UseG1GC
使用Systemd管理服务
使用 nohup bin/kafka-server-start.sh config/server.properties &不方便不安全也不好管理,推荐使用Systemd进行统一管理。
使用systemctl start kafka要安全规范许多。还能配置开机自启,进程挂了自动重启。
vim /usr/lib/systemd/system/kafka.service
[Unit]
Description=Apache Kafka
Requires=zookeeper.service
After=zookeeper.service
[Service]
Type=simple
User=kafka
ExecStart=/usr/local/kafka/bin/kafka-server-start.sh /usr/local/kafka/config/server.properties
ExecStop=/usr/local/kafka/bin/kafka-server-stop.sh
Restart=on-failure
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target查看日志验证服务状态
用自带的 kafka-console-producer.sh 往里灌几条数据,再开个 kafka-console-consumer.sh 看看能不能读出来。
还得看日志!
去 logs/server.log 里看一眼。有没有 Error?有没有频繁的 GC 警告?有没有 Connection refused?
如果有 Controller 频繁切换的日志,那说明你的网络或者 ZK 不稳,赶紧查,别等业务上线了再查。
配置监控项
Kafka 这东西,内部黑盒。你必须得配监控。
最起码,得搞个 Kafka Eagle(现在叫 EFAK)或者 Prometheus + Grafana。
你要盯着两个最重要的指标:
Consumer Lag(消费积压):这是业务死活的晴雨表。
Under Replicated Partitions(未同步分区):这个指标如果不为 0,说明有 Broker 掉队了或者挂了,数据处于危险状态,必须立刻马上处理。
评论 (0)