副本只能防节点故障,防不了误删、误改与逻辑损坏。真正能兜底的是快照:把索引的段文件与集群元数据写进外部仓库,在需要时按索引粒度还原。Elasticsearch 的快照是增量的、可并发的,配合快照生命周期管理(SLM)可以做到无人值守的定期备份与自动过期。本文从仓库类型讲起,覆盖增量快照原理、恢复与部分恢复、SLM 策略编排,最后落到跨集群恢复与日常运维。
1. 快照机制与仓库类型
一句话总结: 快照把索引段与集群状态写入外部仓库,仓库必须支持并发写与原子移动,否则快照会失败。
1.1 快照包含什么
一句话总结: 快照按索引粒度记录段文件,同时保存全局元数据与每个索引的 settings、mappings、aliases。
一次快照的内容分三层:
- 全局元数据:集群级设置、索引模板、ILM 策略、ingest pipeline 等。
- 索引元数据:每个索引的 settings、mappings、aliases。
- 索引数据:实际的分片段文件。
恢复时可以只还原某几个索引的数据,但全局元数据只影响新建索引,不会覆盖集群现有设置。
1.2 仓库类型与选择
一句话总结: 生产推荐 S3、GCS、Azure Blob 等对象存储,共享文件系统只适合小规模或本地验证。
# 注册 S3 仓库
curl -X PUT "localhost:9200/_snapshot/s3_backup" -H 'Content-Type: application/json' -d '
{
"type": "s3",
"settings": {
"bucket": "es-backup-prod",
"base_path": "snapshots",
"region": "cn-north-1",
"max_restore_bytes_per_sec": "200mb",
"max_snapshot_bytes_per_sec": "100mb",
"chunk_size": "1gb",
"compress": true
}
}'
# 注册共享文件系统仓库(需在每个节点挂载同一路径)
curl -X PUT "localhost:9200/_snapshot/fs_backup" -H 'Content-Type: application/json' -d '
{
"type": "fs",
"settings": {
"location": "/mnt/es-backup",
"compress": true,
"max_snapshot_bytes_per_sec": "80mb"
}
}'
chunk_size 决定单个大文件切分粒度,调大可以减少请求数但增加单次重试成本。compress 对文本类数据收益明显,对已压缩的二进制收益有限。仓库注册后必须做一次连通性验证:
curl -X POST "localhost:9200/_snapshot/s3_backup/_verify?pretty"
1.3 仓库的并发约束
一句话总结: 同一仓库同一时间只允许一个快照在跑,多个仓库可以并行。
这是为了元数据一致性。若需要并行备份,就注册多个仓库、把索引分组,让不同仓库同时工作。
2. 增量快照原理
一句话总结: 快照以段为最小单位做复用,只有新增段需要上传,因此第二次之后的快照又快又小。
2.1 段级复用
一句话总结: 段一旦写入就不再修改,所以已存在于仓库的段可以直接引用,不必重复上传。
Elasticsearch 的段是不可变的:新增文档进新段,删除只是标记,段合并会生成新段并淘汰旧段。快照记录的是「这次快照包含哪些段」,与仓库已有段做差集,只上传差集部分。
这带来两个推论:
- 快照之间共享段文件,仓库里的总占用远小于「每次全量」之和。
- 段合并后旧段被删除,快照会重新引用合并后的新段,因此频繁强制合并会让增量快照退化成近似全量。
2.2 快照粒度与并发
一句话总结: 快照是索引粒度的,单个索引内的分片并行上传,整体速度受仓库带宽限制。
curl -X PUT "localhost:9200/_snapshot/s3_backup/snap-2026-10-01?wait_for_completion=false" -H 'Content-Type: application/json' -d '
{
"indices": "logs-2026.09.*,orders",
"ignore_unavailable": true,
"include_global_state": true,
"metadata": {
"taken_by": "ops-batch",
"reason": "monthly-full"
}
}'
wait_for_completion=false 让请求立即返回,之后用任务接口查进度:
curl -s "localhost:9200/_snapshot/s3_backup/snap-2026-10-01/_status?pretty" | head -30
2.3 快照的原子性与失败处理
一句话总结: 快照只有在所有分片成功后才是 SUCCESS,中途失败的分片可以重跑,仓库里会保留部分段。
快照状态有 IN_PROGRESS、SUCCESS、FAILED、PARTIAL 四种。PARTIAL 表示部分分片失败,可以再次执行同名快照,Elasticsearch 会只补齐失败的分片,这是增量机制带来的容错便利。
3. 恢复流程
一句话总结: 恢复把仓库里的段文件拉回本地并重建分片,恢复期间索引不可写,完成后需显式打开。
3.1 恢复整个快照
一句话总结: 恢复默认会还原快照里的全部索引,可用
indices精确控制范围。
curl -X POST "localhost:9200/_snapshot/s3_backup/snap-2026-10-01/_restore?wait_for_completion=false" -H 'Content-Type: application/json' -d '
{
"indices": "orders",
"ignore_unavailable": true,
"include_global_state": false,
"include_aliases": true,
"partial": false
}'
include_global_state 设为 false 时不会还原集群级设置与模板,这在把快照恢复到另一个集群时非常关键,避免把源集群的模板与设置覆盖过来。
3.2 恢复到新索引
一句话总结: 用
rename_pattern与rename_replacement把快照里的索引改名,避免与线上索引冲突。
curl -X POST "localhost:9200/_snapshot/s3_backup/snap-2026-10-01/_restore?wait_for_completion=false" -H 'Content-Type: application/json' -d '
{
"indices": "orders",
"rename_pattern": "(.+)",
"rename_replacement": "restored_$1",
"index_settings": {
"index.number_of_replicas": 0
},
"ignore_index_settings": [
"index.refresh_interval"
]
}'
恢复时把副本数临时设为 0 可以显著加速,完成后再用 _settings 调回。ignore_index_settings 用来丢弃快照里的某些设置,避免与目标集群的运维策略冲突。
3.3 恢复的状态与阻塞
一句话总结: 恢复期间索引处于 red 或只读状态,未恢复完的分片不可查。
curl -s "localhost:9200/_cat/recovery/orders?v&h=index,shard,time,stage,bytes_percent,files_percent"
stage 依次是 init、index、translog、finalize、done。index 阶段是拉取段文件的主要耗时,translog 阶段回放增量写入。恢复完成前不要急着改副本数或强制合并。
4. 部分恢复与细粒度控制
一句话总结: 恢复支持按索引、按分片、按设置做细粒度控制,是「从备份里捞回一条数据」的关键能力。
4.1 只恢复部分索引
一句话总结: 把
indices写成通配或列表,可以只恢复受灾的索引。
curl -X POST "localhost:9200/_snapshot/s3_backup/snap-2026-10-01/_restore?wait_for_completion=false" -H 'Content-Type: application/json' -d '
{
"indices": "logs-2026.09.28,logs-2026.09.29",
"ignore_unavailable": true,
"include_global_state": false
}'
4.2 检查快照内容
一句话总结: 恢复前先用
_snapshot/.../_get或_cat/snapshots确认快照里到底有什么。
# 列出仓库中所有快照
curl -s "localhost:9200/_cat/snapshots/s3_backup?v&h=id,status,start_epoch,end_epoch,duration,indices"
# 查看某个快照包含的索引与分片
curl -s "localhost:9200/_snapshot/s3_backup/snap-2026-10-01/_get?pretty" | head -50
养成「恢复前先看内容」的习惯,可以避免恢复错快照导致数据回退。
4.3 恢复中的只读保护
一句话总结: 恢复完成后索引会自动打开,但若
partial恢复导致分片缺失,需要手工处理。
若快照本身是 PARTIAL 状态,恢复时可用 partial: true 允许缺失分片的索引也能恢复出来,代价是索引处于 red 且部分数据不可查。这适合「先恢复能恢复的部分、再想办法补数据」的应急场景。
5. SLM 策略编排
一句话总结: SLM 按 cron 周期自动创建快照并按保留策略删除旧快照,是无人值守备份的标准做法。
5.1 定义策略
一句话总结: 策略包含 schedule、name、repository、config 与 retention 五部分。
curl -X PUT "localhost:9200/_slm/policy/nightly-snapshots?pretty" -H 'Content-Type: application/json' -d '
{
"schedule": "0 30 2 * * ?",
"name": "<nightly-{now/d}>",
"repository": "s3_backup",
"config": {
"indices": ["logs-*", "orders", "users"],
"ignore_unavailable": false,
"include_global_state": true
},
"retention": {
"expire_after": "30d",
"min_count": 7,
"max_count": 60
}
}'
schedule 是 7 位 cron(秒 分 时 日 月 周 年),name 里的 {now/d} 会渲染成日期,保证快照名唯一。retention 里 min_count 优先级最高:即使超过 expire_after,也要保留至少这么多份。
5.2 执行与观察
一句话总结: 策略注册后立即生效,可用
_execute手动触发一次验证配置。
# 手动触发一次,验证策略正确
curl -X POST "localhost:9200/_slm/policy/nightly-snapshots/_execute?pretty"
# 查看策略运行状态与下次执行时间
curl -s "localhost:9200/_slm/policy/nightly-snapshots?pretty"
# 查看 SLM 自身的运行历史
curl -s "localhost:9200/_slm/stats?pretty"
5.3 常见坑
一句话总结: 快照名重复、仓库未验证、保留策略配错是最常见的三类 SLM 故障。
- 快照名重复:
name里不带日期变量,第二次执行会因重名失败。 - 仓库未验证:注册仓库后没跑
_verify,SLM 首次执行才发现权限或路径问题。 - retention 配错:只写
expire_after不写min_count,极端情况下可能把最近快照也删掉。
5.4 监控 SLM
一句话总结: 把「最近一次快照是否成功」纳入监控,比监控 SLM 进程本身更有意义。
curl -s "localhost:9200/_slm/stats?pretty" | grep -E "policy|snapshots_taken|snapshots_failed"
建议对 snapshots_failed 增长与「最近成功快照时间超过预期周期」两条规则告警。
6. 跨集群恢复
一句话总结: 跨集群恢复是把一个集群的快照恢复到另一个集群,常用于迁移、灾备演练与数据回流。
6.1 直接读取远端仓库
一句话总结: 目标集群注册同一个对象存储仓库,即可直接恢复源集群的快照。
只要两个集群都能访问同一个 bucket,在目标集群注册同名仓库后就能看到源集群的快照:
curl -X PUT "localhost:9201/_snapshot/s3_backup" -H 'Content-Type: application/json' -d '
{
"type": "s3",
"settings": {
"bucket": "es-backup-prod",
"base_path": "snapshots",
"region": "cn-north-1",
"readonly": true
}
}'
设 readonly: true 可以防止误在目标集群写快照、破坏源集群的仓库结构。
6.2 版本兼容规则
一句话总结: 快照只能恢复到同版本或更高版本,且不能跨大版本跳跃。
规则是:可以恢复到相同版本,或从 7.x 恢复到 7.x 及更高。绝不能从高版本恢复到低版本。跨大版本迁移时,官方推荐路径是「旧集群快照 → 新版本集群恢复」,且需先做一次 _migration/deprecations 检查。
6.3 恢复后的验证
一句话总结: 跨集群恢复后必须核对文档数、映射与别名,确认数据完整。
curl -s "localhost:9201/_cat/indices/orders?v&h=index,health,pri,rep,docs.count,store.size"
curl -s "localhost:9201/orders/_mapping?pretty" | head -40
7. 快照运维与容量规划
一句话总结: 快照运维的核心是仓库容量、带宽占用与恢复演练三件事。
7.1 仓库容量估算
一句话总结: 由于段复用,仓库容量通常远小于「索引大小 × 快照数」,但仍需按最坏情况预留。
粗略估算:仓库容量 ≈ 索引总大小 × (1 + 变化率 × 快照数)。变化率高的写入型索引要留足空间。开启 compress 后文本类数据通常能再省 30% 以上。
7.2 限流保护业务
一句话总结:
max_snapshot_bytes_per_sec与max_restore_bytes_per_sec防止备份把业务带宽吃光。
curl -X PUT "localhost:9200/_snapshot/s3_backup/_settings" -H 'Content-Type: application/json' -d '
{
"max_snapshot_bytes_per_sec": "50mb",
"max_restore_bytes_per_sec": "100mb"
}'
7.3 定期恢复演练
一句话总结: 没演练过的备份等于没有备份,建议每季度至少做一次真实恢复。
演练流程:在隔离集群注册只读仓库,恢复最近一次快照到改名索引,核对文档数与抽样数据,最后删除演练索引。演练同时验证了仓库权限、版本兼容与恢复耗时,为真实故障时的决策提供数据。
8. 总结
| 环节 | 要点 |
|---|---|
| 仓库类型 | 生产用对象存储,共享文件系统仅适合验证,注册后必须 verify |
| 增量原理 | 段级复用,只上传新增段,频繁强制合并会让增量退化为全量 |
| 快照创建 | 索引粒度、分片并行,PARTIAL 状态可重跑补齐失败分片 |
| 恢复流程 | 默认全量,用 indices 与 rename 控制范围与命名,恢复期索引不可写 |
| 部分恢复 | partial 允许缺失分片恢复,用于应急先救回可用部分 |
| SLM 策略 | schedule 加日期变量命名,retention 里 min_count 优先级最高 |
| 跨集群恢复 | 目标集群注册只读同仓库,只能平级或向高版本恢复 |
| 运维演练 | 限流保护业务带宽,每季度做一次真实恢复演练 |
快照是集群的最后一道防线,而 SLM 让这道防线可以自动运转、自动过期、自动验证。把仓库选对、把策略配对、把演练做实,灾难来临时才有从容回滚的底气。下一篇我们回到写入与查询的源头,讲分析器与分词如何决定文本检索的质量。
延伸阅读
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。