尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

CentOS7部署Kafka完整指南:从环境配置到生产调优

CentOS7部署Kafka完整指南:从环境配置到生产调优 这篇部署指南其实不是临时起意写的。前阵子我在 HoRain 云上买了台 CentOS7 主机准备把公司的一个异步消息链路迁过去结果发现网上关于 CentOS7 部署 Kafka 的资料要么太老要么就是跳过关键细节照着抄完启动直接报错。折腾了一下午才把问题理顺所以干脆把整个过程整理成一篇完整的指南从 Java、ZooKeeper、Kafka 安装到配置参数、服务化管理、常见问题排查和调优一次性讲透。适合刚入门的开发也适合需要自己维护 Kafka 的运维同学按步骤操作能少走很多弯路。1. 部署前要理清的思路和版本选型1.1 Kafka 到底是什么很多新手容易把 Kafka 当成一个“普通的消息队列”来理解这样后面配置参数很容易踩坑。Kafka 实际上更像是一个分布式提交日志消息按照主题Topic拆分每个主题再分成多个分区Partition分区内消息是有序的消费者靠记录偏移量Offset来知道自己读到哪了。这跟 RabbitMQ 这种“消息即队列”的模型差别很大。Kafka 的消息是持久化在磁盘上的保留期到了才删除所以它可以实现消息回放、离线消费、多消费者订阅同一份数据这些能力。理解了这个模型你去配置 log.retention、分区数、副本数时脑子里会清晰很多。在云服务器上部署 Kafka第一件事不是敲安装命令而是想清楚自己的业务场景消息量多大是否需要高可用需要几个副本这决定了后面的架构选型和机器规格。1.2 Kafka 版本怎么选Kafka 版本演进过程中有个重要的转折点2.8 之前必须依赖 ZooKeeper2.8 开始引入 KRaft 模式可以在不依赖 ZooKeeper 的情况下运行3.x 版本开始逐步完善 KRaft但早期版本3.0、3.1还是有点“半成品”的感觉直到 3.3 左右才比较稳定。如果你只是想快速体验可以选用 3.3 版本的 KRaft 模式少维护一个 ZooKeeper清爽很多。但如果你要求网上的案例多、遇到问题搜得到答案经典 ZooKeeper 模式的部署方式依然是主流。本文为了把整体架构讲透会以 ZooKeeper 模式为主线KRaft 模式在最后提一下部署差异。Java 版本也要注意Kafka 2.x 用 JDK8 就够了Kafka 3.x 可以 JDK8 或 JDK11。CentOS7 自带源里的 OpenJDK 8 是很好的选择没必要去装 JDK17 甚至更高版本因为太新的 JDK 反而容易和部分客户端、监控工具出现兼容性问题。1.3 单机还是集群测试学习的话单机部署完全够用。但真要上生产至少三台 broker 起步。Kafka 的高可用靠的是副本机制每个分区的副本分布在多个 broker 上Leader 挂了Follower 能顶上。如果你只有一台机器就算配置里写了副本数为 3副本也都落在同一台机器上磁盘坏了数据照样丢。资源规划上Kafka 对硬件有一些隐性要求磁盘优先 SSD机械盘跑大吞吐场景会很吃力内存建议 8G 起步但要注意 JVM 堆内存不需要给太大重点是系统页缓存Page Cache要充足网络内网带宽一定要好多副本复制和客户端流量都会吃网络我个人的经验是宁可 CPU 配置低一点也要保证磁盘和网络够用因为 Kafka 瓶颈一般出现在 IO 上。2. 环境准备基础系统、JDK、ZooKeeper2.1 先把 CentOS7 基础环境弄顺拿到一台新的 CentOS7 云主机第一件事不是急着装 Kafka而是把 Yum 源换掉。默认源在国内访问经常很慢换成阿里云源之后速度提升非常明显。cd /etc/yum.repos.d/ cp CentOS-Base.repo CentOS-Base.repo.bak wget -O /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo yum clean all yum makecache同时建议把常用工具装上yum install -y vim wget curl net-tools telnet lsof这里有个隐藏问题CentOS7 默认 SELinux 是 Enforcing 状态如果不处理后面 Kafka 的端口监听、跨机访问会出现各种奇怪问题。虽然网上很多教程都不提但我建议部署前先把它关掉或者改成 Permissivesed -i s/SELINUXenforcing/SELINUXdisabled/g /etc/selinux/config setenforce 0修改完配置文件后建议重启服务器一次性确认基础的网络、挂载、SELinux 状态都正常。2.2 安装 JDK 并配置 JAVA_HOMEKafka 和 ZooKeeper 都是 Java 应用所以 JDK 是绕不开的。我推荐 OpenJDK 8安装方便兼容性也好。yum install -y java-1.8.0-openjdk java-1.8.0-openjdk-devel java -version安装完 JDK 不代表能用必须设置 JAVA_HOME。Kafka 的启动脚本 kafka-run-class.sh 会直接读取这个环境变量不配置的话启动时大概率会报“Could not find any executable java binary”之类的错误。cat /etc/profile EOF export JAVA_HOME/usr/lib/jvm/java-1.8.0-openjdk export PATH$PATH:$JAVA_HOME/bin export CLASSPATH.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar EOF source /etc/profile echo $JAVA_HOME高版本的 JDK 安装路径可能是/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.xxx可以用ls /usr/lib/jvm/确认实际路径。2.3 部署 ZooKeeper经典模式下的 Kafka 需要先部署 ZooKeeper。版本选择上我建议 3.5.7 或 3.6.3兼容性和稳定性都比较可靠。wget https://dlcdn.apache.org/zookeeper/zookeeper-3.6.3/apache-zookeeper-3.6.3-bin.tar.gz tar -zxvf apache-zookeeper-3.6.3-bin.tar.gz -C /opt/ mv /opt/apache-zookeeper-3.6.3-bin /opt/zookeeper创建数据目录修改配置mkdir -p /data/zookeeper/data mkdir -p /data/zookeeper/logs cd /opt/zookeeper/conf cp zoo_sample.cfg zoo.cfg vim zoo.cfgzoo.cfg 里最核心的几项tickTime2000 dataDir/data/zookeeper/data clientPort2181 maxClientCnxns60 initLimit10 syncLimit5简单解释一下tickTime 是 ZooKeeper 的最小时间单位默认 2000 毫秒dataDir 是快照数据目录一定要放在数据盘clientPort 是客户端连接端口默认 2181。如果以后要搭建 ZooKeeper 集群还需要在 zoo.cfg 中加 server.1host1:2888:3888 这类配置但单机部署可以忽略。启动并验证/opt/zookeeper/bin/zkServer.sh start /opt/zookeeper/bin/zkServer.sh status netstat -lnp | grep 2181看到Mode: standalone就说明 ZooKeeper 已经正常启动了。2.4 系统参数调整Kafka 在高负载下会打开大量文件描述符CentOS7 默认的 ulimit 1024 完全不够用必须调大cat /etc/security/limits.conf EOF * soft nofile 65535 * hard nofile 65535 EOF ulimit -n 65535还要注意 vm.swappiness。如果服务器内存充足建议把 swappiness 调低尽量让换页不频繁发生让文件页在 Page Cache 里待得更久sysctl -w vm.swappiness10 echo vm.swappiness10 /etc/sysctl.conf这一步对 Kafka 的读写性能影响很明显因为在 Linux 下 Kafka 读写磁盘依赖的就是页缓存机制。3. Kafka 安装、配置与启动3.1 下载和解压Kafka 官方下载包名称里带有 Scala 编译版本比如 kafka_2.13-3.2.0.tgz。这个 Scala 版本只是 Kafka 编译时的依赖和你之后用的客户端语言没有直接关系选 2.12 或 2.13 都可以。wget https://downloads.apache.org/kafka/3.2.0/kafka_2.13-3.2.0.tgz tar -xzf kafka_2.13-3.2.0.tgz -C /opt/ mv /opt/kafka_2.13-3.2.0 /opt/kafka mkdir -p /data/kafka/logs如果服务器无法直连外网下载可以像搜关键词里提到的“kafka镜像下载地址”一样找国内厂商提供的镜像包下载或者先在本地下载再上传到服务器。3.2 核心配置文件 server.properties配置文件在/opt/kafka/config/server.properties这是整个部署过程中最重要的文件。我先列最核心的几项broker.id0 listenersPLAINTEXT://内网IP:9092 advertised.listenersPLAINTEXT://内网IP:9092 log.dirs/data/kafka/logs zookeeper.connectlocalhost:2181 num.partitions3 default.replication.factor1 log.retention.hours168这份配置的每一项都值得掰开来说broker.id每个 broker 在集群中的唯一编号不能重复。第一台是 0第二台是 1依此类推。listenersKafka 监听地址。这里有个很容易踩的坑如果你监听 0.0.0.0:9092从本机看一切正常但客户端连接时拿到的 broker 地址可能不是预期地址。advertised.listeners这个参数是给客户端使用的告诉客户端“你应该用这个地址连接我”。生产环境一定要显式配置不然跨机器消费时会莫名其妙连接超时。log.dirs注意这个配置项是复数Kafka 会把不同分区的数据分散存储到这里的多个目录。如果有多块数据盘建议用逗号分隔多个目录例如/data1/kafka,/data2/kafka这样不同分区的负载会更均匀。zookeeper.connectZooKeeper 地址单机就是 localhost:2181。如果有 ZK 集群用逗号分隔多个地址。还可以加 chroot 路径比如host1:2181,host2:2181/kafka这样多个项目共用一套 ZK 时不会命名冲突。num.partitions新建主题时的默认分区数。生产环境建议从 3 起步。default.replication.factor默认副本因子。单节点集群写 2 也没意义因为只有一台机器副本无法真正分布三节点集群可以设 2 或 3。log.retention.hours消息保留时间默认 168 小时也就是 7 天。还有一些容易忽略的参数message.max.bytes1048588 replica.fetch.max.bytes1048576 auto.create.topics.enablefalse如果业务需要发送超过 1MB 的大报文需要同步调大 message.max.bytes 和副本拉取的相关参数。auto.create.topics.enable 生产环境务必设为 false避免客户端写数据时拼错 Topic 名Kafka 自动创建了一堆垃圾主题。3.3 启动 Kafka启动前先设置 JVM 堆内存避免默认值过大或过小export KAFKA_HEAP_OPTS-Xms2G -Xmx2G启动命令/opt/kafka/bin/kafka-server-start.sh -daemon /opt/kafka/config/server.properties验证启动状态jps netstat -lnp | grep 9092 tail -f /opt/kafka/logs/server.log这里我要强调一点看到进程不代表启动成功。Kafka 启动过程中要做一些初始化工作必须看到 server.log 中出现started (kafka.server.KafkaServer)才算真正就绪。如果你只看 jps 就急着建 Topic很可能报错。3.4 使用 systemd 管理 KafkaKafka 自带的启动脚本加上 -daemon 参数虽然能后台运行但服务器重启后进程不会自动拉起。更好的方式是配置成 systemd 服务[Unit] DescriptionApache Kafka Server Requiresnetwork.target Afternetwork.target [Service] Typesimple EnvironmentJAVA_HOME/usr/lib/jvm/java-1.8.0-openjdk EnvironmentKAFKA_HEAP_OPTS-Xms2G -Xmx2G Userkafka Groupkafka ExecStart/opt/kafka/bin/kafka-server-start.sh /opt/kafka/config/server.properties ExecStop/opt/kafka/bin/kafka-server-stop.sh Restarton-failure RestartSec10 LimitNOFILE65535 [Install] WantedBymulti-user.target创建专用用户并授权useradd -r -s /sbin/nologin kafka chown -R kafka:kafka /opt/kafka /data/kafka之后就能用 systemctl 统一管理了systemctl daemon-reload systemctl enable --now kafka systemctl status kafka用 systemd 管理还有个好处可以在服务文件里直接写 LimitNOFILE避免只修改 limits.conf 后systemd 依然默认限制进程文件句柄数的问题。4. 消息收发测试和常用运维操作4.1 创建 Topic 并查看信息Kafka 装好后一定要做一次完整的消息收发验证。先创建测试主题/opt/kafka/bin/kafka-topics.sh --create \ --topic test-topic \ --bootstrap-server localhost:9092 \ --partitions 3 \ --replication-factor 1查看 Topic 列表和详情/opt/kafka/bin/kafka-topics.sh --list --bootstrap-server localhost:9092 /opt/kafka/bin/kafka-topics.sh --describe --bootstrap-server localhost:9092 --topic test-topicdescribe 输出里能看到分区数量、Leader 分布、副本列表和 ISR 列表。这些信息对判断集群健康状态很有用。4.2 生产消费链路验证生产消息/opt/kafka/bin/kafka-console-producer.sh \ --broker-list localhost:9092 \ --topic test-topic输入几条消息后回车消息就写入 Kafka 了。消费消息/opt/kafka/bin/kafka-console-consumer.sh \ --bootstrap-server localhost:9092 \ --topic test-topic --from-beginning这里注意一下从--from-beginning开始消费会读取该主题分区中所有历史消息。如果之前测试写过不少数据输出会很长这是正常的。4.3 消费组和偏移量操作Kafka 消息消费的核心机制是消费组。每个消费组有独立的偏移量组内多个消费者实例会分摊分区的消费。查看消费组列表/opt/kafka/bin/kafka-consumer-groups.sh \ --bootstrap-server localhost:9092 \ --list查看某个消费组的状态和 Lag堆积量/opt/kafka/bin/kafka-consumer-groups.sh \ --bootstrap-server localhost:9092 \ --describe --group my-groupLag 是LOG-END-OFFSET和CURRENT-OFFSET的差值Lag 持续变大就意味着消费追不上生产速度了。有时候我们需要手动重置偏移量。比如消费者逻辑天生跑了一次数据已经处理完了但又想重新消费一遍历史数据/opt/kafka/bin/kafka-consumer-groups.sh \ --bootstrap-server localhost:9092 \ --group my-group \ --topic test-topic \ --reset-offsets --to-earliest --execute想要重置到某个时间点可以用--to-datetime 2024-01-01T00:00:00.000。这个能力是 Kafka 很有用的特性之一也是面试题里经常会问到的“消息回溯”功能的实现方式。注意一点执行偏移量重置之前消费组内的所有消费者必须停止否则命令会报错提示 group 还是 active 状态。4.4 可视化工具选型纯命令行操作虽然能用但查看堆积趋势、分区分布甚至集群健康状态时有个图形界面要直观得多。常见的选择有三个Kafka UIprovectuslabs/kafka-ui目前比较活跃的开源项目Web 管理界面支持多集群CMAK原名 Kafka Manager老牌工具Kafka 2.x 时代用得很多Offset Explorer原名 Kafka Tool桌面客户端适合个人本地调试Docker 部署 Kafka UI 非常方便version: 3 services: kafka-ui: image: provectuslabs/kafka-ui:latest ports: - 8080:8080 environment: KAFKA_CLUSTERS_0_NAME: local KAFKA_CLUSTERS_0_BOOTSTRAPSERVERS: localhost:9092 KAFKA_CLUSTERS_0_ZOOKEEPER: localhost:2181注意 kafka-ui 所在的容器/服务器必须能访问到 Kafka 的 9092 端口否则界面能连上但消费和查看消息时会失败。跨机器部署时Kafka 的 advertised.listeners 配置就显得格外重要。5. 常见问题排查实录这部分内容是实际运维中最值钱的我把遇到过的典型问题按出现频率列出来供大家排查时直接对照。5.1 ZooKeeper 连接失败启动 Kafka 时日志里出现org.apache.zookeeper.KeeperException$ConnectionLossException或Timed out waiting for connection while in state: CONNECTING排查顺序ZooKeeper 进程是否真的起来了netstat -lnp | grep 2181有没有监听如果 Kafka 和 ZooKeeper 不在同一台机器检查防火墙、安全组是否放行了 2181zookeeper.connect 是否写对 IP、端口、chroot 路径看一下 ZooKeeper 自己的日志是不是端口被占用或者 dataDir 权限不对云服务器上还要额外注意安全组规则很多问题不是本机配置错了而是安全组层面根本没放行对应端口。5.2 Too many open files现象是 Kafka 运行一段时间后突然卡住日志里大量出现java.io.IOException: Too many open files一般原因就是文件句柄数不够。修改 /etc/security/limits.conf 之后如果你用的是 systemd 启动还要在服务文件里加LimitNOFILE65535否则 systemd 会覆盖 limits 的限制。5.3 客户端连接超时但本机访问正常这台服务器上 telnet 9092 是通的但另一台机器连接超时这可能是最隐蔽的坑原因大概率是 advertised.listeners。打个比方客户端连上 broker 后会向 broker 要元数据broker 会返回每个分区的 Leader 所在的地址。这个地址就是 advertised.listeners 里配置的地址。如果你只配了listenersPLAINTEXT://内网IP:9092没有配 advertised客户端拿到内网 IP 之后就得能路由到那个 IP。如果客户端和 broker 不在同一个内网或者安全组隔离了内网网段连接就会失败。一个比较稳妥的配置方式是listenersPLAINTEXT://0.0.0.0:9092 advertised.listenersPLAINTEXT://客户端可达IP:9092这样 broker 监听所有网卡但对外公布的地址是客户端能访问到的那个。5.4 消费延迟越来越大消费延迟也就是 Lag 持续上涨这是集群上线后最常被问到的。排查思路不能只想着“加机器”要按顺序看用 kafka-consumer-groups.sh --describe 看每个分区的 Lag 是持续增加还是偶发增加看消费者应用日志单条消息处理时间是不是过长有没有外部接口调用成为瓶颈看消费者是否频繁加入、退出触发 rebalance。rebalance 期间整个消费组会短暂停止消费如果频繁发生Lag 自然会涨看 broker 的 CPU、磁盘 IO是否存在分区热点如果一条消息处理要几百毫秒加机器确实能缓解因为消费者并行度上来了。但如果单条消息处理逻辑里有一次很慢的数据库查询加机器可能只是把并发上去数据库还是瓶颈Lag 不一定能压下去。5.5 快速排查表现象可能原因处理方向broker 启动失败连接 ZK 超时ZooKeeper 未启动/端口不通检查 2181 连通性启动成功但 jps 没有进程JVM 内存不足、日志异常退出看 server.log 和 gc.log客户端连不上 9092防火墙/安全组/advertised 配置放行端口正确配置 advertised写入超时、生产者一直重试磁盘 IO 高、ISR 不完整检查 ISR、磁盘性能消费组 Lag 持续增加消费者处理慢、rebalance 频繁看处理耗时、消费组状态大量 Too many open files句柄数限制修改 ulimit 和 systemd LimitNOFILE消息只有部分消费者能收到分区数和消费者实例数导致部分消费者无分区可分配规划分区数量和消费者并行度5.6 关于 KRaft 模式的一个补充如果你选用 Kafka 3.3 的 KRaft 模式部署方式会简单不少因为不需要 ZooKeeper。需要先执行/opt/kafka/bin/kafka-storage.sh random-uuid /opt/kafka/bin/kafka-storage.sh format -t uuid -c /opt/kafka/config/kraft/server.properties然后启动/opt/kafka/bin/kafka-server-start.sh /opt/kafka/config/kraft/server.propertiesKRaft 模式目前已经可以在生产环境使用了但它对集群演进、版本升级的路径仍然和 ZooKeeper 模式有一定差异。如果你是第一次接触 Kafka我还是建议先用经典模式把概念摸透再切 KRaft 模式体验一下差异。6. 生产环境调优和个人经验6.1 JVM 内存别给太大Kafka 的 JVM 堆内存我一般控制在 4G 到 8G不需要给超过 8G。理由很简单Kafka 的性能核心来自 Linux Page Cache数据写入磁盘、读取消息主要靠内核页缓存来加速JVM 堆只是用来跑 broker 自身逻辑的。堆内存设太大反而会让 GC 时间变长Full GC 时整个 broker 的吞吐会明显掉。可以用 G1 收集器控制停顿时间export KAFKA_HEAP_OPTS-Xms4G -Xmx4G -XX:UseG1GC -XX:MaxGCPauseMillis2006.2 日志保留策略要双重兜底生产环境建议 log.retention.hours 和 log.retention.bytes 同时设置。比如保留 72 小时同时限制每分区总量不超过 100GB防止业务量突增时把磁盘写满。这里有个磁盘规划的心得Kafka 的 log.dirs 不要只配一个目录如果有两块数据盘就配成/data1/kafka,/data2/kafkaKafka 会把新分区分布到空间占用最低的目录里这样多盘负载天然均衡。6.3 分区数设计其实没那么玄分区数太少消费者的扩展性有限分区数太多broker 上的文件句柄和内存开销会变大。一个便于理解的估算方式先看业务峰值吞吐比如 100MB/s。单分区在 SSD 上通常能跑到 10MB/s 到 20MB/s。用峰值吞吐除以单分区吞吐再乘 1.5 到 2 的冗余系数就是比较合理的分区数。分区数一旦确定尽量不要频繁扩容因为分区数变化会影响消息顺序性和消费组再平衡。6.4 运维要脚本化和可观测Kafka 部署完成之后我的习惯是把所有管理动作都收敛到 systemd 和简单脚本里。日志统一放到 /data/logs 下按天滚动保留 7 天。Kafka 自带的 server.log 也要配置 log4j 的滚动策略避免长时间运行把磁盘写满。监控这块如果规模不大可以直接用 Kafka UI 看基础指标如果规模上来建议配合 JMX exporter 把 broker 的关键指标拉出来。这里对应的热词里的“kafka exporter 下载”就是指 JMX Prometheus exporter部署后可以对接 Prometheus Grafana。6.5 最后一些大实话如果一定要我总结一条最值得分享的经验那就是一步一步来不要跳步。先把单机版跑通把启动、生产、消费、重启、看日志这些动作都操作熟练再去做集群、副本和监控。每一步都知道自己在做什么遇到问题才不会被各种报错淹没。Kafka 的安装本身不难难的是它和操作系统的细节耦合。文件句柄、SELinux、防火墙、时钟同步、磁盘 IO、网络延迟任何一项出问题都可能导致令人摸不着头脑的现象。这也是为什么我强烈建议大家把部署过程中每一条命令、每一个配置都按本文的顺序验证一遍不要在还没确认 ZooKeeper 状态之前就去启动 Kafka。我个人在反复部署 Kafka 的过程中最深的体会是Kafka 的很多问题其实不是 Kafka 的问题而是基础环境的问题。先把基础环境打扎实后面所有的业务逻辑和集群扩展都会顺很多。希望这篇文章能帮你在 CentOS7 上顺利跑起 Kafka少踩几个我已经踩过的坑。
返回列表