Kafka 2.8 KRaft模式实战:无ZooKeeper集群部署与配置详解
发布时间:2026/10/17 17:20:17 锦皓数字建站

1. 站在2.8这个版本门槛前为什么要去掉Zookeeper先说结论Kafka从2.8版本开始正式允许你在一片没有Zookeeper的世界里运行Kafka集群。这可不是一个小改动这是Kafka社区憋了好几年的大招——把Zookeeper从Kafka的架构里踢出去让Kafka自己管理自己的元数据。官方管这套新机制叫KRaft模式对应的就是传统的ZooKeeper模式。我在第一次听到这个消息的时候第一反应是终于来了。做Kafka运维的人都清楚Zookeeper一直是Kafka集群里最让人头疼的部分。它本身是一个独立的分布式协调系统有自己的一套选举机制、会话超时、数据模型你得额外维护一整套ZK集群还得操心它的性能、监控、扩容。尤其是当Kafka的 broker 节点数量变大、分区数量变多之后Zookeeper常常成为瓶颈。很多生产事故的根源最后都能追溯到Zookeeper的GC停顿、session超时、节点脑裂之类的问题上。Kafka 2.8里KRaft模式还标注为生产环境初步可用也就是说官方认为它已经能跑生产负载了但仍未完全替代ZooKeeper模式。真正到了3.3之后KRaft才被标记为生产就绪而ZooKeeper模式在3.5版本被标记为deprecated。但2.8这个版本对于想提前尝鲜、想了解这套新架构原理的人来说反而是个特别好的切入窗口。这篇文章主要面向两类人。一类是原来维护过ZooKeeper模式Kafka集群的运维或者开发想搞清楚KRaft到底改了什么、部署配置和以前有什么不同另一类是从零开始接触Kafka、没怎么碰过ZK的新手想直接按照KRaft模式把一套集群搭起来。写的时候我会把配置文件的每个参数都拆开讲尽量让你照着操作就能复现。我自己的建议是如果你要在生产环境上跑可以考虑直接上3.3以上版本但如果你想理解这套机制的设计思路2.8的实验集群是非常好的学习载体。2. KRaft模式下Kafka内部到底发生了什么变化在动手部署之前先把架构层面的东西聊透。很多人一上来就照着配置文件敲敲完发现集群起不来然后各种排查最后发现是对新架构理解有偏差。与其这样不如先花十分钟弄清楚KRaft模式下Kafka的组件边界、角色划分和数据流后面排查问题会轻松很多。2.1 控制平面和数据平面从外部协调到内部自治在ZooKeeper架构下Kafka的元数据存放在外部的ZK集群里包括集群里有哪些broker节点每个Topic有哪些分区、分区副本分布在哪些broker上每个分区的ISR同步副本列表消费者组的位移信息旧版本依赖ZK新版本用内部Topic存储各种动态配置Kafka的控制器Controller是一个特殊的broker角色它负责监听ZK中的状态变化然后向其他broker下发指令。一旦控制器所在的broker挂了剩下的broker要通过ZK重新选举一个新的控制器。这里涉及到大量的分布式协调逻辑ZK的读写在高峰期会成为瓶颈。KRaft模式做的事情本质上是把ZK负责的那部分元数据存储功能搬进了Kafka自己的内部日志系统。这个内部日志系统本身就是一个单分区的Topic名字叫__cluster_metadata。Kafka用自己最擅长的复制日志机制来保证元数据的一致性和高可用不再需要一个外部组件来协调。这样改完之后控制平面元数据管理和数据平面消息读写就完全统一在Kafka自身内部了。你不需要再关心ZK集群的容量规划不需要再单独监控ZK的健康状态也不需要担心ZK和Kafka的版本兼容性。整个系统的组件数量减少了一个这在运维层面是一个巨大的简化。2.2 Controller节点与Broker节点两种角色的分离在KRaft模式下节点角色被抽象得更加清晰。一个节点可以是Controller控制器节点只负责元数据管理不处理数据读写Broker数据节点只处理消息的读写请求不参与元数据管理Combined混合节点同时承担Controller和Broker两种角色在2.8版本里官方推荐的做法是用三个节点组成一个Controller集群再用若干个节点组成Broker集群。但小规模实验环境完全可以用三个Combined节点也就是每个节点既当Controller又当Broker这样最省机器。后面我会给出这种部署的完整配置。这里有个很重要的变化在ZK模式下Controller是从所有broker中选举出来的一个谁当选谁就是Controller而KRaft模式下Controller是一个独立配置的角色一个节点是不是Controller写在配置文件里启动时固定下来。换句话说Controller不再是选出来的而是配置出来的。不过需要说明的是Controller节点之间仍然有选举机制。多个Controller节点会通过KRaft内部的投票协议选出一个Active Controller其余作为Standby Controller。只是这个过程不依赖ZK了而是基于元数据日志的复制和投票完成的。2.3 元数据日志__cluster_metadata内部Topic的工作方式KRaft模式的核心数据结构是元数据日志它记录着集群所有元数据的变更事件每条记录就是一次元数据变更。比如创建了某个Topic、某个分区Leader切换了、某个broker上线了这些事件都会被追加到元数据日志中。这个日志被保存在所有Controller节点上并且是持久化的。Controller节点通过类似Raft共识算法的方式在日志条目之间进行复制和投票保证所有存活的Controller节点对元数据日志的内容达成一致。当一个Controller节点从故障中恢复时它会重新读取元数据日志把自己的状态恢复到最新。在2.8版本里这个元数据日志还只能在Controller节点上读写。Broker节点会定期从Active Controller拉取元数据快照和变更事件然后缓存在本地。所以Broker本地的元数据可能比Controller稍微滞后一点但不会差很多因为Controller会主动推送变更。需要特别注意的地方是__cluster_metadata这个内部Topic不是由你手动创建的它是Kafka在格式化存储目录的时候自动生成的。你不需要也不应该手动去干预它否则会破坏元数据的一致性。3. 环境准备与安装过程从JDK到Kafka二进制包这部分实际操作起来并不复杂但有几个细节容易踩坑我一个个说清楚。我的实验环境规划是三台Linux服务器每台2核4G内存系统是CentOS 7。3.1 三台机器的节点规划先规划好角色和IP后面配置的时候直接对照着写就行节点IPController角色Broker角色主机名node1192.168.10.11是是kafka1node2192.168.10.12是是kafka2node3192.168.10.13是是kafka3三个节点都配置为Combined角色也就是既当Controller又当Broker。这是官方文档里的小规模部署推荐方式同时也是最省资源的方式。如果你以后要扩展可以把Controller和Broker拆开部署但从这个基础架构往任何方向演进都不难。3.2 JDK环境检查Kafka 2.8运行需要Java 8或者Java 11我自己用的是JDK 1.8。先检查一下系统里面有没有装java -version如果输出类似下面这样的内容说明环境OKjava version 1.8.0_292 Java(TM) SE Runtime Environment (build 1.8.0_292-b10) Java HotSpot(TM) 64-Bit Server VM (build 25.292-b10, mixed mode)如果没装用包管理器装一个sudo yum install -y java-1.8.0-openjdk-devel装完之后确认JAVA_HOME环境变量是不是正确指向了JDK路径。Kafka的启动脚本kafka-server-start.sh会读取这个变量如果它没设置脚本会尝试自动查找Java路径但最好还是手动配置。3.3 Kafka 2.8安装包下载与部署目录规划Kafka的二进制包会同时包含ZooKeeper相关组件和KRaft相关组件你不需要额外下载什么特殊版本。下载地址这里就不贴了直接去Apache官网下载kafka_2.13-2.8.0.tgz大概几十MB。三台机器都执行同样的下载和解压操作cd /opt wget https://downloads.apache.org/kafka/2.8.0/kafka_2.13-2.8.0.tgz tar -zxvf kafka_2.13-2.8.0.tgz mv kafka_2.13-2.8.0 kafka注意Kafka安装包文件名里的2.13是Scala编译版本后面的2.8.0才是Kafka自身版本两者不要搞混。在写依赖或者做版本兼容性判断的时候要明确用的是哪一个。4. 配置文件逐行拆解server.properties里每个参数的含义KRaft模式下Kafka的配置文件还是叫server.properties但里面的参数和ZK模式有很多不同。很多刚开始接触KRaft的人最不习惯的就是这一点——你打开配置发现zookeeper.connect不见了多了几个全新的controller.*参数然后整个人的思路就乱了。这里我把核心参数一个一个解释清楚。4.1 基础标识参数process.rolesbroker,controller node.id1 controller.quorum.voters1kafka1:9093,2kafka2:9093,3kafka3:9093process.roles这是KRaft模式新增的核心参数指定节点承担什么角色。可选值有broker、controller、broker,controller。三个节点这里都填broker,controller表示同时承担两种角色。node.id节点的唯一ID在ZK模式下叫broker.idKRaft模式把它改名为node.id。三个节点分别是1、2、3全局唯一。controller.quorum.voters这个参数是KRaft最关键的配置它列出了所有Controller节点的地址和端口格式是nodeIdhost:port,nodeIdhost:port。注意这里写的是Controller之间的通信端口不是客户端访问Kafka的端口也不是broker之间通信的端口。所有节点上的这个参数必须完全一致。这里有一个很容易搞混的点controller.quorum.voters里的端口9093是用来跑Controller之间元数据复制和投票的它和broker对外提供消息读写服务的端口9092是不同的。在Combined模式下一个节点会同时监听两个端口各干各的。4.2 网络监听参数listenersPLAINTEXT://kafka1:9092,CONTROLLER://kafka1:9093 advertised.listenersPLAINTEXT://kafka1:9092 controller.listener.namesCONTROLLER listener.security.protocol.mapCONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT,SSL:SSL,SASL_PLAINTEXT:SASL_PLAINTEXT,SASL_SSL:SASL_SSL inter.broker.listener.namePLAINTEXTlisteners节点启动时绑定的监听地址列表。这里配置了两个协议PLAINTEXT用于broker之间的数据传输和客户端连接CONTROLLER专门用于Controller通信。advertised.listeners这个参数是告诉客户端你可以通过这个地址访问我。在ZK模式下这个参数也很重要尤其当broker部署在NAT环境或者Docker容器里的时候很容易因为内外IP不一致导致连不上。我这里直接填的是节点自身的主机名和9092端口。controller.listener.names指定Controller通信使用的是哪个监听器名称这里就是CONTROLLER。listener.security.protocol.map把监听器名称映射到具体的安全协议。CONTROLLER映射为PLAINTEXT意思是Controller之间使用明文通信不加密。inter.broker.listener.namebroker与broker之间通信使用的监听器名称。这里指定为PLAINTEXT也就是走9092端口。4.3 日志存储与持久化参数log.dirs/data/kafka-logslog.dirs指定Kafka日志数据存储目录。注意这里不只是存放消息数据的目录在KRaft模式下它同时也会存放元数据日志。所以这个目录必须是本地的、独立的磁盘路径不要和系统盘混在一起否则IO竞争会很严重。三台机器上都需要先创建并授权这个目录sudo mkdir -p /data/kafka-logs sudo chown -R $(whoami):$(whoami) /data/kafka-logs另外一个重要参数是log.retention.hours默认是168小时7天日志保留时间可以根据业务需求调整。比如测试环境可以缩短log.retention.hours244.4 副本与ISR参数num.partitions3 default.replication.factor3 min.insync.replicas2num.partitions新建Topic时默认分区数。这里是3正好匹配三台broker每台broker承载一个分区副本。default.replication.factor新建Topic时默认副本数3表示每个分区在三个broker上各保留一份副本。min.insync.replicas生产端在配置了acksall的情况下写入请求至少要有几个副本处于同步状态才算成功。这里设置为2意味着至少两台broker都确认写入后才向生产者返回成功。这是保证数据不丢失的关键参数之一。这三个参数的共同作用决定了集群的容错能力。比如默认副本数为3当一个broker宕机后分区还剩两个副本其中至少一个需要保持ISR状态写入才能继续。如果min.insync.replicas设置成3那任意一个broker宕机都会导致生产写入失败这个要按业务可用性和数据可靠性做权衡。以下是我实验环境中的完整配置其它参数根据机器情况做了微调process.rolesbroker,controller node.id1 controller.quorum.voters1kafka1:9093,2kafka2:9093,3kafka3:9093 listenersPLAINTEXT://kafka1:9092,CONTROLLER://kafka1:9093 advertised.listenersPLAINTEXT://kafka1:9092 controller.listener.namesCONTROLLER listener.security.protocol.mapCONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT,SSL:SSL,SASL_PLAINTEXT:SASL_PLAINTEXT,SASL_SSL:SASL_SSL inter.broker.listener.namePLAINTEXT log.dirs/data/kafka-logs num.partitions3 default.replication.factor3 min.insync.replicas2 log.retention.hours24 offset.topic.replication.factor3 transaction.state.log.replication.factor3 transaction.state.log.min.isr2offset.topic.replication.factor和transaction.state.log.replication.factor这两个参数也挺重要。消费者组的offset是存在一个内部Topic里的事务状态日志也存在内部Topic里这两个内部Topic的副本因子默认是3。如果集群规模比较小只有一台或两台broker得调小一点否则内部Topic创建会失败。5. 第一次启动前如何正确生成集群ID并格式化存储目录这一步是KRaft模式与ZK模式区别最大的地方也是很多人最容易出错的地方。在ZK模式下你启动Kafka之前不需要做任何格式化操作ZK自己会管理好一切。但在KRaft模式下你必须先为集群生成一个唯一的集群ID然后用这个ID去格式化每个节点的存储目录之后才能启动。为什么需要这一步因为KRaft模式下元数据日志是Kafka自己维护的每个节点在启动之前必须知道自己属于哪个集群。如果集群ID不一致节点之间无法加入同一个元数据日志复制组整个集群就废了。5.1 用官方工具生成集群IDKafka 2.8的bin目录下自带了一个工具叫kafka-storage.sh。在任意一台机器上执行cd /opt/kafka/bin ./kafka-storage.sh random-uuid执行完会输出一串UUID类似n7B6L0YvT1yH0NkFp3jC2w这个UUID就是你的集群ID。把它保存下来后面每一步都会用到。注意这个命令只需要执行一次不管你有多少个节点共享同一个集群ID。5.2 格式化存储目录关键步骤不可跳过在每台机器上用刚才生成的集群ID格式化各自的日志目录cd /opt/kafka/bin ./kafka-storage.sh format -t n7B6L0YvT1yH0NkFp3jC2w -c /opt/kafka/config/server.properties这条命令的作用是读取server.properties里的log.dirs配置在对应的目录下初始化元数据日志结构并把集群ID写入其中。执行成功后你会看到类似这样的输出Formatting /data/kafka-logs with metadata.version 2.8-IV0.这里有个非常关键的点如果你之前用ZK模式跑过这套数据目录里面已经存在旧的日志文件那么格式化之前必须把目录清理干净否则格式化会报错。我的做法是直接把目录清空sudo rm -rf /data/kafka-logs/*再强调一次这一步必须三台机器都执行而且格式化用的server.properties必须跟你后续启动用的完全一致。尤其是node.id、controller.quorum.voters、log.dirs这三个参数如果格式化和启动时不一致节点会直接拒绝启动并报一些莫名其妙的数据目录错误。5.3 格式化的本质元数据日志的初始化从底层来看format命令做的事情就是在每个节点的日志目录下创建一个新的元数据日志分段然后将集群ID和初始元数据快照写入其中。之后节点启动时会读取这个目录恢复自身的状态。这也是为什么你不能用一个已经跑过数据的目录直接改成KRaft模式。因为旧目录里残留的ZK模式数据格式和新格式完全不同Kafka无法自动迁移。2.8版本本身也不提供从ZK模式自动迁移到KRaft模式的工具这个工具到3.x版本才逐渐成熟。所以如果想把现有ZK集群迁移到KRaft只能通过新建集群、拷贝数据的方式来做或者直接等迁移工具完善后再操作。6. 集群启动与验证让三个节点真正工作起来格式化完成之后就可以启动Kafka集群了。顺序上没有严格要求但从哪个节点开始会影响你观察日志的体验。我习惯从node1开始因为它是第一个会尝试竞选Active Controller的节点。6.1 启动节点三台机器上都执行同样的启动命令cd /opt/kafka bin/kafka-server-start.sh config/server.properties如果想后台运行用-daemon参数bin/kafka-server-start.sh -daemon config/server.properties启动过程中观察日志输出。node1上应该能看到类似这些关键信息加载了格式化好的元数据日志成功加入了Controller的投票集群成为Active Controller或者等待其他Controller发起投票broker身份成功注册监听在9092端口如果一切正常node1最终会输出类似[Controller id1] Registering broker 1 at path /brokers/1node2和node3启动后它们会通过controller.quorum.voters里配置的地址找到node1然后以Controller和Broker的身份加入集群。这时候你再看node1的日志应该能看到新的节点注册信息。6.2 用Broker状态命令验证集群Kafka提供了一个简单的工具来检查broker状态bin/kafka-broker-api-versions.sh --bootstrap-server kafka1:9092正常的话会列出每个broker支持的API版本同时也就验证了broker之间的网络连通性和注册状态。如果不方便执行命令还可以用JMX端口看节点状态但命令行方式是最直接的。6.3 验证Controller的选举与元数据同步要让集群真正可用还需要创建一个测试Topic。在KRaft模式下Topic的创建过程会触发一次元数据日志写入这能顺便验证Controller的工作是否正常bin/kafka-topics.sh --bootstrap-server kafka1:9092 --create --topic test-topic --partitions 3 --replication-factor 3返回Created topic test-topic.之后查看Topic详情bin/kafka-topics.sh --bootstrap-server kafka1:9092 --describe --topic test-topic正常输出应该显示3个分区每个分区有3个副本均匀分布在三个节点上。如果看到副本分布不均或某些分区Leader为空就要检查是否某个节点没正常启动。6.4 生产端和消费端全链路测试验证消息读写我用生产端脚本发几条消息bin/kafka-console-producer.sh --bootstrap-server kafka1:9092 --topic test-topic输入几条测试消息然后开一个新的终端用消费端脚本消费bin/kafka-console-consumer.sh --bootstrap-server kafka1:9092 --topic test-topic --from-beginning如果能正常看到刚才输入的消息说明这个KRaft集群已经能完整支撑Kafka的读写链路了。到这一步一个基本的集群部署就算成功了。7. 生产环境部署与2.8版本常见问题排查集群虽然跑起来了但只能说能用了。生产部署还需要考虑很多东西比如Controller和Broker要不要分离部署、安全协议要不要用TLS、JVM参数怎么调、日志持久化策略怎么定。同时2.8版本里还有几个老坑我把自己踩过的整理出来。7.1 Controller节点数怎么选奇数原则Controller节点数量必须保持奇数。这是因为Controller之间的元数据投票协议要求大多数节点在线才能选出Active Controller并对外提供服务。3个Controller允许挂1个5个Controller允许挂2个。偶数个Controller在理论上不会带来额外的容错能力反而可能在某些特殊故障场景下导致选票分裂。所以生产环境选3个或者5个就够了不要画蛇添足。Controller和Broker是否分离取决于你的业务规模。如果节点数量少、分区数少Combined模式完全够用。但如果你管理的是超大规模集群分区数几千甚至上万建议把Controller节点独立开避免元数据管理对数据读写造成资源竞争。Controller节点对磁盘IO、CPU的要求不高但对延迟很敏感所以给它独立的机器是更稳妥的选择。7.2 2.8版本已知限制和兼容性问题2.8的KRaft模式有不少限制需要提前知道第一不支持kafka-configs.sh的动态配置修改。在2.8的KRaft模式下有些动态配置项你改了不会实时生效甚至有些配置操作直接被拒绝。这个到3.x版本才逐步完善。所以2.8更适合学习和验证不适合大规模生产。第二不支持kafka-reassign-partitions.sh的分区副本迁移。这个工具在ZK模式下是日常运维法宝但KRaft模式的2.8版本里它还不能正常工作或者说不具备完整的操作能力。如果你需要迁移分区会比较麻烦。第三KRaft模式下的Controller节点目前不支持滚动升级到新版本。你在2.8上用KRaft后续想升级到2.9或者3.x官方给出的建议是先重建集群再迁移数据。这对生产来说是一个很大的迁移成本我当初评估完直接放弃了在线上用2.8的想法。第四sasl认证和ssl加密在2.8 KRaft模式下支持不完整。Controller之间的通信虽然可以走TLS但配置比较复杂而且官方文档在某些场景下还标注了已知问题。如果你的安全要求很高建议不要在生产环境使用2.8的KRaft。7.3 排查“节点无法启动”的几个高危错误我搭建过程中遇到最典型的问题是格式化之后的目录出现了残留信息。比如我第一次在node2上格式化后发现日志报错说metadata版本不对最后发现是我在node2上用了别的server.properties文件格式化导致元数据版本和集群ID都对不上。解决办法就是清空目录重新格式化。另一个高频问题是端口冲突。9092和9093两个端口都要确保没有被占用。用以下命令检查ss -lntp | grep -E 9092|9093如果端口被占用改server.properties里的监听端口同时记得更新advertised.listeners和controller.quorum.voters里的地址。还有一个隐蔽的问题如果你在配置里把advertised.listeners写成了localhost或者127.0.0.1客户端和broker之间无法正确建立连接。很多新手在这个地方卡住明明broker显示启动了但客户端连接就是超时。我建议只要涉及跨节点通信一律使用可解析的主机名或者内网IP。7.4 Controller组和Broker组全部分离的部署思路如果你的机器充足可以考虑将Controller和Broker分离部署这也是生产环境推荐的架构形态。假设用3台Controller节点和3台Broker节点Controller节点运行在独立机器上process.rolescontroller node.id1 controller.quorum.voters1ctrl1:9093,2ctrl2:9093,3ctrl3:9093 listenersCONTROLLER://ctrl1:9093 controller.listener.namesCONTROLLER listener.security.protocol.mapCONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT,SSL:SSL,SASL_PLAINTEXT:SASL_PLAINTEXT,SASL_SSL:SASL_SSL log.dirs/data/kafka-metadataBroker节点运行在另外的机器上process.rolesbroker node.id4 controller.quorum.voters1ctrl1:9093,2ctrl2:9093,3ctrl3:9093 listenersPLAINTEXT://broker1:9092 advertised.listenersPLAINTEXT://broker1:9092 controller.listener.namesCONTROLLER inter.broker.listener.namePLAINTEXT log.dirs/data/kafka-logs注意Broker节点上没有controller.listener.names对应的监听器但依然需要配置这个参数因为broker需要通过该监听器名称去理解Controller返回的元数据。同时broker上的controller.quorum.voters必须和Controller节点上的完全一致否则broker无法找到Controller。分离部署的核心思路是Controller节点之间通过9093端口互通Broker节点通过9092端口为客户端提供服务Broker与Controller之间的通信走9093端口。三个端口职责清晰互不干扰。8. 监控与运维层面2.8 KRaft模式下要怎么管部署完集群只是第一步日常运维才是重头戏。在这里分享一下监控和运维层面的体会。8.1 从ZooKeeper监控转型到Controller监控在ZK模式下你要监控ZooKeeper集群的/brokers/ids路径、ZK的延迟、会话数量等。在KRaft模式下这些都不需要了。你要转而关注Controller节点的元数据日志复制状态、Active Controller是否稳定、各broker节点的元数据版本是否滞后。在2.8中Controller的状态信息可以通过JMX指标获取。主要包括kafka.controller:typeKafkaController,nameActiveControllerCount当前节点是否为Active Controllerkafka.controller:typeKafkaController,nameOfflinePartitionsCount离线分区数kafka.server:typeBrokerTopicMetrics,nameBytesInPerSecbroker的入站流量这些都是原来就有的指标但监控对象从ZK换成了Controller节点本身。如果你的监控系统原来有一堆ZK相关告警要记得删除或调整规则。8.2 元数据日志目录的容量规划KRaft模式下元数据日志会随着集群变更不断增长。虽然单条元数据记录很小但在频繁创建Topic、修改配置、broker上下线的集群里日志增长还是可观的。建议为元数据日志目录配置足够的磁盘空间并设置监控告警。log.dirs目录下如果元数据日志占用空间过大一个是可以考虑定期清理旧的元数据日志段文件另一个是在确认集群稳定后通过调整元数据日志保留策略来控制增长速度。8.3 节点下线与上线操作在KRaft模式下下线一个broker节点前最好确认它的分区副本已经被迁移到其它节点。2.8版本中由于kafka-reassign-partitions.sh存在功能缺失你可能需要手动检查分区分布确保该节点上的所有分区都有足够的副本在其他节点上。上线新broker节点时在server.properties中对node.id分配一个从未使用过的新ID格式化数据目录后启动即可。新broker会自动从Controller拉取全量元数据快照然后开始接收分区副本的复制任务。9. 一次真实的排障记录advertised.listeners配错之后的诡异现象最后分享一个我自己在搭建过程中真实遇到的排障过程这个问题在2.8 KRaft模式下特别容易遇到而且它不报明显错误排查起来很费劲。当时我把三台节点的Kafka都启动成功了broker状态也都能看到。但是在用kafka-console-producer.sh往test-topic里写入消息时生产者一直显示超时。看日志报错信息是关于Connection to node -1 could not be established. Broker may not be available.。我本能地怀疑是防火墙问题。但检查了三台机器的防火墙、安全组都没有拦截9092端口。用telnet测试端口也能通。后来我仔细看了一遍每台机器的server.properties发现node2上我把advertised.listeners写成了PLAINTEXT://192.168.10.12:9092而listeners写的是PLAINTEXT://kafka2:9092。理论上这样配置也能工作但因为Kafka在解析主机名kafka2的时候解析到了127.0.0.1这个回环地址导致broker之间互相通信时node1尝试用kafka2去连接node2却连到了自己身上。整个集群的broker间通信就乱了。这给了我一个教训在生产环境里advertised.listeners必须填入客户端和broker都能稳定访问的地址最好是内网固定IP避免依赖DNS解析结果和主机名映射。如果你用主机名一定要确保/etc/hosts里配置正确并且在每个节点都保持一致的解析结果。修改完node2上的配置重启之后问题立刻消失。这种问题在ZK模式下同样存在但KRaft模式下因为节点角色变多、端口变多排查起来更容易混乱。所以我的建议是配置阶段就把所有监听地址固定成IP不要图省事用localhost也别依赖系统DNS的解析顺序。10. 我个人对2.8 KRaft模式的定位建议最后说一点我的个人判断。Kafka 2.8的KRaft模式是一个里程碑式的版本它第一次让用户能够在不部署ZooKeeper的情况下跑起一套Kafka集群。它对学习Kafka内部原理、验证KRaft架构设计有非常大的价值。但如果你要跑关键生产业务我劝你暂时不要上2.8。原因前面也提到了2.8的KRaft缺少一些运维工具支持迁移工具也不完善安全特性支持不到位。更适合的选择是等待3.3之后的成熟版本或者直接用3.4、3.5这些KRaft已经生产就绪的版本。如果确实必须在早期版本上跑KRaft建议先压测、做好故障演练至少不要在生产环境裸奔。搭完这套2.8集群之后我对Kafka架构演进的理解提升了一个档次。以前看Kafka源码总是要关心ZooKeeper怎么协调、Controller怎么选主、broker怎么注册现在再看KRaft感觉到Kafka真的在朝着自我管理、自我调度的方向走。省去的不仅是一个组件而是一整套运维心智负担。这篇文章把部署过程中的关键节点都梳理了一遍如果你也在折腾2.8的KRaft模式希望能帮你少踩几个坑。
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。