最近把一个内部项目的消息队列从旧版自研组件迁到了 Kafka选定的版本是 Kafka-2.4.1。当时组里也有同事问为什么不用最新的版本其实理由很简单JDK 8 环境下跑得最稳、周边生态兼容性经过大量验证、该踩的坑网上基本都有答案。这篇文章就把 Kafka-2.4.1 从下载、配置、启动到集群部署的完整流程记录下来附带我在实际搭建中遇到的各种问题和解法给准备上手或者正在折腾 Kafka 的朋友一个参考。1. 版本选择与整体思路1.1 为什么是 2.4.1 这个版本Kafka 2.4.1 是 2020 年初发布的维护版本放在今天看确实不算新但它的定位非常清晰稳定。回到当时的选型场景我们的技术栈是 Java 8 Spring Boot线上部署在 CentOS 7Zookeeper 用的是 3.5.7Kafka 客户端基本以 Java 为主。Kafka 2.4.1 在功能上已经具备了生产环境最常用的一套能力幂等生产者、事务支持、增量式 rebalance 协议优化、消费组管理。后面几个大版本虽然引入了 KRaft、分层存储等新特性但在我们这种“业务系统多、消息量中等、运维团队不大”的环境里新特性往往意味着新坑没必要为了追新而增加排查成本。另外有一点容易被忽略Kafka 客户端和服务端版本是有兼容性讲究的。比如某些新版本的客户端连接旧版本 broker 时虽然一般能通但部分新协议特性会被静默降级。而 2.4.1 配合当时主流的 Spring Kafka 2.3.x/2.4.x官方测试覆盖非常充分搭配起来几乎不会出现莫名其妙的兼容问题。1.2 搭建前的需求梳理搭建 Kafka 之前先别急着下载安装包把下面几个问题想清楚能省掉后面一大半返工是单机演示环境还是生产多节点集群单机和集群的配置差异很大至少涉及 broker.id、副本因子、Zookeeper 连接串。消息量大概是什么级别每秒几百条和每秒几万条对应的分区数、JVM 堆内存、日志保留策略都不一样。是否已有独立的 Zookeeper还是打算用 Kafka 自带的单机 ZooKeeper生产环境我强烈建议单独维护 Zookeeper 节点尽量别和 Kafka 混布在同一批机器上。我当时的目标是搭一套“3 节点 Kafka 3 节点 Zookeeper”的小集群先跑通核心链路再逐步优化参数。所以在下面这些配置里很多数值都是按照这个规模来给的如果你只是本地测试可以适当缩小。2. 环境准备与基础依赖2.1 JDK 环境Kafka 2.4.1 依赖 Java 8Kafka 是 Java 写的这是最基础的前提。Kafka 2.4.1 官方明确要求 Java 8虽然你在 Java 11 上也能跑但很多生产环境排查问题时会发现官方测试主要基于 Java 8建议老实装一个 8u202 或更高版本的 JDK。java -version # openjdk version 1.8.0_302 # Java(TM) SE Runtime Environment (build 1.8.0_302-b08)注意一个细节Kafka 启动脚本会读取 JAVA_HOME如果 JAVA_HOME 没配置好即使 java 命令能执行Kafka 也可能起不来。建议在 /etc/profile 里把这行写清楚export JAVA_HOME/usr/local/java/jdk1.8.0_302 export PATH$JAVA_HOME/bin:$PATH配置完后 source /etc/profile再用 java -version 确认一次。这个步骤看起来简单实际操作中我见过好几回有人跳过去最后 Kafka 启动脚本直接报“JAVA_HOME is not set”。2.2 Zookeeper 选型与版本匹配Kafka 2.4.1 默认还需要 Zookeeper 做协调服务版本上官方推荐的组合是 Zookeeper 3.5.x。这里踩过一个坑当时一开始图省事用了 3.4.14结果 Kafka 启动后不断报 session 超时后来才发现 3.4.x 对一些新建的 watcher 处理方式和 3.5.x 有差异换了 3.5.7 之后问题消失。Zookeeper 下载路径不再赘述但装完之后目录结构建议这样规划/opt/zookeeper ├── bin ├── conf ├── data └── logs其中 data 目录是 ZK 的数据目录logs 是事务日志目录两者最好分开放在不同的磁盘挂载点上避免 I/O 争抢。conf 目录下的 zoo.cfg我用的核心配置如下tickTime2000 initLimit10 syncLimit5 dataDir/opt/zookeeper/data dataLogDir/opt/zookeeper/logs clientPort2181 maxClientCnxns60如果做 Zookeeper 集群还需要在 zoo.cfg 里加 server.1、server.2、server.3 的节点声明并在 dataDir 下创建 myid 文件写入对应编号。这些细节看起来基础但漏一个 Kafka 连不上 ZK 的概率就大一分。2.3 Kafka 二进制包下载与目录规划Kafka 2.4.1 的二进制包可以从 Apache 镜像站获取文件名是 kafka_2.12-2.4.1.tgz其中 2.12 是指 Scala 编译版本不是 Kafka 版本号很多新手在这会被搞混。下载解压之后我习惯把目录放在 /opt/kafka并且做一个当前版本软链方便以后升级tar -zxvf kafka_2.12-2.4.1.tgz -C /opt ln -s /opt/kafka_2.12-2.4.1 /opt/kafkaKafka 解压后的目录结构里重点关注这几个位置bin启动脚本目录包含 kafka-server-start.sh、kafka-topics.sh 等工具。config服务端和客户端配置文件目录。logsKafka 服务端自己的运行日志目录注意它与 Kafka 的“消息数据日志目录”不是一回事。消息数据目录默认在 config/server.properties 里配置的 log.dirs比如 /data/kafka-logs建议挂载到大容量磁盘上。这里可以先把目录创建好mkdir -p /data/kafka-logs chown -R kafka:kafka /data/kafka-logs关于运行用户生产环境不建议直接用 root 跑 Kafka创建一个低权限用户更稳妥。我当时的做法是创建了一个 kafka 系统用户所有 Kafka 相关目录归属到这个用户下避免权限越界。3. Kafka 核心配置逐项拆解3.1 broker 基础身份配置Kafka 的配置文件是 config/server.properties。刚打开这个文件时会看到一堆注释和默认值如果直接全默认启动也能跑但那样部署出来的服务在集群环境会有各种隐性问题。我把每个关键配置项按照“用途-推荐值-原因”的方式过一遍。首先是 broker.id这是每个 broker 的唯一编号集群内不能重复。单机环境默认是 0 即可broker.id0其次是 listeners 和 advertised.listeners这两个配置非常关键。listeners 定义 broker 对外绑定的地址和端口advertised.listeners 是 broker 注册到 Zookeeper 并告诉客户端“你可以通过这个地址访问我”的地址。常见错误是只配了 listeners结果跨机器访问时客户端拿着 Zookeeper 里的内网地址去连连不通。单机测试可以这样写listenersPLAINTEXT://0.0.0.0:9092 advertised.listenersPLAINTEXT://192.168.1.101:9092注意 advertised.listeners 这里的 IP 要写客户端实际能访问到的地址如果用 Docker 部署这里尤其要谨慎配置容器内和容器外的网络地址往往不一样。3.2 存储与日志保留策略Kafka 把消息持久化在 log.dirs 所指向的目录里这个目录可以配置多个用逗号分隔。多个目录时 Kafka 会按照“分区目录大小均衡”的策略分配而不是简单轮询。我当时只用了一个数据目录log.dirs/data/kafka-logs接下来是日志保留策略这直接关系到磁盘使用。Kafka 的日志保留有两个维度时间retention.ms / retention.hours和大小retention.bytes。默认是保留 7 天不限制大小。对于消息量不大的内部系统保留 7 天完全够用log.retention.hours168 log.retention.check.interval.ms300000还有一个 log.segment.bytes 参数默认 1GB。它表示单个日志段文件的大小上限。这个值不要太小不然会产生大量小文件但也不要盲目调大因为日志清理是按段文件为最小单位的段文件越大清理时释放空间的延迟就越高。对于日志留存这里有个实际的教训有一次我发现某个 topic 的磁盘占用异常大排查发现是有消费者下线了但生产端一直在发消息而 Kafka 的日志保留删除只针对已提交的消息未消费的消息默认不会被删除。也就是说消息保留时间到了之后如果消费者组没消费完Kafka 依然会删除旧消息但消费者用 offset 去拉时就会触发 OffsetOutOfRange 异常。这一点很多人会搞混留在后面的常见问题里细说。3.3 网络线程与并发模型Kafka 的网络模型可以简单理解为客户端请求先进 acceptor 线程然后交给网络线程处理网络读写再交给 IO 线程即 ReplicaFetcherThread 和 KafkaRequestHandlerPool执行实际的消息写入。这几个线程数的配置直接决定高并发下的吞吐num.network.threads8 num.io.threads16 queued.max.requests1024一般服务器 CPU 核数在 8 到 16 之间时网络线程配 4 到 8IO 线程配 8 到 16都能获得不错的性能。如果 CPU 核数很多比如 32 核可以适当调大。但没必要盲目堆线程线程切换开销也会反噬吞吐。此外还有两个核心参数需要留意num.partitions默认新建 topic 的分区数默认值是 1。如果你的业务消息量预期较大建议提前改掉比如设成 8 或者 12。这个参数只影响新建的 topic已存在的 topic 不受影响。default.replication.factor默认副本因子单机环境必须保持为 1集群环境建议至少是 2。如果服务端配置了副本因子大于 1而实际可用副本数不足生产时会直接报 NotEnoughReplicas 异常。我们集群的 topic 创建命令通常这样指定分区和副本因子/opt/kafka/bin/kafka-topics.sh --bootstrap-server kafka1:9092 --create \ --topic order-event \ --partitions 8 \ --replication-factor 23.4 JVM 与操作系统级参数调优Kafka 启动脚本默认的 JVM 堆内存是 1GB这个数值对新环境来说偏小。生产环境中Kafka 的堆内存主要用来缓存消息批次和各类索引结构在页缓存充足的前提下堆内存需求反而不是特别高。一般给 4GB 到 8GB 已经可以覆盖很大一部分场景。修改方式是编辑 bin/kafka-server-start.sh 里的 KAFKA_HEAP_OPTSexport KAFKA_HEAP_OPTS-Xmx4G -Xms4G注意这里 Xmx 和 Xms 设成一样避免 JVM 动态伸缩带来性能抖动。操作系统层面有一个参数值得关注文件描述符上限。Kafka 作为分布式消息中间件会打开大量文件句柄尤其是 topic 分区多、客户端连接多的时候。用 ulimit -n 确认一下如果只有 1024那就不用等到高并发连接数稍微涨一点就会报 Too many open files。ulimit -n 65535如果要做成永久配置需要修改 /etc/security/limits.conf加上类似这样的行kafka soft nofile 65535 kafka hard nofile 655353.5 可选配置自动创建主题与删除主题开关Kafka 默认开启 auto.create.topics.enable。这个设计本意是方便生产端直接往不存在的 topic 发消息时自动创建但在生产环境这是一个隐患某个客户端如果 topic 名字写错了Kafka 会悄悄帮你创建一个分区数为默认值的新 topic后续排查时你会发现一堆不明来源的 topic。我习惯在集群里把它关掉auto.create.topics.enablefalse delete.topic.enabletruedelete.topic.enabletrue 这个参数影响的是执行 kafka-topics.sh --delete 时是否会真正删除数据。默认情况下它是 false也就是说你执行删除命令后 topic 只是被打上删除标记数据并不会立即物理删除。刚开始接触 Kafka 的人经常会遇到“删除 topic 后还在”的困惑根源就在这个参数。4. 启动流程与功能验证4.1 启动 Zookeeper 并确认健康状态配置完成后第一步是先启动 Zookeeper因为 Kafka 启动时要向 ZK 注册元数据。如果 ZK 没起好Kafka 进程可能能起来但会在日志里反复刷连接异常。启动 ZK/opt/zookeeper/bin/zkServer.sh start确认 ZK 健康状态/opt/zookeeper/bin/zkServer.sh status还可以用 ZK 自带的客户端工具验证一下/opt/zookeeper/bin/zkCli.sh -server 127.0.0.1:2181 # 连接成功后会进入交互模式输入 ls / 查看根节点ZK 启动成功后根节点下会逐步出现 /brokers、/consumers、/config 等路径这些是 Kafka 运行时自动创建的。如果你看到这些节点说明 Kafka 元数据已经成功注册到了 ZK。4.2 启动 Kafka 服务端Kafka 的启动命令很简单前提是配置文件没有问题/opt/kafka/bin/kafka-server-start.sh /opt/kafka/config/server.properties如果想要后台启动并输出日志到指定文件使用nohup /opt/kafka/bin/kafka-server-start.sh /opt/kafka/config/server.properties \ /var/log/kafka/kafka.out 21 启动过程中最值得关注的日志是 /opt/kafka/logs/server.log。正常启动时最后一行应该出现类似这样的内容INFO [KafkaServer id0] Started (kafka.server.KafkaServer)如果启动失败也基本能从日志里定位到问题类型。常见的有端口被占用、ZK 连不上、配置项格式错误等。4.3 执行一场“生产-消费”实测服务起来了怎么能确认这条链路是通的最快的方式是手动创建一个 topic然后通过控制台生产者和消费者分别发一条消息验证。这个步骤强烈建议不要跳过因为只有实际跑通一遍才能确认配置文件里的 advertised.listeners 等网络配置真的没问题。创建 topic/opt/kafka/bin/kafka-topics.sh --bootstrap-server localhost:9092 \ --create --topic test-topic --partitions 3 --replication-factor 1查看 topic 详情/opt/kafka/bin/kafka-topics.sh --bootstrap-server localhost:9092 \ --describe --topic test-topic结果类似Topic: test-topic PartitionCount: 3 ReplicationFactor: 1 Topic: test-topic Partition: 0 Leader: 0 Replicas: 0 Isr: 0 Topic: test-topic Partition: 1 Leader: 0 Replicas: 0 Isr: 0 Topic: test-topic Partition: 2 Leader: 0 Replicas: 0 Isr: 0Leader、Replicas、Isr 都能对应到 broker.id说明元数据已正确注册。然后开一个终端启动消费者/opt/kafka/bin/kafka-console-consumer.sh --bootstrap-server localhost:9092 \ --topic test-topic --from-beginning再开另一个终端启动生产者并发送消息/opt/kafka/bin/kafka-console-producer.sh --bootstrap-server localhost:9092 \ --topic test-topic hello kafka this is a test此时消费者端应立即打印出这两条消息。如果消费端迟迟不见消息先别急着怀疑代码或脚本可以从这几个方向排查消费者是否在同一个消费组默认 console-consumer 是临时组、bootstrap-server 是否 broker 实际监听的地址、能不能 telnet 通 9092 端口。4.4 用 systemd 管理 Kafka 进程直接 nohup 启动的方式适合临时测试。生产环境建议把 Kafka 和 Zookeeper 都交给 systemd 管理实现开机自启和异常退出自动拉起。以 Kafka 为例我创建了 /etc/systemd/system/kafka.service[Unit] DescriptionApache Kafka server Afternetwork.target zookeeper.service [Service] Typesimple 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 RestartSec30 [Install] WantedBymulti-user.target配置好后执行systemctl daemon-reload systemctl enable kafka systemctl start kafka systemctl status kafka这里有一个实际经验RestartSec 不要设太短。Kafka 启动通常需要几十秒如果进程因为启动缓慢被 systemd 判定为启动超时而你设置的 RestartSec 又很短可能陷入频繁重启循环。我在初期调试配置时遇到过一次后来把超时时间和重启间隔都放宽才稳定下来。5. 从单机到集群高可用实施方案5.1 集群部署架构规划如果业务量不大单节点 Kafka 也能跑但一旦消息通道成为关键链路broker 宕机意味着整个上游到下游的数据管道断裂所以生产环境至少要 3 个 broker 起步。我当时规划的集群是 3 台机器分布在同一内网网段。Zookeeper 也是 3 台跟 Kafka 分开部署避免相互影响。主机名角色ZK 端口Kafka 端口zk1Zookeeper 12181-zk2Zookeeper 22181-zk3Zookeeper 32181-kafka1Kafka Broker 1-9092kafka2Kafka Broker 2-9092kafka3Kafka Broker 3-9092这种方式拆分的机器数量较多但故障隔离效果好。如果资源紧张也可以把 ZK 和 Kafka 混布在 3 台机器上但要注意 JVM 堆内存和磁盘 IO 的争抢。5.2 集群关键配置差异集群模式下每台 Kafka 节点的 server.properties 有以下几项必须逐一修改broker.id每台节点不同依次为 0、1、2。zookeeper.connect需要把所有 ZK 节点都写进去用逗号分隔zookeeper.connectzk1:2181,zk2:2181,zk3:2181注意这里不要加 chroot 路径也能正常部署但生产环境我建议为 Kafka 指定单独的 ZK 命名空间即zookeeper.connectzk1:2181,zk2:2181,zk3:2181/kafka这样做的好处是如果同一个 ZK 集群上还有其他组件比如其他版本的 Kafka、某些大数据组件它们的元数据节点不会相互覆盖。ZK 端不需要额外创建 /kafka 节点Kafka 启动时检测不到会自动创建。advertised.listeners集群里特别重要它要写其他机器能访问到的地址。如果这里写成了 localhost那其他 broker 之间同步数据时就会去连自己本机直接报连接失败。我在三台机器上的配置类似# kafka1 broker.id0 listenersPLAINTEXT://0.0.0.0:9092 advertised.listenersPLAINTEXT://kafka1:9092 log.dirs/data/kafka-logs # kafka2 broker.id1 listenersPLAINTEXT://0.0.0.0:9092 advertised.listenersPLAINTEXT://kafka2:9092 log.dirs/data/kafka-logs # kafka3 broker.id2 listenersPLAINTEXT://0.0.0.0:9092 advertised.listenersPLAINTEXT://kafka3:9092 log.dirs/data/kafka-logs副本因子相关参数单机环境是 replication.factor1集群环境建议改为 2 或 3default.replication.factor2 min.insync.replicas1注意 min.insync.replicas 要和生产者端的 acks 配合使用。如果生产者设置 acksall而 min.insync.replicas2那么至少要有 2 个副本同步完成才会返回成功如果集群里实际可用副本只有 1 个生产就会报 NotEnoughReplicas。这个参数需要在可用性和一致性之间做权衡业务对消息丢失敏感的场景建议 min.insync.replicas2对可用性要求更高的场景可以设成 1。5.3 集群启动顺序与副本分配验证集群启动顺序上建议先把 3 台 ZK 全部启动再按 broker.id 顺序依次启动 Kafka。其实 Kafka 不要求强制的启动顺序但如果 ZK 没就绪就启动 Kafkabroker 会一直重试连接虽然最终也会连上但日志里的报错会误导排查方向。全部启动后用 kafka-topics.sh 查看集群状态/opt/kafka/bin/kafka-topics.sh --bootstrap-server kafka1:9092,kafka2:9092,kafka3:9092 \ --describe --topic test-topic正常情况下分区副本会分布在不同 broker 上比如Topic: test-topic PartitionCount: 3 ReplicationFactor: 2 Topic: test-topic Partition: 0 Leader: 1 Replicas: 1,2 Isr: 1,2 Topic: test-topic Partition: 1 Leader: 2 Replicas: 2,0 Isr: 2,0 Topic: test-topic Partition: 2 Leader: 0 Replicas: 0,1 Isr: 0,1看到 Isr 列表与 Replicas 一致说明副本同步正常。这里我习惯性停掉其中一个 broker 做一次故障演练确认剩下的两个节点能不能继续完成消息的读写。演练完再启动该节点观察新增的副本能否自动追平。5.4 控制器与分区平衡Kafka 集群里有一个特殊角色叫 Controller它负责分区 leader 选举和元数据管理。第一个启动的 broker 通常会竞选成为 Controller。如果 Controller 节点挂了其余 broker 会自动重新选举不用人工干预。相关日志会输出 controller 变更信息排查问题时可以留意。集群运行一段时间后可能出现分区在各节点上分布不均的情况尤其是新增节点或节点宕机恢复后。这时可以使用官方提供的 kafka-reassign-partitions.sh 脚本把分区重新平衡一下。操作步骤是先把当前分布导出一个 JSON 文件再通过 --generate 生成目标方案确认后执行 --execute最后用 --verify 检查状态。这个操作对在线集群是安全的但建议在低峰期执行因为分区迁移会有额外的网络和磁盘 IO 开销。6. 常见问题与排查实录6.1 “连接不上”类问题排查思路在搭建和后续使用中我遇到最多的就是连接类问题。这里整理一张速查表按“出现位置、常见原因、解决办法”的方式列出现象可能原因处理方式生产者报 Connection refusedbroker 没启动或端口被防火墙拦截检查 broker 进程、telnet 9092 端口消费者报 TimeoutExceptionadvertised.listeners 配置不对在客户端机器上执行 telnet 到 advertised 地址跨网络访问失败配了 listeners 但没配 advertised.listeners补上 advertised 内网/外网地址启动时报 zookeeper 连接超时ZK 节点地址写错或 ZK 未启动先单独验证 ZK 端到端连通性其他机器连不上本机 broker防火墙没有放行 9092/2181临时用 firewall-cmd 或 iptables 放行确认后固化配置关于 advertised.listeners 有一个较隐蔽的场景Kafka broker 之间的副本同步会默认使用 advertised 地址如果配成了 127.0.0.1那其他 broker 拉取该节点的副本数据时就会扑空。日志里表现为 Repeated fencing / Fetch from follower 超时。这种问题在单机环境完全复现不了只有上集群或跨机器消费的时候才暴露。6.2 磁盘占用不断上涨与“删除不生效”日志保留策略配置正确的前提下Kafka 会在消息到期后删除旧日志段。但“到期删除”不等于“实时释放”它存在一个时间窗口。Kafka 的日志清理线程默认每 300 秒检查一次而且删除动作发生在 log.segment.bytes 指定的段文件边界上。换句话说哪怕 retention 设的是 1 小时那 1 小时内一直在活跃写入的日志段当前写入中的 active segment也不会被删除只有滚动到历史段后才会按策略处理。如果磁盘占用长期居高不下除了检查 retention 配置还要看是不是有主题的生产速率远超预期。另外一个重要方向是查看消费者消费情况Kafka 删除旧消息不依赖消费者状态但它清理的是“过期数据”这一层如果消费者拿 offset 去拉取已删除的过期消息会直接抛 OffsetOutOfRangeException这和“消息被堆积未消费”是两码事不要混淆。我在实践中见过一个 case某个环境日志保留设了 2 小时但有一个 topic 单日写入量达到几个 GB磁盘很快告警。后来定位发现是该环境的一个重要业务 pod 因为配置错误把日志输出到 Kafka相当于把消息系统当成了日志收集系统。这种问题改配置没用要从源头业务侧治理。6.3 消费者组 “rebalance 风暴”Kafka 2.4.1 对 rebalance 协议做了不少优化但“频繁 rebalance”依然是消费端最常见的稳定性问题之一。典型表现是消费者组成员频繁加入退出导致整个消费组反复进入 rebalance 状态此时消费吞吐骤降甚至出现重复消费。我遇到的一个场景是单个消费者处理消息耗时特别久超过了 max.poll.interval.ms 默认值 300 秒消费者客户端和 broker 之间的心跳判定超时于是 broker 认为该消费者已死亡触发 rebalance把它负责的分区重新分配给其他成员。而其他成员负载变高后也相继超时形成连锁反应。解决方案有两类调参把 max.poll.interval.ms 调大或者把 max.poll.records 调小让单次 poll 返回的消息量降低处理时长缩小到安全范围内。优化消费逻辑把耗时的 IO 操作移出消息处理的同步路径先快速提交 offset再异步处理。另外有一点值得提醒Kafka 消费端不建议同时把多个不同用途的业务处理逻辑放在同一个消费者组里因为一个组的消费能力受限于组内最慢的成员慢成员会拖垮全组。6.4 副本不同步与 ISR 收缩ISRIn-Sync Replicas是 Kafka 高可用的核心。当某个副本长期落后于 leader 或者与 leader 的通信中断它会被从 ISR 中剔除。ISR 内副本数量下降会导致全局可用性退化。检查命令很简单/opt/kafka/bin/kafka-topics.sh --bootstrap-server kafka1:9092 --describe重点看每个分区的 Isr 列表是否等于 Replicas 列表。如果出现 Isr 小于 Replicas 的情况去对应 broker 的 server.log 查 Fetch 相关报错。常见原因包括副本所在机器磁盘 IO 过高导致日志同步落后阈值replica.lag.time.max.ms 默认 30 秒。网络延迟或带宽不足Follower 拉取 leader 数据超时。JVM GC 停顿过长导致处理线程停滞。我遇到过最奇怪的一次是 Follower 在拉数据时总是超时排查发现那台机器的网卡因为驱动问题间歇性丢包换了一块网卡后问题消失。这类问题在节点数量少的小集群里尤其隐蔽因为它不会体现在 Kafka 自身日志中而是要靠系统层面的监控数据才能定位。6.5 从实操角度补充的几件事Kafka 的日志和消息数据目录要定期观察不要等磁盘满了再处理。建议至少加一层磁盘使用率监控阈值设在 70% 就开始告警。不要随意手动删除数据目录下的文件。Kafka 的数据是有内部索引结构的直接删文件可能导致索引和数据不一致甚至起不来。升级 Kafka 前先把新版本的 config 和旧版本的 config 做一次 diff很多参数在新版本中的默认值已经改变了比如最早的 num.io.threads 默认值调整会直接影响性能表现。脚本里的 KAFKA_HEAP_OPTS 会根据机器内存大小变更不要太依赖默认值每台机器都确认一下。关于稳定运行的一点个人体会把 Kafka 2.4.1 从零搭起来其实并不难真正难的是后续的运维和调优。我在搭建过程中最大的体会是Kafka 的配置参数之间经常是相互关联的单独看某一个配置都“说得通”但组合在一起才会暴露出问题。比如 rebalance 问题表面上是消费端参数配置问题实质上是消费链路整体设计的问题。如果让我给刚开始接触 Kafka 的人一句话那就是先跑通最小链路再逐步加机器、加配置、加监控。单机环境把基础流程摸熟了集群部署就是重复劳动排查问题的思路也能沿用到生产环境。最后再分享一个小技巧每次修改完 server.properties 并启动前可以先用 kafka-server-start.sh 启动一次前台模式观察前几秒日志没有异常再 CtrlC不要直接 nohup 后台跑这样能省掉不少反复看日志的操作。
阅读完成 · 觉得有帮助?