首页
学习
活动
专区
圈层
工具
发布

Kafka 中 Zookeeper 的作用?

Broker 没挂,磁盘也没满,生产者却一直报NOT_LEADER_OR_FOLLOWER。 这种问题我一般不先看业务代码,先看 Kafka 控制面。老版本 Kafka 里,这个控制面背后站着的就是 ZooKeeper。

Kafka 里的 ZooKeeper,别把它想成“存消息的地方”。

消息不在 ZooKeeper。

消息在 Broker 的日志文件里,路径一般类似这样:

/data/kafka-logs/order_pay-3/00000000000000000000.log

/data/kafka-logs/order_pay-3/00000000000000000000.index

ZooKeeper 管的是另一摊事:谁还活着,谁是 Controller,Topic 有哪些分区,分区副本在哪些 Broker 上,哪个副本是 Leader。

老版本配置里一般能看到这一行:

broker.id=2

listeners=PLAINTEXT://10.10.8.22:9092

log.dirs=/data/kafka-logs

zookeeper.connect=zk-1:2181,zk-2:2181,zk-3:2181/kafka-prod

zookeeper.session.timeout.ms=18000

看到zookeeper.connect,基本就能判断这是 ZK 模式的 Kafka 集群。

Broker 启动后,会去 ZooKeeper 上注册一个临时节点。临时节点这东西挺关键,Broker 活着,节点就在;Broker 进程挂了,或者和 ZooKeeper 的 session 断了,节点就会消失。

线上看 Broker 是否还在,不能只看进程。

public class KafkaZkProbe {

  private final ZooKeeper zk;

  public KafkaZkProbe(String connect) throws Exception {

      this.zk = new ZooKeeper(connect, 8000, e -> {

          System.out.println("zk event: " + e.getState() + ", " + e.getType());

      });

  }

  public void printClusterView() throws Exception {

      System.out.println("brokers:");

      for (String id : zk.getChildren("/brokers/ids", false)) {

          byte[] raw = zk.getData("/brokers/ids/" + id, false, null);

          System.out.println("broker-" + id + " => " + new String(raw));

      }

      byte[] controller = zk.getData("/controller", false, null);

      System.out.println("controller => " + new String(controller));

  }

}

这段代码不是让你在线上服务里依赖 ZooKeeper。真要排障,临时跑一下可以。尤其是怀疑 Broker 假活、Controller 频繁切换的时候,比盯着业务日志靠谱。

ZooKeeper 在 Kafka 里最重要的一件事,是选 Controller。

Controller 不是业务意义上的 Controller,它是 Kafka 集群里的“调度员”。哪个分区的 Leader 挂了,哪个副本要升上来,Topic 创建后分区怎么分配,这些活都归它管。

比如一个 Topic:

topic: order_pay

partition: 0

replicas: [1, 2, 3]

leader: 1

isr: [1, 2, 3]

如果 Broker 1 掉了,Controller 要从 ISR 里挑一个新的 Leader,比如 Broker 2。这个动作不是生产者自己决定的,也不是消费者决定的,是 Controller 根据元数据和副本状态推进的。

所以 ZooKeeper 抖一下,最烦的不是“ZooKeeper 抖了”这句话本身,而是后面一串连锁反应:

[Controller id=2] Broker 1 was removed from live brokers

[Controller id=2] New leader and ISR for partition order_pay-0 is Leader:2, ISR:[2,3]

[Producer clientId=pay-producer] Received NOT_LEADER_OR_FOLLOWER

这时候业务侧看到的可能只是发送失败、消费延迟、偶发超时。你不顺着 Controller 日志看,很容易去改一堆没用的重试参数。

ZooKeeper 还保存 Kafka 的一些元数据。

比如 Topic、分区、副本分布、部分配置、ACL 等。注意这里也有版本差异,老 Consumer 的 offset 曾经放 ZooKeeper,后来新 Consumer 早就放到 Kafka 内部 Topic__consumer_offsets里了。这个点别背错,不然一问 offset 存哪儿就露馅。

我以前查过一次消费位点异常,有人上来就说“去 ZooKeeper 查 offset”。我第一眼就不太信。看客户端版本和 group 协议,发现是新 Consumer,那就应该去查 Kafka:

bin/kafka-consumer-groups.sh \

--bootstrap-server 10.10.8.21:9092 \

--group pay-sync-group \

--describe

不要什么都往 ZooKeeper 上扣。

ZooKeeper 对 Kafka 的价值,核心就四个字:集群协调。

Broker 注册,靠它。 Controller 选举,靠它。 元数据存储,靠它。 Broker 上下线感知,也靠它。

但它也带来了麻烦。

Kafka 本身要部署一套,ZooKeeper 又要部署一套。Kafka 没问题,ZooKeeper 磁盘慢、网络抖、GC 卡一下,Kafka 控制面照样跟着晃。生产环境里最怕这种:数据面还在跑,控制面开始抽风,报错一会儿一个样。

现在新集群已经不建议再上 ZooKeeper 模式。Kafka 3.5 开始 ZooKeeper 被标记为 deprecated;Kafka 官方文档里也写了,ZooKeeper 在 3.x 还支持元数据管理,但不推荐新部署继续用,Kafka 4.0 之后走 KRaft 模式,控制面由 Kafka 自己的 controller quorum 承担。

所以回答“Kafka 中 ZooKeeper 的作用”,别只背一句“保存元数据”。

更准一点是:

ZooKeeper 是老版本 Kafka 的控制面底座。它不存业务消息,但它决定 Broker 怎么组成集群,谁来当 Controller,Topic 和分区元数据怎么维护,Broker 掉线后 Leader 怎么重新选。

消息丢不丢,主要看 Broker 副本、ISR、acks、刷盘这些配置。 集群乱不乱,老版本里 ZooKeeper 很关键。

现在要新搭 Kafka,我一般直接看 KRaft。 还在跑 ZooKeeper 模式的老集群,就别只监控 Kafka Broker。ZooKeeper 的延迟、连接数、磁盘、GC、session 过期日志,都得一起盯。控制面一抖,业务侧看到的往往已经是第二现场了。

  • 发表于:
  • 原文链接https://page.om.qq.com/page/OVjFRiY8izPYdCDjblcbzYVA0
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。
领券