ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

ZooKeeper与Kafka集群部署实战:版本选型、配置与高可用指南

ZooKeeper与Kafka集群部署实战:版本选型、配置与高可用指南 大概聊一下这篇指南的背景。ZooKeeper 和 Kafka 这对黄金搭档在分布式系统里的地位不用多说。当年我刚接触集群部署的时候照着网上各种教程一步步操作结果总会遇到版本不兼容、节点无法互相发现、客户端连不上这类问题折腾一整天最后还得自己翻官方文档属于典型的“教程没看完就开始踩坑”。这篇指南就是冲着这些问题来的把我在 CentOS 上从零部署 ZooKeeper 和 Kafka 集群的完整流程、配置细节、以及部署过程中真正会遇到的坑都梳理清楚方便你基于一套可复现的步骤把集群搭起来。适合三类人看一是刚接触分布式系统、想自己动手搭一套环境练手的学习者二是公司内部需要快速搭建消息中间件集群做测试或生产的工程师三是已经部署过但总遇到莫名其妙的问题想回头排查基础配置的人。建议你按照章节顺序操作尤其是版本选型那部分不要跳过很多后续问题都源于版本之间的兼容关系没理顺。1. 版本选型与环境规划为什么是这些组合1.1 版本组合的兼容性考量进入正式部署之前先要把版本组合定下来。这个问题搞不定后面全白干。我见过不少人在这一步踩大坑JDK 用错了版本导致 Kafka 启动直接抛 UnsupportedClassVersionError或者下载的 Kafka 版本附带的 ZooKeeper 与集群里已有的 ZooKeeper 版本不一致导致通信协议不兼容各种诡异报错层出不穷。这里给出我实测稳定的一套组合CentOS 7.9 OpenJDK 8 ZooKeeper 3.6.3 Kafka 2.13-3.0.0并说明为什么这样选。逻辑大概是这样的CentOS 7.9 是目前 CentOS 7 系列的最终版本稳定性和软件源适配度都到位在服务器存量市场里的占比依然很高教程适配性最好。JDK 方面Kafka 2.x 系列官方依赖 JDK 8用 OpenJDK 8 最稳妥。如果你非要上 JDK 11那建议选 Kafka 3.x 以上的版本否则会在编译和运行兼容性上出问题。ZooKeeper 与 Kafka 的搭配有讲究。Kafka 2.13-3.0.0 本身打包了一个 ZooKeeper 依赖但它只是用于运行模式检查真正的外部协调者还是建议单独部署 ZooKeeper 集群。ZooKeeper 3.6.x 是个很好的平衡点和 Kafka 3.0 配合成熟又没有 3.7/3.8 那些新版本在滚动升级时可能出现的不稳定情况。这个结论是基于我实际搭建多套环境的对比得出的。选择 CentOS 7.9 而不是 CentOS Stream 或 Rocky Linux是因为本指南要最大程度兼容经典 yum 操作习惯。如果你手头是 Rocky Linux 或 AlmaLinux操作流程同样适用只是软件包管理器的名称和源配置略有差异。1.2 集群节点规划与专用账号建议至少用三个节点这也是多数生产环境的标准规模。ZooKeeper 集群采用多数派选举机制奇数节点才能保证单点故障时集群依然可用。三个节点允许一个节点宕机而不影响整体服务如果你只有两个节点宕掉一个就无法凑齐多数派集群只能只读甚至完全不可用。节点角色规划参考如下表格节点IP 地址主机名ZooKeeper 角色Kafka 角色Node1192.168.10.11node1participant / Leader 候选者broker 1Node2192.168.10.12node2participant / Leader 候选者broker 2Node3192.168.10.13node3participant / Leader 候选者broker 3三个节点同时承担 ZooKeeper 和 Kafka 的职责。在小规模集群测试环境和中等规模生产环境中这种混合部署是合理的但当业务量比较大时建议把 ZooKeeper 和 Kafka 拆到独立的节点组因为两者都是内存和 IO 敏感型服务混部会互相争抢资源。部署前还要统一完成几项准备工作修改每台机器的/etc/hostname保证各节点主机名唯一。在所有节点的/etc/hosts中统一写入三分量映射关系这一步关键到什么程度如果主机名解析不通节点之间根本无法互相发现。关闭 SELinux或至少将其设置为 permissive 模式。SELinux 的强制模式经常会拦截 ZooKeeper 和 Kafka 的端口绑定和文件读写操作但报错信息又非常隐晦排查难度极高。为 Kafka 和 ZooKeeper 创建专用的系统账号而不是直接用 root 运行服务。这是安全习惯的问题毕竟中间件长期以 root 权限运行一旦被利用损失范围就是整个机器。2. 下载安装与基础配置把底层堡垒先筑起来2.1 JDK 安装与环境变量配置在三个节点上分别执行 JDK 安装。CentOS 7.9 默认源中没有较新的 OpenJDK 8建议先安装java-1.8.0-openjdk-devel这个包包含了开发工具不只是运行时环境。仅装java-1.8.0-openjdk会导致后续启动 Kafka 时找不到部分工具类。# 在 node1、node2、node3 上均执行 sudo yum install -y java-1.8.0-openjdk-devel安装完成后验证版本java -version正常会输出类似openjdk version 1.8.0_...的信息。环境变量配置方面由于 CentOS 的 OpenJDK 安装包会自动配置好 java 命令的软链接通常JAVA_HOME并不是必须的。但 Kafka 和 ZooKeeper 的启动脚本有时会自动探测 java 可执行文件探测失败时就需要环境变量来兜底。建议还是主动配置一下省得以后其他 Java 应用部署时再踩一遍坑。cat /etc/profile.d/java.sh EOF export JAVA_HOME$(dirname $(dirname $(readlink -f $(which java)))) export PATH$PATH:$JAVA_HOME/bin EOF source /etc/profile.d/java.sh注意readlink -f $(which java)能拿到真实 JDK 路径因为 CentOS 上/usr/bin/java是指向/usr/lib/jvm/...的软链接不用手动写死路径。2.2 ZooKeeper 与 Kafka 安装包准备在 node1 上统一下载安装包再分发给其它节点。这种方式比在三台机器上分别下载更省时间也能避免各节点下载到不一致的版本。# 在 node1 上执行 cd /opt wget https://dlcdn.apache.org/zookeeper/zookeeper-3.6.3/apache-zookeeper-3.6.3-bin.tar.gz wget https://dlcdn.apache.org/kafka/3.0.0/kafka_2.13-3.0.0.tgz请务必下载apache-zookeeper-3.6.3-bin.tar.gz而不是apache-zookeeper-3.6.3.tar.gz。后者是源码包里面没有编译好的二进制直接用会卡在启动阶段。Kafka 的压缩包命名里2.13表示 Scala 编译版本3.0.0才是 Kafka 版本号不要搞混。解压并移动到统一目录tar -zxvf apache-zookeeper-3.6.3-bin.tar.gz -C /opt tar -zxvf kafka_2.13-3.0.0.tgz -C /opt mv /opt/apache-zookeeper-3.6.3-bin /opt/zookeeper mv /opt/kafka_2.13-3.0.0 /opt/kafka创建相关数据目录mkdir -p /data/zookeeper/data mkdir -p /data/zookeeper/logs mkdir -p /data/kafka/logs之所以把数据和程序分目录存放是为了后续扩容、升级、重装系统时数据目录可以挂独立的数据盘不会因为程序目录被清空而损失数据。生产环境强烈建议把数据目录放在单独的磁盘或分区上分布式系统三原则里数据安全永远是第一位的。把解压后的两个目录以及数据目录同步复制到 node2 和 node3。可以使用scp或rsyncscp -r /opt/zookeeper root192.168.10.12:/opt/ scp -r /opt/kafka root192.168.10.12:/opt/ rsync -avz /opt/zookeeper root192.168.10.13:/opt/ rsync -avz /opt/kafka root192.168.10.13:/opt/ # 记得也要创建对应的数据目录并在后续步骤修改所有者这里提醒一个小细节分发完成后各个节点上/opt/zookeeper、/opt/kafka的属主可能还是 root。如果打算用专用账号运行需要 chown 给对应账号。但很多生产环境中直接用一个普通账号运行全部服务这里可根据自己的安全规范灵活处理。3. ZooKeeper 集群部署与启动验证3.1 核心配置文件 zoo.cfg 解析ZooKeeper 的配置文件模板在$ZK_HOME/conf目录下名为zoo_sample.cfg。需要复制一份为zoo.cfg因为启动脚本只认这个名字。cp /opt/zookeeper/conf/zoo_sample.cfg /opt/zookeeper/conf/zoo.cfg编辑/opt/zookeeper/conf/zoo.cfg配置内容如下三个节点保持一致只有 myid 文件不同tickTime2000 initLimit10 syncLimit5 dataDir/data/zookeeper/data clientPort2181 maxClientCnxns60 autopurge.snapRetainCount5 autopurge.purgeInterval24 server.1node1:2888:3888 server.2node2:2888:3888 server.3node3:2888:3888逐一解释这些参数的含义这比盲目抄配置更有价值tickTimeZooKeeper 的最小时间单元单位毫秒。它决定了会话超时、心跳间隔等时间参数的基础刻度。2000 ms 即 2 秒是官方推荐且最普适的值。initLimitFollower 节点启动时与 Leader 节点完成初始同步的最大心跳周期数。这里配置为 10即允许最多 20 秒。网络环境较差时建议把此值调大否则可能出现启动即集群震荡的情况。syncLimitLeader 与 Follower 之间正常通信时的最大心跳周期数配置为 5 即最多 10 秒。如果超过这个时间没有收到消息Leader 会将该节点判定为不可用并剔除集群。dataDirZooKeeper 快照存储目录。这个目录要求 IO 性能较好建议不要放系统盘。必须提前手工创建目录否则启动会报错。clientPort客户端连接端口。应用与 ZooKeeper 交互都走这个端口默认为 2181。maxClientCnxns单台 ZooKeeper 服务器允许的最大客户端连接数默认 60。如果 Kafka 客户端数量很多建议适当调高。autopurge.snapRetainCount和autopurge.purgeInterval控制快照和事务日志的自动清理策略。前者保留最近 5 份快照后者表示每 24 小时执行一次清理任务。不配置的话长时间运行的 ZooKeeper 会积累大量快照文件造成磁盘空间溢出。server.1node1:2888:3888这个配置含义是集群中有三个 ZooKeeper 节点名称分别是server.1、server.2、server.3分别对应三个主机名。后面的两个端口含义是2888 用于 Leader 与 Follower 之间的数据复制通信用3888 用于 Leader 选举投票通信。这两个端口都是集群内部端口不要暴露到公网。3.2 创建 myid 文件myid是 ZooKeeper 集群识别节点身份的唯一凭证。它存放在dataDir目录下文件内容就是集群配置文件里对应的那份数字标识。在 node1 上执行echo 1 /data/zookeeper/data/myidnode2 上执行echo 2 /data/zookeeper/data/myidnode3 上执行echo 3 /data/zookeeper/data/myid写myid文件时文件里只允许有一个数字且不允许后面加换行以外的任何字符。我踩过加了一个空格导致节点身份无法识别的坑后来排查了很长时间才发现是这个问题。建议写完直接cat确认内容。3.3 ZK 启动脚本与状态校验启动前先放行防火墙端口。CentOS 7.9 默认 firewalld 是开启的需要放行 2181、2888、3888 三个端口sudo firewall-cmd --permanent --add-port2181/tcp sudo firewall-cmd --permanent --add-port2888/tcp sudo firewall-cmd --permanent --add-port3888/tcp sudo firewall-cmd --reload三个节点都放行后依次启动 ZooKeeper/opt/zookeeper/bin/zkServer.sh start启动信息里如果出现STARTED说明启动命令已成功执行。接着用状态命令查看当前节点的角色/opt/zookeeper/bin/zkServer.sh status正常输出应该是三种情况之一Mode: leader或Mode: follower。如果三个节点的命令都显示 leader说明配置有问题。更常见的异常是启动后卡住或提示无法连接其他节点这时候很可能是集群节点间的主机名解析不通去检查 /etc/hosts 吧。还可以用jps命令查看 Java 进程确认 QuorumPeerMain 进程是否存活jps另一个验证集群可用的方法是用四字命令echo stat | nc node1 2181如果返回了节点角色、收发消息数、连接数等信息说明集群正常工作。没有 nc 的话可以先yum install -y nc。ZooKeeper 的日志默认输出到控制台和$ZK_HOME/zookeeper.out文件。如果启动失败第一件事就是翻这个文件的尾部里面的异常信息比任何猜测都更直接tail -100 /opt/zookeeper/zookeeper.out3.4 ZooKeeper 集群异常排查方法论这里说几个 ZooKeeper 集群最典型的启动异常场景以及对应的排查链路。场景一启动后 status 提示 Error contacting service这表示本节点的 ZooKeeper 进程已经启动但无法与集群中其它节点正常通信。按这个顺序排查先检查三个节点的防火墙是否放行 2888 和 3888 端口再检查 /etc/hosts 中主机名是否全部映射正确接着用ping node2验证主机名是否能够解析最后查看 zookeeper.out 日志里是否有Cannot open channel to X at election address这类报错。场景二集群启动后反复选主节点角色不停切换多数情况下是 initLimit 设置偏小或者节点间的网络延迟偏高。把 initLimit 和 syncLimit 调大后重启即可。场景三客户端连接后频繁断连排查思路是先看 ZooKeeper 节点数是否不足三个单节点或双节点没有容错能力再检查maxClientCnxns是否设置过小最后查看服务器端 GC 日志确认是否存在长时间 Full GC 导致心跳超时。4. Kafka 集群部署与核心参数精讲4.1 server.properties 配置要点Kafka 集群的部署核心在于分清哪份配置会被哪个组件读取。脚本kafka-server-start.sh会读取config/server.properties所以我们要改的就是这个文件。进入/opt/kafka/config目录编辑server.propertiesbroker.id1 listenersPLAINTEXT://192.168.10.11:9092 advertised.listenersPLAINTEXT://192.168.10.11:9092 num.network.threads4 num.io.threads8 socket.send.buffer.bytes102400 socket.receive.buffer.bytes102400 socket.request.max.bytes104857600 log.dirs/data/kafka/logs num.partitions3 num.recovery.threads.per.data.dir1 offsets.topic.replication.factor3 transaction.state.log.replication.factor3 transaction.state.log.min.isr2 log.retention.hours168 log.segment.bytes1073741824 log.retention.check.interval.ms300000 zookeeper.connectnode1:2181,node2:2181,node3:2181 zookeeper.connection.timeout.ms18000 group.initial.rebalance.delay.ms0然后把这份配置复制到 node2 和 node3并分别修改两个参数node2 上broker.id2listeners和advertised.listeners改用 192.168.10.12。node3 上broker.id3listeners和advertised.listeners改用 192.168.10.13。重点解释几个容易出现理解偏差的地方。broker.id每个 Kafka 节点在集群中的唯一标识。可以配置任意字符串但建议和 ZooKeeper 的 myid 保持数字一致主要是为了管理方便。生产环境里不要动态修改 broker.id否则会导致 Kafka 内部元数据错乱旧分区副本无法正确归属。listeners 与 advertised.listeners这是初学者最容易踩的坑。listeners定义的是 broker 进程实际绑定并监听连接的地址和端口。而advertised.listeners是 broker 向客户端和 ZooKeeper 注册的对外发布地址客户端获取元数据后会拿着这个地址去连接 broker。这里的关键在于如果你把listeners配置为0.0.0.0:9092表示本机所有网卡的 9092 端口都会监听但如果advertised.listeners不显式设置Kafka 会默认把listeners里配置的主机名注册给客户端。若配置的是0.0.0.0客户端连接时会发现拿到一个不可路由的地址表现就是生产者能连上 ZooKeeper但一发送消息就报Connection refused或TimeoutException。所以推荐的做法是把两个参数都显式设置为对应节点的内网 IP不使用通配符。如果你的机器有多个网卡比如同时有内网、外网更要仔细规划每个地址的含义避免元数据广播错地址。log.dirsKafka 存储消息日志的目录。注意是复数形式可以配置多个目录并用逗号分隔。Kafka 会在这些目录间做数据分区提高磁盘并行吞吐能力。我这里只配置了一个目录是为了让示例更清晰生产环境如果是机械硬盘强烈建议挂多块盘配置多个目录。offsets.topic.replication.factor这是 Kafka 内部用来保存消费者位移offset的 Topic 的副本因子。生产环境必须设置为大于等于 2否则占用该内部 Topic 的 broker 宕机后消费者组的位移信息可能丢失。设置成 3 最稳配合三个节点的集群正好每个副本落一个节点。zookeeper.connect指向 ZooKeeper 集群的地址列表多个地址用逗号分隔。Kafka broker 启动时会连接这里把自己注册进集群并通过它感知其它 broker 的存在。配置全部三个地址是为了避免单点故障只要至少有一个 ZooKeeper 节点可用Kafka broker 就能正常工作。4.2 启动 Kafka 前要放行的防火墙端口Kafka broker 间通信使用的端口默认是 9092可自定义需要在三个节点上都放行sudo firewall-cmd --permanent --add-port9092/tcp sudo firewall-cmd --reload如果后续启用了 SSL 或 SASL 认证对应的端口也要一并放行。这一步漏掉的话往往会让 Kafka 的启动进程本身正常但客户端或其它 broker 连不上。4.3 启动 Kafka 并验证多 Broker 状态依次在三台机器上启动 Kafka/opt/kafka/bin/kafka-server-start.sh -daemon /opt/kafka/config/server.properties-daemon参数表示后台运行。不加这个参数关掉终端进程就结束了虽然也可以配合 nohup 实现但既然官方提供了参数直接使用是最稳妥的。启动完成后验证集群状态。Kafka 自带的工具脚本可以列出所有 broker 信息/opt/kafka/bin/zookeeper-shell.sh node1:2181 ls /brokers/ids正常会输出[1, 2, 3]表示三个 broker 都已在 ZooKeeper 中注册。如果输出的列表里只有部分 ID说明其它 broker 启动失败或注册延迟继续往下排查对应节点的启动日志。查看单个 broker 的详细信息/opt/kafka/bin/zookeeper-shell.sh node1:2181 get /brokers/ids/1输出里包含该 broker 的listeners、host、port等信息可以用来验证注册到 ZooKeeper 的地址是否与预期一致。也可以用jps查看 Kafka 进程关键类名是kafka.Kafka。4.4 验证 Kafka 集群的消息往来集群部署成功与否最终以消息能否正常往来为准。第一步创建测试 Topic/opt/kafka/bin/kafka-topics.sh --create \ --bootstrap-server node1:9092,node2:9092,node3:9092 \ --replication-factor 3 \ --partitions 3 \ --topic test-topic注意参数是--bootstrap-server而不是旧版本文档里常见的--zookeeper。Kafka 3.0 及以后的管理操作都推荐通过 broker 的端口来执行--zookeeper方式会提示废弃。这条命令会创建一个 3 副本、3 分区、名为 test-topic 的 Topic恰好让每个 broker 都保存一个分区的副本。第二步查看 Topic 详情确认副本分布/opt/kafka/bin/kafka-topics.sh --describe \ --bootstrap-server node1:9092 \ --topic test-topic输出中会看到每个分区的 Leader、Replicas、Isr 列表。正常情况是三个分区每个分区的 Leader 分布在不同 broker 上Isr列表里有三个节点。如果Isr列表缺少某个节点说明该节点的副本同步没跟上常见原因是磁盘 IO 慢或网络延迟高。第三步启动控制台消费者/opt/kafka/bin/kafka-console-consumer.sh \ --bootstrap-server node1:9092,node2:9092,node3:9092 \ --topic test-topic \ --from-beginning开一个终端执行这个命令它会阻塞等待消息。第四步另开终端启动控制台生产者并发送消息/opt/kafka/bin/kafka-console-producer.sh \ --bootstrap-server node1:9092,node2:9092,node3:9092 \ --topic test-topic输入任意字符串后回车消费者端应当能够立即收到。这表明集群整体链路已经通了。5. 高可用验证故障转移的真实表现5.1 杀掉 Leader 节点看 ZooKeeper 自愈搭建集群和验证集群的区别在于前者只证明配置正确后者则要证明系统具备自愈能力。先确认当前 ZooKeeper 集群的 Leader 是哪一台/opt/zookeeper/bin/zkServer.sh status假设返回结果显示 node1 是 leader。那么直接杀掉 node1 的 ZooKeeper 进程/opt/zookeeper/bin/zkServer.sh stop然后立刻去 node2 和 node3 上执行/opt/zookeeper/bin/zkServer.sh status几秒之内其中一台会从 follower 变成 leader。这个过程中如果有 Kafka 客户端正在发送消息理论上不会明显感知到 ZooKeeper 集群的问题因为 Kafka broker 已经记住了相关元数据只有在新的 broker 注册或客户端首次获取元数据时才会重新连接 ZooKeeper。再把 node1 重新启动/opt/zookeeper/bin/zkServer.sh start它会作为 follower 自动重新加入集群并从现役 leader 那里全量同步数据。这里有个值得注意的观察点ZooKeeper 的数据目录下会有 snapshot 和 transaction log 两种文件node1 重启后会基于最新的快照和增量日志恢复数据不需要外部干预。5.2 杀掉 Kafka Broker 节点看分区 Leader 切换Kafka 的分区自愈能力体现在分区副本的 Leader 迁移上。用--describe命令查看当前 broker 的分布找出哪个分区当前的 Leader 在某个节点上。比如 test-topic 的 partition 0 Leader 是 1然后杀掉 node1 的 Kafka 进程kill -9 $(jps | grep Kafka | awk {print $1})等待几秒后具体取决于zookeeper.connection.timeout.ms以及 controller 的检测机制再次执行 describe 命令/opt/kafka/bin/kafka-topics.sh --describe \ --bootstrap-server node2:9092 \ --topic test-topic你会看到原先的 Leader 已经切换为其它节点了。如果还没有切换说明该节点的副本不在 ISR 列表里优先级较高的 Follower 节点未满足条件。通常等 ISR 列表中的节点全部跟上之后控制器会自动完成 Leader 切换。这个过程对生产环境的意义很明显某个 broker 宕机只要该分区还有至少一个同步副本就不会造成读写中断。5.3 数据目录备份思路集群的高可用验证完毕后别急着写笔记先做一件事把 ZooKeeper 的dataDir和 Kafka 的log.dirs目录加入你的备份计划。ZooKeeper 挂了可以快速重建但数据丢了怎么都找不回来。生产环境里建议对这两个目录做周期快照或者文件级备份并保证备份文件存放在独立的存储设备上。6. 生产环境调优与值得记录的坑6.1 JVM 内存参数的修正默认情况下kafka-server-start.sh脚本里的堆内存配置比较保守启动命令里KAFKA_HEAP_OPTS通常为 1G。如果没有额外设置Kafka 只使用 1GB 堆内存。这在训练集群里没什么问题但到了生产环境分区数量上千时内存紧张会导致频繁 Full GC表现出来就是消息延迟飙升、消费者频繁掉线。推荐根据节点内存情况调整。如果是 16GB 内存的机器可以给 Kafka 分配 6GB 堆给 ZooKeeper 分配 4GB。修改kafka-server-start.sh文件在 JVM 参数块中设置export KAFKA_HEAP_OPTS-Xmx6G -Xms6G设置-Xms与-Xmx相同可以让 JVM 启动时就申请好内存减少运行过程中动态扩容带来的性能抖动。ZooKeeper 的 JVM 堆可以在zookeeper-env.sh中设置Linux 下默认值也是 1GB通过以下变量调整export ZOO_JVM_OPTS-Xmx4G -Xms4G注意别过度分配。ZooKeeper 和 Kafka 共用一台机器时要给操作系统和页缓存留足余量毕竟 Kafka 的读写性能很大程度上依赖 OS page cache。6.2 系统层面的网络与文件描述符优化Linux 默认对单进程可打开文件描述符数量有限制。Kafka 在高分区、多客户端场景下文件描述符数量轻松消耗数千默认的 1024 很容易被耗尽进而出现Too many open files异常。修改方式cat /etc/security/limits.conf EOF * soft nofile 65535 * hard nofile 65535 EOF同时修改/etc/sysctl.conf调大网络连接复用阈值net.ipv4.tcp_max_syn_backlog 4096 net.core.somaxconn 4096执行sysctl -p让配置立即生效。这些基础项的调整往往比花里胡哨的 Kafka 参数更有效。6.3 必须记录的几个典型坑坑一ZooKeeper 客户端端口被防火墙拦截现象是 Kafka broker 启动正常但一直打日志Unable to connect to zookeeper。排查时先确认 telnet 是否能通确认是防火墙问题后直接参考前面命令放行 2181。坑二Kafka 进程起来后或者节点间同步分区总超时先检查磁盘剩余空间以及磁盘 IO 速率。Kafka 对低速磁盘非常敏感一旦 IO 阻塞ISR 列表会发生收缩副本间同步持续超时。运行iostat -x 1可以快速确认磁盘是否成为瓶颈。坑三advertised.listeners 忘记改导致客户端连不上前面反复强调了这两个参数的作用。如果你的程序部署在其它机器上连接 Kafka 时能拿到元数据但连不上 broker十有八九是advertised.listeners配置错误。坑四kill -9 之后 broker 启动报错Kafka 进程被强制杀掉后在一些版本中可能出现某些索引文件损坏导致启动失败。解决方案是先启动单个 broker 并开启unclean.leader.election.enable相关的强制恢复参数或者重新初始化该 broker 的log.dirs目录。生产环境建议用kafka-server-stop.sh脚本优雅关闭除非真的无响应才用 kill -9。6.4 关于 systemd 托管的问题直接把 Kafka 和 ZooKeeper 用 nohup 启动的方式虽然快但进程被误杀后不会自动拉起。生产环境建议把两个服务配置为 systemd service实现开机自启和自动拉起。以 Kafka 为例创建一个/etc/systemd/system/kafka.service[Unit] DescriptionApache Kafka Server Requireszookeeper.service Afterzookeeper.service network.target [Service] Typesimple Userkafka Groupkafka EnvironmentKAFKA_HEAP_OPTS-Xmx6G -Xms6G ExecStart/opt/kafka/bin/kafka-server-start.sh /opt/kafka/config/server.properties ExecStop/opt/kafka/bin/kafka-server-stop.sh Restarton-failure RestartSec10 [Install] WantedBymulti-user.targetZooKeeper 的 service 文件构建思路类似只是ExecStart指向zkServer.sh start注意 ZooKeeper 脚本自身会 fork 出子进程所以Typeforking可能更合适。这里不再贴完整文件重点是领会托管思想。不过需要提醒的是systemd 配置好之后的验证环节不能省。设置开机自启后务必在不同节点上做一次完整重启测试确认服务是否真的会自动拉起。我见过不少配置了WantedBy但enable列表里没有设置导致重启后还是没启动的案例。7. Kafka 3.x 时代ZooKeeper 模式还是 KRaft 模式Kafka 3.0 之后引入了 KRaft 模式目标是逐步移除 ZooKeeper 依赖。但本指南选择 ZooKeeper 模式有充分的现实考量。KRaft 模式在 Kafka 3.0 中仍标记为 experimental直到 3.3 之后才逐步可用3.6 开始才被官方推荐用于生产。但 KRaft 和 ZooKeeper 模式在一个很长时间段内并行存在大量现有工具链、监控系统、周边组件依然优先适配 ZooKeeper 模式。如果你的团队刚接触 Kafka短期内不建议直接切 KRaft把 ZooKeeper 模式跑熟之后再考虑评估 KRaft 的优势。从学习角度说ZooKeeper 模式能让你深刻理解分布式协调服务的核心作用。从生产角度说ZooKeeper 模式经过了大规模生产环境的验证生态完整性更好。等到后续版本稳定、资料足够丰富时再规划迁移也不迟。8. 最后的经验分享整套部署流程走完后我个人最想强调的是集群搭建的难点不在某个具体参数而在基础环境的一致性。节点间的主机名解析、防火墙放行、数据目录权限、JVM 内存分配这些看似简单的点任何一个不一致都会以各种奇怪的方式影响到运行状态。实际维护这套环境一段时间后我养成了一个习惯每次变更配置前先备份、变更后重启服务并至少观察十分钟运行日志。分布式系统的故障很多时候不会在第一时间暴露可能某台机器负载一高问题才会浮现出来。部署初期建议先不套用任何自动化工具手动完成一遍所有步骤再做镜像。这个过程能帮你积累足够的排错经验同时也方便团队后续分类维护。当手动操作已经轻车熟路后再用 Ansible、Puppet 这类工具做批量部署和版本管理那时整套流程已经形成了内部知识沉淀自动化配置只是把已知步骤变成脚本不再是自己都不清楚原理的盲抄作业。踩过的坑多了之后你会发现越是大而全的教程越容易忽略基础细节。希望这篇记录能帮你少走我在集群搭建初期走过的弯路节省下来的时间足够你把消息链路上下游的工程细节再摸清楚一遍。
返回列表