📣 极限科技诚招搜索运维工程师(Elasticsearch/Easysearch)- 全职/北京 👉 : 立即申请加入

适用版本: 7.12-8.9

1. 错误异常的基本描述 #

当 Elasticsearch 在读取仓库元数据 RepositoryData 时,按快照名称遍历 snapshotIds 仍然找不到目标快照,就会抛出 snapshot [snapName] not found in repository [repoName]。这不是“快照执行失败”的泛化报错,而是一个明确的元数据查找失败异常。

常见现象 #

  • 调用快照恢复、删除、查看状态等接口时返回 404500
  • 仓库中明明存在大量快照,但指定名称的快照无法被解析。
  • 快照名称曾被人工记录在运维脚本、ILM 策略或备份平台中,但仓库当前代际元数据里已不存在该条目。

典型报错与异常栈 #

snapshot [daily-es-2024.12.01] not found in repository [prod-backup]
org.elasticsearch.snapshots.SnapshotMissingException

2. 为什么会发生这个错误 #

从源码看,Elasticsearch 会先加载仓库的 RepositoryData,再通过快照名称匹配 SnapshotId。如果没有匹配项,就直接抛出 SnapshotMissingException。常见根因包括:

  • 请求里使用了错误的快照名,尤其是脚本拼接、日期格式、环境前缀不一致时。
  • 快照已经被删除,但外部调度、恢复脚本或 ILM 仍在引用旧名称。
  • 仓库元数据曾被并发更新或损坏,导致某些快照记录缺失。
  • 用户查的是逻辑名,但仓库已切换、重建或指向了不同后端目录。

3. 如何排查和解决这个异常和解决这个异常 #

建议先确认“快照是否真的不存在”,再判断是请求错误还是仓库元数据异常。

  1. 查看仓库中的快照清单:
GET /_snapshot/prod-backup/_all
  1. 如果快照很多,按名称过滤或人工比对最近生成记录,确认目标名是否拼写一致。
  2. 检查调用来源,尤其是自动化恢复脚本、ILM/SLM、CI 备份任务是否还在引用旧快照名。
  3. 若你确信快照应当存在,但 _all 中也查不到,进一步检查仓库后端是否被人工清理、覆盖或切换目录。
  4. 查看主节点日志,确认在加载 RepositoryData 时是否同时伴随仓库读取异常、代际不一致或 blob 缺失。

排查时需要注意的问题 #

  • 不要只凭对象存储里“看起来像快照文件”的目录判断快照存在与否,Elasticsearch 以仓库元数据为准。
  • 如果仓库被多个集群写入,某些快照可能在元数据竞争中丢失可见性。
  • 恢复脚本里常见问题是把快照名、仓库名、索引名三者混用,先校对参数来源。

4. 如何解决这个错误 #

常用修复思路 #

  • 如果只是名称写错,修正请求中的 snapshot 参数即可。
  • 如果快照确实已删除,需要更新外部任务配置,避免继续引用失效名称。
  • 如果仓库被误切换到其他后端位置,恢复正确的仓库配置并重新验证:
GET /_snapshot/prod-backup
  • 如果怀疑仓库元数据异常,先将仓库切为只读,检查底层存储中的 index-Nindex.latest 与快照清单是否一致,再决定是否重建仓库引用。

相关 Elasticsearch API #

  • GET /_snapshot/{repository}/_all:查看仓库当前可见的全部快照。
  • GET /_snapshot/{repository}/{snapshot}:按名称查询单个快照。
  • DELETE /_snapshot/{repository}/{snapshot}:删除指定快照,前提是该快照在元数据中存在。

借助 INFINI 产品提升排障效率 #

  • INFINI Console 可以集中查看快照任务、节点日志与仓库相关异常趋势。
  • INFINI Gateway 可用于追踪是谁在持续请求一个已经不存在的快照名称。

5. 小结 #

snapshot [snapName] not found in repository [repoName] 的关键不在于“对象存储里有没有文件”,而在于仓库当前加载到的 RepositoryData 里有没有这个快照记录。优先校验请求参数,再检查仓库绑定位置和元数据一致性,通常可以很快定位问题。

相关错误 #

附:日志上下文 #

repositoryData.getSnapshotIds()
	.stream()
	.filter(snapshotId -> snapshotId.getName().equals(request.snapshot().getSnapshot()))
	.findFirst()
	.orElseThrow(() -> new SnapshotMissingException(repositoryName, request.snapshot().getSnapshot()));