3. Kafka 元数据全景分析

说实话,很多做 Kafka 的同学,天天跟生产消费打交道,但真要问一句「Kafka 到底有哪些元数据」,能说全的还真不多。我刚开始带团队那会儿,有一次集群出了故障,排查了半天才发现是 Broker 配置不一致导致的。从那以后,我就养成了一个习惯——先把元数据地图画清楚。

这一章,我们就来把这幅地图画出来。我会从四个维度展开:集群元数据、Topic 元数据、消费元数据、配置元数据。你想想看,搞清楚了这些,后面做实时采集才有方向。

核心观点:Kafka 元数据不是孤立的,它们之间互相引用、互相依赖。Broker 挂了会影响 Topic 的副本分配,Topic 分区变化会影响 Consumer 的 Offset 提交。理解这些关联,才是元数据管理的精髓。

Kafka 元数据全景结构图 Kafka 元数据 集群元数据 Topic 元数据 消费元数据 配置元数据 Broker 列表 Controller 信息 分区数 副本分配 ISR 列表 Consumer Group Offset Topic 配置 Broker 配置 💡 元数据关联关系 • Broker 列表 + Controller 信息 → 决定 Topic 副本分配策略 • Topic 分区数 + 副本分配 → 影响 Consumer Group 的 Offset 提交行为 • 配置元数据(Topic/Broker)→ 控制整个集群的行为边界

3.1 集群元数据:Broker 列表与 Controller 信息

集群元数据,说白了就是「这个集群里有哪些机器,谁在管事」。我见过不少运维同学,集群出问题了第一反应是看日志,其实先看一眼集群元数据,很多问题就一目了然了。

3.1.1 Broker 列表

Broker 列表记录了集群中所有存活的 Broker 节点。每个 Broker 有一个唯一的 ID,以及对应的主机名、端口、Rack 信息等。Kafka 通过 ZooKeeper 或 KRaft 来维护这份列表。

获取 Broker 列表的方式很简单:

# 通过命令行
./kafka-brokers.sh --bootstrap-server localhost:9092 --describe

# 通过 AdminClient API
Properties props = new Properties();
props.put(AdminClientConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
try (AdminClient admin = AdminClient.create(props)) {
    DescribeClusterResult result = admin.describeCluster();
    Collection<Node> nodes = result.nodes().get();
    for (Node node : nodes) {
        System.out.println("Broker ID: " + node.id() + 
                           ", Host: " + node.host() + 
                           ", Port: " + node.port());
    }
}

我的经验:我曾经遇到过一个诡异的问题——某个 Broker 明明进程还在,但集群里就是看不到它。后来发现是 ZooKeeper 会话超时了,但进程没退出。所以采集 Broker 列表时,别只看进程,要看它是否真的在集群注册表中。

3.1.2 Controller 信息

Controller 是 Kafka 集群的「大脑」。它负责管理分区 leader 的选举、副本分配等核心操作。集群中只有一个 Controller,如果它挂了,其他 Broker 会重新选举。

Controller 的信息包括:

  • Controller ID:当前担任 Controller 的 Broker ID
  • Controller 版本:Kafka 版本信息
  • Controller 任期:从第几次选举开始
  • 最近一次选举时间:方便排查故障

我个人习惯在元数据采集时,把 Controller 信息单独拎出来监控。为什么呢?因为 Controller 的频繁变更往往预示着集群不稳定。

注意:Controller 的选举不是瞬间完成的。在选举期间,集群的元数据操作会阻塞。如果你的采集任务恰好在此时发起,可能会拿到不一致的数据。建议加一个重试机制。

3.2 Topic 元数据:分区数、副本分配与 ISR 列表

Topic 元数据是元数据采集中最核心的部分。你想想看,生产者和消费者都是围绕 Topic 工作的,Topic 的元数据一旦出错,整个数据流就乱了。

3.2.1 分区数

每个 Topic 可以分成多个分区。分区数是 Topic 创建时指定的,但也可以后期调整。不过要注意,分区数只能增加,不能减少。

属性 说明 采集建议
分区总数 Topic 当前的分区数量 与预期值对比,发现异常
分区 ID 列表 0, 1, 2, ... 检查是否有缺失
Leader 分布 每个分区的 leader 在哪个 Broker 看是否均匀分布

3.2.2 副本分配

副本分配决定了每个分区的数据冗余在哪些 Broker 上。Kafka 默认会尽量把副本分散到不同的 Broker 上,以提高容错性。

获取副本分配的代码示例:

// 获取 Topic 的副本分配
DescribeTopicsResult result = admin.describeTopics(Arrays.asList("my-topic"));
TopicDescription topicDesc = result.values().get("my-topic").get();
for (TopicPartitionInfo partition : topicDesc.partitions()) {
    System.out.println("Partition: " + partition.partition());
    System.out.println("  Leader: " + partition.leader().id());
    System.out.println("  Replicas: " + 
        partition.replicas().stream().map(Node::id).collect(Collectors.toList()));
    System.out.println("  ISR: " + 
        partition.isr().stream().map(Node::id).collect(Collectors.toList()));
}

关键点:副本分配不是一成不变的。当 Broker 宕机或新增时,Kafka 会自动触发副本重分配。采集时要注意时间戳,避免拿到过时的分配信息。

3.2.3 ISR 列表

ISR(In-Sync Replicas)是「与 leader 保持同步的副本列表」。说白了,就是那些数据跟 leader 基本一致的副本。如果某个副本落后太多,就会被踢出 ISR。

ISR 列表的变化非常频繁,尤其是在高负载场景下。我建议采集 ISR 时,同时记录一下时间点和对应的 leader epoch,这样后续分析才有依据。

3.3 消费元数据:Consumer Group 与 Offset

消费元数据是排查数据丢失或重复消费的关键。我记得有一次,业务方反馈说数据丢了,我第一反应就是查 Consumer Group 的 Offset。

3.3.1 Consumer Group

每个 Consumer Group 有一个唯一的名称,以及一组消费者实例。Kafka 会记录每个 Group 的成员信息、分区分配策略、状态等。

常见的 Consumer Group 状态:

  • Stable:正常运行
  • Rebalancing:正在重新分配分区
  • Empty:没有活跃消费者
  • Dead:已超时未心跳

3.3.2 Offset

Offset 是消费者在每个分区上的消费位置。Kafka 把 Offset 保存在内部 Topic __consumer_offsets 中。

采集 Offset 时,我通常会关注三个值:

  1. 当前 Offset:消费者已经提交的位置
  2. Log End Offset (LEO):分区的最新消息位置
  3. Lag:LEO - 当前 Offset,表示消费延迟

避坑指南:我曾经遇到过 Offset 提交失败导致重复消费的问题。原因是消费者在处理消息时抛了异常,但 Offset 却提前提交了。所以采集 Offset 时,最好也采集一下消费者的状态和异常信息。

3.4 配置元数据:Topic 配置与 Broker 配置

配置元数据决定了 Kafka 的行为。很多性能问题,归根结底是配置不合理。

3.4.1 Topic 配置

每个 Topic 可以单独设置一些参数,比如:

配置项 默认值 说明
retention.ms 604800000 (7天) 消息保留时间
max.message.bytes 1000012 单条消息最大大小
cleanup.policy delete 日志清理策略
compression.type producer 压缩类型

3.4.2 Broker 配置

Broker 配置是全局性的,影响整个集群。常见的包括:

  • num.partitions:新建 Topic 的默认分区数
  • default.replication.factor:默认副本因子
  • log.retention.hours:日志保留时间
  • zookeeper.connect:ZooKeeper 连接地址

注意:Broker 配置的变更需要重启才能生效。采集时如果发现配置与预期不符,要确认是临时修改还是持久化修改。我曾经踩过坑——改了配置忘了重启,结果采集到的还是旧值。