2.6 Elasticsearch-快照与恢复:SLM 策略 + HDFS/S3仓库

在这里插入图片描述
2.6 Elasticsearch-快照与恢复:SLM 策略 + HDFS/S3 仓库

0. 引言

生产集群里,索引从 GB 级膨胀到 TB 级往往只需要一个促销季。一次误删 mapping、一次脚本字段爆炸,就可能让业务“归零”。快照(Snapshot)是 ES 最后的“后悔药”,而 SLM(Snapshot Lifecycle Management)把“吃药”变成了定时定量、免运维的自动化流程。本节把 SLM 与两种最主流的分布式仓库——HDFS 与 S3——串成一条完整链路:从仓库注册、SLM 策略编写、索引模板隔离、到跨集群恢复与演练,全部给出可直接落地的配置与脚本。


1. 仓库选型:HDFS vs. S3

维度HDFS 仓库(repository-hdfs)S3 仓库(repository-s3)
最终一致性强一致最终一致(需 s3.client.path_style_access=false+版本桶)
吞吐机架本地磁盘,千兆网卡 110 MB/s×节点数万兆 VPC 到 S3 1 GB/s/节点,可打满 100 GbE
成本自建机房折旧,3 副本膨胀 3×按量+低频/归档,可降 70 %
权限模型Kerberos + 文件 ACLIAM + Bucket Policy + KMS
网络隔离同一 YARN 集群VPC Endpoint / 专线 / 公网 HTTPS

结论:

  • 离线数仓、YARN 共池、数据不出机房——选 HDFS。
  • 云原生、跨 Region 容灾、希望“按量付费”——选 S3;最终一致问题用“分片并发+重试”解决。

2. 注册仓库

2.1 HDFS
# 所有数据节点安装 hadoop-hdfs-client,并放置 core-site.xml / hdfs-site.xml 到 /etc/elasticsearch/
# keystore 里放 Kerberos principal 与 keytab
bin/elasticsearch-keystore add hdfs.client.impersonation.user
bin/elasticsearch-keystore add hdfs.security.principal
bin/elasticsearch-keystore add hdfs.security.keytab

PUT _snapshot/hdfs_prod
{
  "type": "hdfs",
  "settings": {
    "uri": "hdfs://nameservice1",
    "path": "/user/elasticsearch/snapshot",
    "chunk_size": "500mb",
    "compress": true,
    "max_restore_bytes_per_sec": "1g",
    "max_snapshot_bytes_per_sec": "1g",
    "security.principal": "elasticsearch@EXAMPLE.COM"
  }
}
2.2 S3(以 MinIO 为例,兼容 AWS)
# 在 keystore 中写入统一的客户端名“backup”
bin/elasticsearch-keystore add s3.client.backup.access_key
bin/elasticsearch-keystore add s3.client.backup.secret_key
bin/elasticsearch-keystore add s3.client.backup.endpoint  # http://minio.example.com:9000
PUT _snapshot/s3_prod
{
  "type": "s3",
  "settings": {
    "client": "backup",
    "bucket": "es-snapshot-prod",
    "base_path": "slm",
    "chunk_size": "1gb",
    "compress": true,
    "server_side_encryption": true,
    "storage_class": "INTELLIGENT_TIERING",
    "max_restore_bytes_per_sec": "2g",
    "max_snapshot_bytes_per_sec": "2g"
  }
}

3. SLM 策略:一条 DSL 管五年

SLM 把“什么时候备、保留多久、备哪些索引”三句话固化成 JSON,由 Master 节点定时触发,失败自动重试并写 .slm-history*

3.1 核心字段
  • schedule:cron 表达式,注意 ES 用 UTC。
  • name:支持 <yyyy-MM-dd-HH-mm> 占位符,防止重名。
  • repository:必填,指向上一节注册的仓库名。
  • config.indices:支持通配符,* 表示全部开放索引;-*kibana* 可排除系统索引。
  • retention.expire_after:快照存活时长,支持 30d12h
  • retention.min_count / max_count:兜底策略,防止“删光了”。
3.2 实战:每天 02:30 备份,保留 30 天,最少 7 份
PUT _slm/policy/daily-s3
{
  "schedule": "0 30 2 * * ?",
  "name": "<daily-s3-{now/d}>",
  "repository": "s3_prod",
  "config": {
    "indices": ["*","-.kibana*","-.slm-history*"],
    "include_global_state": false,
    "partial": false,
    "metadata": {
      "owner": "inf",
      "purpose": "daily-backup"
    }
  },
  "retention": {
    "expire_after": "30d",
    "min_count": 7,
    "max_count": 60
  }
}
3.3 灰度策略:按业务标签隔离

对日志集群,常见的做法是给索引打上 team:payteam:search 的 setting,然后写两条 SLM:

"config": {
  "indices": ["*"],
  "include_global_state": false,
  "feature_states": ["none"],
  "partial": false,
  "metadata": {
    "filter": "team:pay"
  }
}

快照名里用 <{metadata.filter}> 占位,即可在仓库路径里看到 pay-2025-11-23 这样的目录,恢复时直接 team:pay 过滤,避免“全量拉回”。


4. 快照并发调优

ES 7.10 之后支持分片级并发上传,参数在仓库层控制:

  • max_snapshot_bytes_per_sec:节点级限流,默认 40 MB/s。
  • max_restore_bytes_per_sec:恢复限流,防止刷爆 IO。

S3 插件额外提供:

  • canned_acl: bucket-owner-full-control(跨账号必备)
  • buffer_size: 100mb(内存换并发,默认 5 MB)
  • retry.count: 3(最终一致重试)

HDFS 插件提供:

  • conf.dfs.replication: 2(快照文件无需 3 副本,省空间)
  • conf.dfs.client.use.datanode.hostname: true(DNS 解析,避免 IP 漂移)

5. 跨集群恢复:一键“克隆”

场景:新集群做压测,需要 1 TB 线上数据,但不想走 reindex。步骤:

  1. 新集群注册同一个仓库(只读即可)。
  2. 查看快照列表:
    GET _snapshot/s3_prod/_all
    
  3. 按索引粒度恢复,并改名:
    POST _snapshot/s3_prod/daily-s3-2025-11-22/_restore
    {
      "indices": "pay-order-2025-11-22",
      "rename_pattern": "(.+)",
      "rename_replacement": "restore_$1",
      "include_global_state": false,
      "index_settings": {
        "number_of_replicas": 0,
        "refresh_interval": "-1"
      }
    }
    
  4. 观察集群 cat/recovery;完成后把副本调成 1,refresh 调成 1s,即可对外服务。

注意:S3 最终一致可能导致 IndexShardSnapshotFailedException——ES 7.17 已内置重试,若仍失败,手动 DELETE snapshot 后重跑 SLM。


6. 灾备演练:把“备份”变“可用”

真正灾难时,恢复时间 = 快照下载 + translog replay + 业务验证。演练脚本(bash + jq):

#!/bin/bash
REPO=s3_prod
SNAP=daily-s3-$(date -d '-1 day' +%F)
TARGET=restore_$(date +%s)

# 1. 找到最大的 5 个索引
INDICES=$(curl -s -XGET "localhost:9200/_cat/indices?bytes=b&h=index,store.size" | \
          sort -k2 -nr | head -5 | awk '{print $1}' | paste -sd,)

# 2. 恢复
curl -XPOST "localhost:9200/_snapshot/$REPO/$SNAP/_restore?wait_for_completion=false" -H "Content-Type: application/json" -d"
{
  \"indices\": \"$INDICES\",
  \"rename_pattern\": \"(.+)\",
  \"rename_replacement\": \"${TARGET}_$1\",
  \"include_global_state\": false,
  \"index_settings\": {
    \"number_of_replicas\": 0
  }
}"

# 3. 轮询 recovery
until [[ $(curl -s "localhost:9200/_cat/recovery?h=stage" | grep -c done) -eq $(echo $INDICES | tr ',' '\n' | wc -l) ]]; do
  sleep 30
done

# 4. 校验 doc 数
for idx in $(echo $INDICES | tr ',' '\n'); do
  ori=$(curl -s "localhost:9200/$idx/_count" | jq -r .count)
  new=$(curl -s "localhost:9200/${TARGET}_${idx}/_count" | jq -r .count)
  echo "$idx $ori -> ${TARGET}_${idx} $new"
done

跑完输出:

pay-order-2025-11-22 512345678 -> restore_1732231200_pay-order-2025-11-22 512345678

数量一致即演练通过;最后批量 DELETE restore_* 清理。


7. 监控与告警

SLM 会把每次执行结果写到 .slm-history-7-*,配套 Kibana 规则:

{
  "name": "SLM 连续失败 2 次",
  "type": "count",
  "index": ".slm-history-*",
  "time_field": "@timestamp",
  "query": "result:FAILED",
  "threshold": 2,
  "window": "1h",
  "actions": {
    "webhook": {
      "url": "https://alert.example.com/webhook/slm",
      "body": "{\"text\":\"SLM 连续失败 2 次,请检查仓库权限或磁盘空间\"}"
    }
  }
}

同时监控仓库级指标:

  • es_snapshot_stats{state=STARTED} 长时间不下降 → 卡住。
  • es_repository_s3_chunk_upload_bytes 增长缓慢 → 限流或网络瓶颈。

8. 常见问题速查

Q1:快照卡在 “intializing” 不动?
→ 查看 Master log,大概率是 repository 路径权限问题;S3 检查 IAM 是否忘开 s3:AbortMultipartUpload

Q2:恢复后索引 red?
→ 原集群有 5 主分片,新集群只有 3 数据节点,且 cluster.routing.allocation.awareness.force.zone.values 限制导致分片无法分配;临时 PUT settings {"number_of_replicas":0} 即可。

Q3:SLM 保留策略没删快照?
→ 快照正被恢复或仍在进行中;SLM 会跳过“in-use”快照,先 DELETE /_snapshot/repo/snap 手动删,再查 .slm-history 看报错。


9. 小结

  • 仓库先决:HDFS 重权限,S3 重一致;先把 keystore 与 IAM 搞对,再谈备份。
  • SLM 三板斧:schedule 定时、retention 定寿、indices 定范围;配合通配符与元数据,能做到“千人千面”的备份策略。
  • 灾备不是“有快照”就行,而是“敢恢复”。每月一次演练,把 max_restore_bytes_per_sec 拉到 2 GB/s,测出真实 RTO,写进 On-Call 手册。

把这一节配置直接粘进集群,明天凌晨 02:30,第一枚自动快照就会悄悄生成;当你某天真的“手抖”删了索引,只需一条 _restore,数据就能在分钟级回到任何你想要的时间点——这就是 SLM 与分布式仓库给 Elasticsearch 带来的“时间回溯”能力。
更多技术文章见公众号: 大城市小农民

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

乔丹搞IT

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值