2163 字
约 7 分钟
12
S13-A29 · 索引模板:为什么"每天一个索引"半年后维护不动了

日志索引按天建:app-logs-2026.11.12、app-logs-2026.11.13……一开始很清爽——查哪天就查哪个索引,删旧数据就删整个索引。半年后集群开始报 too many shards,主节点 CPU 常年 80 %,而每天的日志量其实只有 2 GB。

问题不在日志变多,在索引数量变多:180 个索引 × 默认 1 主 1 副 = 360 个分片,每个分片都有自己的段文件、自己的元数据,全都要进集群状态。集群状态的维护成本随分片数线性上升,而它由主节点单线程处理——这才是主节点顶不住的原因。


1. "每天一个索引"的收益与代价

收益 代价
删旧数据 = 删索引(秒级) 分片数随时间线性增长
只查一天 = 只扫一个索引 跨天查询要 fan-out 到多个分片
单个索引小、恢复快 mapping 要每天"复制"一遍(否则漂移)

第五行是隐含成本:每个新索引都要重新应用一次映射。如果靠人复制,某个字段的类型在某天变了(status 从 keyword 变 text),那天之后的查询就开始出错——这类问题在"字段爆炸"之外,是另一条隐蔽的漂移路径。

// 180 天后的真实账单
索引数 180    分片数 360(1 主 1 副)
集群状态 ≈ 每分片几 KB → 总计数 MB,每次变更全量广播
主节点:单线程处理集群状态更新 → CPU 80%
// 而数据总量只有 360 GB,完全不需要 360 个分片

2. 模板解决的是"每天重复正确"

模板类型 解决什么 关键点
索引模板(旧) 映射 + 设置 已被 composable 取代
composable template 组件可复用(mappings / settings / aliases) 支持多模板叠加与优先级
组件模板(component template) 把"映射片段"抽出来复用 一处改、处处生效

第二种是当前的标准做法:把"日志的公共映射"和"分片设置"拆成组件,模板只负责组合 + 匹配 app-logs-*。这样新增索引自动继承,不需要人复制。

// 一个可用的组合:组件 + 索引模板
PUT _component_template/logs-mappings
{ "template": { "mappings": { "dynamic": "strict",
    "properties": { "@timestamp": {"type":"date"},
                    "level": {"type":"keyword"},
                    "msg": {"type":"text"} } } } }

PUT _index_template/app-logs
{ "index_patterns": ["app-logs-*"],
  "composed_of": ["logs-mappings"],
  "template": { "settings": { "number_of_shards": 1,
                              "number_of_replicas": 1 } },
  "priority": 200 }
// 关键:dynamic=strict 让"新字段"直接失败,而不是悄悄建字段

3. ILM 的四个阶段,真正要定的是三个数

阶段 动作 关键参数
hot 写入 + rollover max_primary_shard_size / max_age
warm 只读、合并段、降副本 forcemerge 到 1 段
cold 冻结、迁到廉价节点 查询变慢
delete 删除 min_age

第二行的三个数(分片大小、rollover 条件、保留时长)是联动的:

  • 分片目标 30–50 GB(太大恢复慢、太小浪费)
  • rollover 用 max_primary_shard_size: 50gb 比 max_age: 1d 更好——按大小切比按时间切更稳定,因为日流量会波动
  • 保留时长决定索引总数:保留天数 × 每天索引数
// 两种 rollover 策略在流量波动下的差异
按时间(1d): 大促日 20GB → 一个 20GB 分片;平日 2GB → 一堆 2GB 小分片
按大小(50gb): 大促日切 1 次,平日 25 天才切一次 → 分片数稳定
// 判据:分片数应随"数据量"变化,而不是随"天数"变化

4. 别名:写指向"唯一",读指向"全部"

别名 指向 谁用
app-logs-write 恰一个 write index 写入方
app-logs-read 所有活跃索引 查询方
app-logs-2026.11 单月索引 特定排查
// 一次 rollover 实际发生了什么(ILM 自动做,但你得知道顺序)
1 新建 app-logs-000002,自动应用模板
2 把 app-logs-write 别名移到新索引(唯一写入点)
3 把 app-logs-read 别名加上新索引,旧的保留
4 旧索引进入 warm 阶段
// 顺序错了:写别名同时指两个索引 → 写入分散 / 新索引没人写

第一行的"恰一个"是硬约束:写入别名若指向多个索引,写入会分散到多个分片,而 rollover 时又会出现"写到一半切新索引"的不一致。正确姿势是:写入永远通过 rollover 别名,ILM 自己维护它指向谁。


5. 半年后"维护不动"的三种形状

症状 根因 修法
too many shards 分片数随时间线性涨 改 rollover 按大小 + 合并旧索引
主节点 CPU 高 集群状态过大 减少分片(reindex 到更少分片)
某天开始查询报 mapping 错 模板未版本化,新索引映射漂移 建模板 + 版本化组件

第三种是全篇最值得记住的:它是一个"时间点"故障——某天之后的索引有问题,之前的都正常。排查时容易误判成"代码改动导致的",实际是那天的索引用了不同的映射。

// 三步体检(半年期索引都该跑一次)
$ curl -s 'localhost:9200/_cat/shards?v&h=index,shard,prirep,store' | awk 'NR>1{s[$1]++} END{for(i in s) print s[i], i}' | sort -rn | head
$ curl -s 'localhost:9200/_cluster/health?pretty' | grep -E 'number_of_(pending_tasks|in_flight)'
$ curl -s 'localhost:9200/app-logs-*/_mapping' | python3 -c 'import sys,json;d=json.load(sys.stdin);print(len(d),"indexes");[print(k, sorted(v["mappings"]["properties"])) for k,v in list(d.items())[:2]]'
// 判据:分片数 > 数据量(GB)/50 就该合并;mapping 各索引不一致就该建模板

6. 排错:五种"索引越建越多"

现象 八成原因 处理方向
每天 1 索引但流量很小 按时间 rollover 改按大小
旧索引没被删 ILM 没挂上或 min_age 写错 查 ilm explain
写入报 index_not_found 写别名指错/未创建 检查 rollover 别名
跨月查询很慢 分片太多、每片很小 合并旧索引
新索引 mapping 与旧的不同 没用模板 建 composable template

第二行要用 _ilm/explain 逐个确认:ILM 是"挂了但没匹配",还是"匹配了但条件没满足",两者修法完全不同。


7. 边界:什么情况就该用单一索引

场景 为什么 说明
数据量小(< 50 GB 总量) 一个索引足够 简单最好
需要全局排序/聚合 跨索引 fan-out 代价高 单索引
更新频繁(非追加) 按天分会把更新拆散 单索引 + 分区字段
保留期无限 没有"删旧"需求 不用按天

判断口径一句话:按天建索引的收益只有"删旧数据"一条,代价是"分片数随时间增长"——所以只有当数据确实需要"到期删除"、且总量会涨到分片该合并的规模时才这么做;否则单索引 + 定期清理更省。


8. 自测

  1. "每天一个索引"的唯一真实收益是什么?它带来的主要代价是哪一项指标的线性增长?
  2. 为什么主节点会成为瓶颈?集群状态的维护成本由什么决定?
  3. composable template 与组件模板分别解决什么问题?dynamic: strict 在这里起什么作用?
  4. 为什么 rollover 按"分片大小"比按"时间"更稳?分片目标大小该定多少?
  5. 写别名与读别名为什么必须分开?写别名指向多个索引会发生什么?
  6. "某天开始查询报 mapping 错"的根因是什么?为什么容易误判?

9. 一句话总结

按天建索引的收益只有"删旧数据",代价是分片数线性增长——而分片数直接决定集群状态大小,主节点单线程处理它,这才是半年后"维护不动"的机制。修法是三步:composable 模板(映射一处改、处处生效 + dynamic: strict)→ rollover 按分片大小而非时间 → 写/读别名分离。判据:分片数应随数据量变化,而不是随天数变化;数据总量 < 50 GB 时,单索引 + 定期清理更省。

S13-A29 · 索引模板:为什么"每天一个索引"半年后维护不动了
https://www.clxhxhhr.top/posts/6758/
作者
clxstart
发布于
2024-12-31
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。