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

适用版本: 7.4-8.9

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

cannot run cleanup on readonly repository 表示你正在尝试对一个只读快照仓库执行 cleanup 操作。cleanup 并不是只读查询,它会扫描并移除仓库中不再被引用的遗留 blob,因此本质上属于写操作或至少是需要修改仓库内容的维护动作。对于只读仓库,Elasticsearch 会直接拒绝这类请求。

从当前源码片段看,异常在 cleanup(...) 方法刚开始时就通过 isReadOnly() 判断抛出,这说明问题不在 cleanup 执行中途,而是在入口阶段就被策略拦截。只要仓库还是只读状态,cleanup 就不会继续执行。

常见现象 #

  • 调用 repository cleanup 接口时立即失败,并提示仓库为 readonly。
  • 仓库可能可以正常查看、校验甚至恢复快照,但只要执行 cleanup 就会被拒绝。
  • 常见于灾备恢复仓库、跨集群共享仓库或被安全策略设为只读的对象存储仓库。
  • 从业务侧看,表现通常不是搜索异常,而是仓库维护任务、容量回收任务或运维清理任务失败。

典型报错与异常栈 #

这类错误通常会与下面这些关键字一起出现:

  • cannot run cleanup on readonly repository
  • repository_exception
  • readonly repository

常见日志通常类似下面这样:

RepositoryException: [my_repo] cannot run cleanup on readonly repository

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

这个错误的根因非常直接:cleanup 需要对仓库内容做整理,而只读仓库不允许任何可能改变仓库状态的操作。也就是说,报错不是偶发故障,而是配置策略与运维动作不匹配。

常见原因通常包括:

  • 仓库配置中明确设置了 readonly: true
  • 当前仓库是专门用于恢复或共享访问的,只允许读,不允许做 cleanup。
  • 底层对象存储或文件系统权限本身就是只读,即使逻辑上想清理,实际也没有权限执行。
  • 运维把 cleanup 任务错误地指向了只读仓库,而不是可写主仓库。

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

建议按“先确认仓库是否只读,再确认 cleanup 是否应该在这个仓库上执行”的顺序处理:

  1. 查看仓库配置,确认 readonly 是否为 true
  2. 确认当前 cleanup 操作是不是误发到了恢复仓库、备份副本仓库或共享只读仓库。
  3. 如果业务上确实需要 cleanup,确认是否应该切换到对应的可写主仓库执行。
  4. 如果要把仓库改回可写,先核对底层存储权限和运维策略是否允许。

相关 Elasticsearch API 及调用说明 #

1. 查看仓库配置 #

curl -X GET "http://localhost:9200/_snapshot/my_repo?pretty"

重点看 settings.readonly 是否为 true

2. 执行 cleanup #

curl -X POST "http://localhost:9200/_snapshot/my_repo/_cleanup?pretty"

如果仓库是只读的,这个接口会直接失败。

3. 更新仓库配置 #

如果业务上确定该仓库应允许维护操作,可以重新设置:

curl -X PUT "http://localhost:9200/_snapshot/my_repo?pretty" \
	-H 'Content-Type: application/json' \
	-d '{
		"type": "fs",
		"settings": {
			"location": "/mount/backups/es",
			"readonly": false
		}
	}'

但只有在仓库本来就该可写时才这样做,不能为了 cleanup 强行破坏恢复仓库的只读设计。

排查时需要注意的问题 #

  • cleanup 是维护写操作,不要把它误认为“只是清理查看一下”这种只读操作。
  • 如果仓库承担灾备恢复职责,通常应该保持只读,不建议为了 cleanup 临时改写策略。
  • 修改 readonly 之前必须确认底层存储权限、团队流程和仓库用途都允许这样做。

4. 如何解决这个错误 #

常用修复思路 #

  • 如果 cleanup 目标选错了,改到正确的可写仓库执行。
  • 如果仓库本来就应当维护和回收空间,修正仓库配置为可写,并同步修复底层存储权限。
  • 如果仓库设计上必须只读,就接受 cleanup 不能在此执行,并把清理动作放到主写仓库上完成。

后续注意事项与推荐建议 #

  • 为每个仓库标明职责边界,例如“主写备份仓库”“只读恢复仓库”。
  • 对 cleanup、delete snapshot、create snapshot 这类维护动作增加仓库类型检查,避免误操作只读仓库。
  • 在运维平台中把 readonly 状态显式展示出来,减少认知偏差。

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

  • INFINI Console 可以帮助观察快照仓库相关任务、错误趋势和配置变更后的效果。
  • INFINI Gateway 适合保留维护接口审计记录,帮助确认 cleanup 请求是不是发错仓库。

5. 小结 #

cannot run cleanup on readonly repository 的本质是仓库策略和运维动作冲突。只读仓库不接受 cleanup,这不是异常波动,而是明确的设计限制。

最有效的处理方式,是先确认这个仓库是否本来就不该被清理,再决定切换仓库还是调整其读写策略。只要把仓库用途区分清楚,这类错误通常很容易避免。

相关错误 #

附:日志上下文 #

下面保留当前页面中的源码或日志片段,便于继续结合异常调用栈定位问题:

* @param listener              Listener to complete when done
 */
 public void cleanup(long repositoryStateId; Version repositoryMetaVersion; ActionListenerlistener) {
 try {
 if (isReadOnly()) {
 throw new RepositoryException(metadata.name(); "cannot run cleanup on readonly repository");
 }
 MaprootBlobs = blobContainer().listBlobs();
 final RepositoryData repositoryData = safeRepositoryData(repositoryStateId; rootBlobs);
 final MapfoundIndices = blobStore().blobContainer(indicesPath()).children();
 final SetsurvivingIndexIds = repositoryData.getIndices()