适用版本: 6.8-7.17
1. 错误异常的基本描述 #
a snapshot is already running 是 Elasticsearch 在创建快照时抛出的并发控制异常。当你尝试在某个快照仓库(repository)上创建新快照,但该仓库已经有正在执行的快照任务时,就会触发此错误。Elasticsearch 的快照机制采用串行执行策略,同一仓库同一时间只能有一个活跃的快照任务。
常见现象 #
- Elasticsearch 返回 HTTP
409 Conflict状态码,表示并发冲突。 - 创建快照的请求(
PUT _snapshot/<repo>/<snapshot_name>)失败。 - 在 Elasticsearch 服务端日志中会记录
ConcurrentSnapshotExecutionException。 - 如果是通过定时任务(SLM)或自动化脚本创建快照,会导致后续快照任务失败。
- 如果前一个快照长时间不结束,后续所有新快照都会连续失败。
典型报错与异常栈 #
该异常的典型日志形态如下:
ConcurrentSnapshotExecutionException: [repo:snap-20260331] a snapshot is already running
at org.elasticsearch.snapshots.ConcurrentSnapshotExecutionException.<init>(ConcurrentSnapshotExecutionException.java:...)
at org.elasticsearch.snapshots.SnapshotsService.createSnapshot(SnapshotsService.java:...)
at org.elasticsearch.action.admin.cluster.SnapshotsStatusTransportAction.shardOperation(SnapshotsStatusTransportAction.java:...)
通过 API 请求的响应通常如下:
{
"error": {
"root_cause": [
{
"type": "snapshot_creation_exception",
"reason": "[repo:snap-20260331] a snapshot is already running"
}
],
"type": "snapshot_creation_exception",
"reason": "[repo:snap-20260331] a snapshot is already running",
"status": 409
},
"status": 409
}
另一种常见形态(查看当前快照状态):
GET /_snapshot/my_repo/_current
{
"snapshots": [
{
"snapshot": "snap-20260330",
"state": "STARTED",
"start_time_in_millis": 1711856400000,
"failures": [],
"shards_stats": {...}
]
}
2. 为什么会发生这个错误 #
Elasticsearch 的快照服务(SnapshotsService)会维护一个 SnapshotsInProgress 状态机来管理当前仓库上正在执行的快照任务。源码中的逻辑是:
if (snapshots != null && snapshots.asStream()
.anyMatch(entry -> (entry.state() == State.INIT && initializingSnapshots.contains(entry.snapshot()) == false) == false)) {
throw new ConcurrentSnapshotExecutionException(repositoryName, snapshotName, "a snapshot is already running");
}
这意味着只要 SnapshotsInProgress 里还有未完成的快照条目,就不会允许新的快照在同一仓库上并发启动。
常见原因包括:
- 上一个快照仍在执行:初始化、写分片文件或等待 finalize 阶段尚未完成。
- 定时任务和人工操作重叠:SLM 策略、外部调度器和人工快照请求撞在同一时间窗口。
- 快照任务耗时过长:因为主节点切换、慢存储或分片问题导致快照执行时间异常长。
- 自动化脚本缺少排他控制:失败后立即重复发起新快照,没有检查当前状态。
- 主节点切换后的短时现象:旧任务状态尚未清理,导致新任务被拒绝。
- 仓库状态异常:某些分片的快照操作卡住,导致整个快照无法完成。
3. 如何排查和解决这个异常和解决这个异常 #
排查步骤 #
建议按以下顺序进行排查:
第一步:查看当前仓库正在执行的快照 #
# 查看当前仓库正在执行的快照
curl -X GET "localhost:9200/_snapshot/my_repo/_current?pretty"
# 查看所有快照及其状态
curl -X GET "localhost:9200/_snapshot/my_repo/_all?pretty" | jq '.snapshots[] | select(.state != "SUCCESS")'
# 查看快照状态详情
curl -X GET "localhost:9200/_snapshot/my_repo/_status?pretty"
第二步:查看活跃任务和主节点日志 #
# 查看是否存在长时间运行的快照相关任务
curl -X GET "localhost:9200/_tasks?actions=*snapshot*&pretty"
# 查看主节点日志中的快照相关信息
tail -n 500 /var/log/elasticsearch/elasticsearch.log | grep -A 10 "snapshot.*STARTED\|INIT\|FINALIZE"
第三步:判断快照卡在哪个阶段 #
# 查看快照进度
curl -X GET "localhost:9200/_snapshot/my_repo/snap-20260330/_status?pretty" | jq '.snapshots[0].shards_stats'
# 检查是否有失败的分片
curl -X GET "localhost:9200/_snapshot/my_repo/snap-20260330/_status?pretty" | jq '.snapshots[0].failures'
第四步:核对定时任务和人工操作时间线 #
# 查看 SLM 策略的执行历史
curl -X GET "localhost:9200/_slm/policy/my_policy/_stats?pretty"
# 查看最近修改的快照相关配置
curl -X GET "localhost:9200/_cluster/state/metadata?pretty" | jq '.metadata.persistent.indices.".tasks"'
排查时需要注意的问题 #
- 区分并发运行和同名快照:
a snapshot is already running是并发执行冲突,snapshot with the same name already exists是历史记录冲突,两者不同。 - 不要盲目重试:如果快照任务只是慢,急于重试会叠加更多同类请求。
- 检查主节点状态:如果是主节点切换后的短时现象,结合 cluster state 日志判断旧任务是否真的已经结束。
- 关注耗时异常长的快照:正常快照应该在分钟级别完成,如果运行数小时需要深入排查。
4. 如何解决这个错误 #
常用修复思路 #
方案一:等待当前快照完成(推荐) #
# 监控当前快照状态,等待完成
while true; do
STATUS=$(curl -s "localhost:9200/_snapshot/my_repo/_current" | jq -r '.snapshots[0].state // "NONE"')
echo "Current snapshot state: $STATUS"
if [ "$STATUS" = "NONE" ] || [ "$STATUS" = "SUCCESS" ]; then
echo "Snapshot completed, can create new one now"
break
fi
sleep 30
done
# 然后创建新快照
curl -X PUT "localhost:9200/_snapshot/my_repo/snap-$(date +%Y%m%d)" -H 'Content-Type: application/json' -d '
{
"indices": "my_index*",
"ignore_unavailable": true,
"include_global_state": false
}'
方案二:调整 SLM 和备份任务的时间窗口 #
# 查看当前 SLM 策略的调度配置
curl -X GET "localhost:9200/_slm/policy?pretty"
# 更新策略,避免时间重叠
curl -X PUT "localhost:9200/_slm/policy/my_policy" -H 'Content-Type: application/json' -d '
{
"schedule": "0 2 * * *", # 调整执行时间
"name": "<my_index-{now/d}>",
"repository": "my_repo",
"config": {
"indices": ["my_index*"]
}
}'
方案三:为自动化脚本增加状态检查 #
# Python 示例:在创建快照前检查当前状态
import requests
import time
repo = "my_repo"
snapshot_name = "snap-20260331"
# 检查当前是否有运行中的快照
response = requests.get(f"http://localhost:9200/_snapshot/{repo}/_current")
if response.json().get('snapshots'):
print(f"Snapshot already running, waiting...")
while True:
time.sleep(30)
response = requests.get(f"http://localhost:9200/_snapshot/{repo}/_current")
if not response.json().get('snapshots'):
break
# 创建新快照
requests.put(f"http://localhost:9200/_snapshot/{repo}/{snapshot_name}", json={
"indices": "my_index*",
"ignore_unavailable": True
})
方案四:处理卡住的快照(谨慎操作) #
# 如果快照确实卡住无法完成,可以考虑删除仓库重建(⚠️ 危险操作)
# 1. 先关闭所有索引
curl -X POST "localhost:9200/my_index*/_close"
# 2. 删除有问题的仓库(这会删除仓库中的所有快照!)
curl -X DELETE "localhost:9200/_snapshot/my_repo"
# 3. 重新创建仓库
curl -X PUT "localhost:9200/_snapshot/my_repo" -H 'Content-Type: application/json' -d '
{
"type": "fs",
"settings": {
"location": "/mnt/snapshots",
"compress": true
}
}'
后续注意事项与推荐建议 #
- 建立快照监控:监控快照执行状态、耗时和成功率,及时发现异常长的快照任务。
- 错开定时任务时间:确保 SLM 策略、外部备份任务和人工操作的时间窗口不重叠。
- 增加排他控制逻辑:在自动化脚本中,先检查
_current状态再决定是否提交新快照。 - 设置合理的超时:为快照操作设置合理的超时时间,避免长时间占用执行窗口。
- 定期清理旧快照:建立快照生命周期管理,避免仓库中积累过多历史快照。
借助 INFINI 产品提升排障效率 #
INFINI Console 提供快照状态的可视化监控界面,可以直观地查看、管理和调试快照任务。通过 Console 的快照管理功能,可以快速发现正在运行的快照、查看进度和失败分片,并直接删除异常卡住的快照。
INFINI Gateway 可以作为 Elasticsearch API 的代理层,在快照创建请求到达 Elasticsearch 之前进行拦截和检查。Gateway 可以自动检测并发冲突,并根据预定义的策略(如排队等待、返回友好错误、转发到备用仓库等)进行处理。
对于依赖快照进行数据备份的团队,建议结合 INFINI Console 的快照监控功能和 INFINI Gateway 的请求治理能力,建立从快照创建、监控、到恢复的完整自动化流程,减少因并发冲突导致的备份失败。
5. 小结 #
a snapshot is already running 是一个典型的并发控制错误,根源在于同一仓库同一时间只能有一个活跃的快照任务。虽然报错信息直接指向并发冲突,但解决思路需要根据快照的实际状态来决定:是等待完成、调整时间窗口,还是处理卡住的任务。
在实际工作中,为避免此类问题,建议建立快照监控体系、错开定时任务时间、并在自动化脚本中增加状态检查逻辑。更重要的是,考虑使用 INFINI Console 来实现可视化的快照管理,使用 INFINI Gateway 来拦截和预处理快照创建请求,从源头避免并发冲突的发生。
相关错误 #
- snapshot-with-the-same-name-is-already-in-progress:同名快照已在进行中
- another-snapshot-is-currently-running-cannot-delete:删除操作被活跃快照阻塞
- snapshot-with-the-same-name-already-exists:同名快照已存在
- failed-to-perform-snapshot-index-files:快照执行失败
- snapshot-is-already-in-progress-cannot-delete:快照已在进行中无法删除
参考文档 #
附:日志上下文 #
下面保留当前页面中的源码或日志片段,便于继续结合异常调用栈定位问题:
if (snapshots != null && snapshots.asStream()
.anyMatch(entry -> (entry.state() == State.INIT && initializingSnapshots.contains(entry.snapshot()) == false) == false)) {
throw new ConcurrentSnapshotExecutionException(repositoryName, snapshotName, "a snapshot is already running");
}





