跳转到主内容
新派编程网 - 新潮编程理念,全新技术课堂!

如何在Elasticsearch中利用Shrink动态减少分片的数量

Elasticsearch shrink操作需满足四条件:索引设为read-only、所有主分片active、新分片数为原数约数、原索引不可含routing_partition_size;执行时须用POST指定新索引名及shards数,且shrink后需验证数据一致性与分片状态。 Shrink前必须满足的硬性条件 Elasticsearch 的
shrink
操作不是“随时点一下就能缩”的通用功能,它对索引状态有强制约束。最常踩的坑是直接对活跃写入的索引执行 shrink,结果卡在
blocked by: [FORBIDDEN/12/index read-only / allow delete (api)];
或更隐蔽的
all primary shards must be active and relocating
错误。 目标索引必须处于
read-only
状态(通过
index.blocks.write=true
设置) 所有主分片(primary shards)必须是
active
,不能有正在恢复、relocating 或 unassigned 的分片 新索引的分片数必须是原索引分片数的 约数 (例如 12 → 6、12 → 4、12 → 3 都合法;12 → 5 不合法) 原索引不能使用
routing_partition_size
(即不能是 routing partitioned index) 实际操作中,建议先用
GET /my-index/_stats?level=shards
确认分片状态,再用
PUT /my-index/_settings
写入
{"index.blocks.write": true}
—— 注意:这步不会阻断查询,只停写入。 执行 shrink 的标准请求结构与参数含义
shrink
是一个同步 API,但底层会触发分片合并和数据重分配,耗时取决于数据量。它的核心不是“复制”,而是把多个分片的数据重新组织进更少的分片里,所以新索引的每个分片实际承载更多数据。
POST /my-index/_shrink/my-index-shrunken { "settings": { "number_of_shards": 3, "number_of_replicas": 1 } }
请求路径中的
my-index-shrunken
是新索引名,必须不存在,且符合 Elasticsearch 索引命名规则(小写、不能以
_
开头等)
number_of_shards
必须在请求体
settings
中显式指定,不能省略或从原索引继承
number_of_replicas
可以设为 0 临时加速(后续再用
PUT /my-index-shrunken/_settings
调整),但要注意:shrink 过程中 replica 分片也会被重建,设太高会延长完成时间 不支持在 shrink 请求里改
mappings
或
aliases
,这些得在 shrink 完成后再单独操作 shrink 后常见数据异常与验证方式 shrink 成功返回
"acknowledged": true
并不等于数据完整无误。最容易被忽略的是 routing 行为变化导致的查询结果偏差。 原索引若用了自定义
_routing
字段,shrink 后该字段仍生效,但分片数变少,相同 routing value 可能落到不同物理分片, 不影响正确性,但影响局部性 (比如原来某 user_id 总落在 shard 2,现在可能落在 shard 0) 使用
GET /my-index-shrunken/_search?q=*
查不到数据?先检查是否忘了删掉原索引的
write
block:
PUT /my-index/_settings {"index.blocks.write": null}
数据量明显变少?大概率是原索引存在大量已删除文档(
deleted
doc),shrink 会跳过它们——这是正常行为,不是丢数据 验证是否真正收缩成功:对比
GET /my-index/_cat/shards
和
GET /my-index-shrunken/_cat/shards
的行数,同时检查
GET /my-index-shrunken/_stats/docs
的
count
是否与原索引一致 为什么不能 shrink 正在 rollover 的索引 滚动索引(rollover)本质是创建新索引并切换别名指向,而 shrink 要求源索引完全静止。如果在
logs-000001
还没关写就去 shrink 它,即使设置了
write
block,rollover 触发后别名可能已指向
logs-000002
,而你 shrink 的还是旧索引 —— 这会导致后续写入继续打到新索引,旧索引变成“僵尸”,没人管又没法删。 正确做法:确保 rollover 已完成、且旧索引明确进入只读归档阶段(比如按天 rollover 后,昨天的索引才允许 shrink) 如果用 ILM(Index Lifecycle Management),shrink 是一个独立 phase,必须放在
freeze
或
delete
之前,且 ILM 会自动处理
write
block 和分片检查 —— 但前提是策略里
min_age
设置合理,别让 shrink 在 rollover 刚完成时就触发 shrink 看似简单,但依赖索引生命周期的精确控制。一旦在分片未完全稳定、或别名关系混乱时强行操作,轻则任务卡住,重则需要手动清理残留分片或重建索引。

相关文章