3. 元数据采集机制
元数据治理的第一步不是治理,而是"看见"。如果连集群里有哪些索引、每个索引的字段结构长什么样、分片分布在哪几个节点上、节点当前的负载如何都不清楚,后续的质量规则、血缘分析、生命周期管理都无从谈起。Elasticsearch 本身提供了大量自描述接口,元数据采集机制的核心思路就是:不依赖人工登记,而是通过一组稳定的 REST API 周期性拉取集群与索引的元数据,形成可对比、可追溯的元数据快照。
本节聚焦四类最常用的采集接口,它们分别覆盖了集群级、索引级、节点级和字段级四个不同的元数据层次。理解每个接口"返回什么、粒度多细、适合采集什么",是设计采集任务的前提。
四类接口的定位与采集内容
_cluster/state 返回的是集群的"权威状态",包括集群名称、UUID、版本、主节点信息、路由表(routing_table)、元数据(metadata)等。其中 metadata.indices 部分包含了每个索引的设置、映射和别名,routing_table.indices 则给出了每个索引的分片及其分配到的节点。它适合采集集群拓扑与索引归属关系,但返回体较大,通常通过 ?filter_path 裁剪,例如只取 metadata.indices.*.settings.index.creation_date 和 routing_table.indices.*.shards。
_cat 系列 API 是面向人的可读接口,加上 ?format=json&v 后也能被程序消费。_cat/indices 给出每个索引的健康状态、文档数、主分片与副本分片数、存储大小;_cat/shards 给出分片级别的位置与状态;_cat/aliases 给出别名到索引的映射。它适合采集索引清单与规模指标,字段扁平、解析成本低,是日常巡检最常用的入口。
_nodes/stats 返回节点级的运行统计,包括 JVM 堆使用、CPU、磁盘、线程池、段合并等。_nodes/stats/indices 还能下钻到节点上承载的索引级统计。它适合采集节点资源与承载压力,用于判断分片分布是否均衡、是否存在热点节点。
_mapping 返回索引的字段映射,是字段级元数据的唯一权威来源。它描述了每个字段的名称、类型(keyword、text、date、long、nested 等)、是否分词、是否有子字段(如 text 字段常带一个 keyword 子字段用于聚合)、是否被 index: false 排除索引。字段级元数据是数据质量规则(如"某字段不应为空""某字段值域应在枚举内")和血缘分析的直接依据。
采集任务的实际组织方式
把四个接口简单堆在一起调用并不等于采集机制。真正可用的采集需要解决三个问题:调用顺序、数据关联、增量识别。
调用顺序上,建议先取 _cluster/state 获得索引清单与路由信息,再以该清单为输入逐个索引调用 _mapping,避免对已删除索引做无效请求。节点级统计可以并行采集,因为它与索引清单无依赖关系。
数据关联的关键是统一主键。集群级用 cluster_uuid,索引级用 index_name(注意跨集群时需加集群前缀),节点级用 node_id,字段级用 index_name + field_name。只有主键统一,才能把"某索引在哪个节点上、该节点堆使用多少、该索引某字段是什么类型"串成一条可查询的元数据记录。
增量识别依赖两个字段:索引的 settings.index.creation_date 和 settings.index.uuid。前者用于判断索引是否为新建,后者用于判断索引是否被重建(同名索引重建后 UUID 会变化)。字段级变更则通过对比两次 _mapping 的哈希值来识别,只有哈希变化时才触发字段字典更新,避免全量重写。
一个可执行的采集脚本骨架
下面给出一个基于 curl 与 jq 的最小采集示例,用于演示如何把四类接口的返回裁剪成结构化记录。示例中的集群地址、索引名均为占位值,实际使用时替换为真实环境参数。
#!/bin/bash
ES="http://es-node1:9200"
AUTH="-u elastic:${ES_PWD}"
# 1. 集群级:取集群 UUID 与索引清单
curl -s $AUTH "$ES/_cluster/state/metadata?filter_path=cluster_uuid,metadata.indices.*.settings.index.uuid,metadata.indices.*.settings.index.creation_date" \
| jq '{cluster_uuid, indices: (.metadata.indices | to_entries | map({name: .key, uuid: .value.settings.index.uuid, created: .value.settings.index.creation_date}))}' \
> cluster_meta.json
# 2. 索引级:取索引规模与健康
curl -s $AUTH "$ES/_cat/indices?format=json&h=index,health,pri,rep,docs.count,store.size" \
| jq 'map({name: .index, health: .health, pri: .pri, rep: .rep, docs: .["docs.count"], size: .["store.size"]})' \
> index_meta.json
# 3. 节点级:取节点堆使用与分片承载
curl -s $AUTH "$ES/_nodes/stats/jvm,indices?filter_path=nodes.*.name,nodes.*.jvm.mem.heap_used_percent,nodes.*.indices.docs.count" \
| jq '.nodes | to_entries | map({node_id: .key, name: .value.name, heap_pct: .value.jvm.mem.heap_used_percent, docs: .value.indices.docs.count})' \
> node_meta.json
# 4. 字段级:对每个索引取 mapping 并计算哈希
for idx in $(jq -r '.[].name' index_meta.json); do
curl -s $AUTH "$ES/$idx/_mapping" | jq --arg i "$idx" '{index: $i, mapping: .}' >> mapping_raw.jsonl
done
执行后得到四份 JSON 文件,分别对应四个元数据层次。判断采集是否成功,可以检查三点:cluster_meta.json 中 cluster_uuid 非空且索引数量与 index_meta.json 一致;node_meta.json 中节点数量与集群实际数据节点数一致;mapping_raw.jsonl 行数等于索引数。任何一项不匹配,说明采集过程中存在权限不足、索引被删除或接口超时,需要重试或记录异常。
采集结果如何支撑后续治理
四层元数据采集完成后,它们并不是孤立的文件,而是后续治理动作的输入。索引资产清单用于识别长期无写入的"僵尸索引"和未按命名规范创建的索引;节点负载画像用于判断分片是否过度集中,为再平衡提供依据;字段字典用于生成数据质量规则,例如发现某字段类型为 text 且未定义 keyword 子字段时,提示该字段无法直接用于聚合,需要补充映射;集群拓扑快照则用于血缘分析中确定数据来源节点与副本分布。
需要强调的是,采集机制本身要具备幂等性和可追溯性。每次采集应记录采集时间、接口版本、返回状态码和记录条数,形成采集日志。当某次采集返回的索引数量骤降或字段数量异常减少时,能够快速区分是集群真的发生了变化,还是采集任务本身失败。这是元数据治理从"能采"走向"可信"的关键一步。