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

适用版本: 6.8-7.15

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

Could not start datafeed [datafeed_id] as indices are being upgraded 是 Elasticsearch 机器学习模块在集群处于升级模式时抛出的保护性异常。当集群正在对 ML 相关的系统索引(如 .ml-anomalies-*.ml-state-*.ml-meta-* 等)进行版本升级或迁移时,所有 datafeed 任务会被暂时阻止启动,以避免在索引结构不一致的状态下产生数据损坏或状态冲突。

常见现象 #

  • 启动 datafeed 时接口返回 429 Too Many Requests 状态码,并携带上述错误信息。
  • 在 Kibana 的 Machine Learning 页面中,datafeed 状态显示为 stopped 且无法手动启动。
  • 集群日志中反复出现 datafeed 启动失败的记录,但无明显的数据写入失败。
  • 如果此时尝试通过 API 强制启动,会立即收到异常响应,不会进入重试队列。

典型报错 #

{
  "error": {
    "root_cause": [
      {
        "type": "status_exception",
        "reason": "Could not start datafeed [datafeed-high-cpu] as indices are being upgraded"
      }
    ],
    "type": "status_exception",
    "reason": "Could not start datafeed [datafeed-high-cpu] as indices are being upgraded"
  },
  "status": 429
}

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

Elasticsearch 的机器学习模块在版本升级或系统索引迁移过程中,会将集群标记为 ML Upgrade Mode。在此模式下,所有涉及 ML 系统索引的写操作和数据feed 任务都会被拦截。

源码层面的判断逻辑如下:

if (MlMetadata.getMlMetadata(clusterState).isUpgradeMode()) {
    throw new ElasticsearchStatusException(
        "Could not start datafeed [" + datafeedId + "] as indices are being upgraded",
        RestStatus.TOO_MANY_REQUESTS,
        detail
    );
}

常见触发原因包括:

  • 集群版本升级:从 6.x 升级到 7.x 后,ML 索引需要迁移到新的内部格式,升级过程中 upgrade mode 处于开启状态。
  • 系统索引自动升级:Elasticsearch 在启动时发现 ML 索引的版本与当前节点版本不匹配,自动触发升级流程。
  • 插件或功能迁移:安装/卸载 ML 相关插件,或执行 _ml/migrate 类操作时,会短暂进入升级模式。
  • 集群恢复后初始化:集群从快照恢复后,ML 索引可能需要进行兼容性升级,在升级完成前 datafeed 无法启动。
  • 手动触发升级任务:管理员通过 API 手动触发了 ML 索引升级,未等待完成就尝试启动 datafeed。

3. 如何排查这个异常 #

建议按以下步骤确认当前集群状态和升级进度:

3.1 检查 ML 升级模式状态 #

# 查看集群 ML 元数据信息
GET _cluster/state?filter_path=metadata.ml

# 或直接查询 upgrade_mode 状态
GET _ml/_info

如果返回中 upgrade_mode: true,说明集群正处于升级模式。

3.2 查看升级任务进度 #

# 查看当前正在执行的任务
GET _tasks?actions=*ml*migrate*&detailed=true

# 查看 ML 相关线程池和任务状态
GET _cat/tasks?v&actions=*ml*

3.3 检查系统索引状态 #

# 查看 ML 相关索引的健康状态
GET _cat/indices/.ml-*?v&s=index

# 查看是否有索引处于 red 或 yellow 状态
GET _cluster/health/.ml-*?pretty

3.4 查看节点日志 #

在 Elasticsearch 日志文件中搜索以下关键字,确认升级任务的启动和结束时间:

grep -i "upgrade\|migration\|ml.*index" /var/log/elasticsearch/elasticsearch.log

4. 如何解决这个错误 #

4.1 等待升级完成(推荐) #

大多数情况下,ML 索引升级是自动且快速的(通常在秒级到分钟级完成)。等待升级完成后,datafeed 可以正常启动:

# 轮询检查 upgrade_mode 是否结束
GET _cluster/state?filter_path=metadata.ml.upgrade_mode

# 升级完成后启动 datafeed
POST _ml/datafeeds/datafeed-high-cpu/_start

4.2 手动触发升级(如升级卡住) #

如果发现升级任务长时间未完成,可尝试手动触发或重试升级流程:

# 手动触发 ML 索引迁移(适用于升级卡住的场景)
POST _ml/migrate

# 检查迁移结果
GET _ml/migrate

4.3 检查并修复异常索引 #

如果升级任务因索引异常而卡住,需要先修复底层索引问题:

# 查看是否有未分配的分片
GET _cat/shards/.ml-*?v&h=index,shard,prirep,state,unassigned.reason

# 尝试恢复 red 状态的索引
POST _cluster/reroute?retry_failed=true

4.4 回退方案 #

如果升级长时间无法完成且影响业务,可考虑在维护窗口内重启集群节点,触发重新初始化(仅在充分评估后使用):

# 在维护窗口内逐个重启 ML 节点,避免整个集群同时不可用
# 重启后再次检查 upgrade_mode 状态

5. 预防措施 #

  • 规划升级窗口:在执行集群版本升级前,提前停止所有 datafeed 和 ML 任务,避免在升级过程中触发保护机制。
  • 监控 ML 任务状态:通过监控平台持续关注 datafeed 和 job 的状态,升级前发送告警并自动停止相关任务。
  • 分阶段升级:对于生产集群,采用滚动升级方式,每次升级后确认 ML 索引升级完成,再继续下一节点。
  • 定期备份 ML 数据:在执行大版本升级前,对 ML 相关索引创建快照,避免升级失败后无法回滚。
  • 使用维护模式:在升级前将集群设置为维护模式,防止自动任务在升级窗口内被触发。

6. 小结 #

Could not start datafeed as indices are being upgraded 是 Elasticsearch 在 ML 索引升级期间的保护性异常,不属于配置错误。处理的核心是确认升级任务进度,等待或辅助升级完成后再启动 datafeed。通过合理的升级规划和监控手段,可以有效避免此类异常对业务造成影响。

相关错误 #

附:日志上下文 #

public void checkDatafeedTaskCanBeCreated() {
    if (MlMetadata.getMlMetadata(clusterState).isUpgradeMode()) {
        String msg = "Unable to start datafeed [" + datafeedId +"] explanation [" + AWAITING_UPGRADE.getExplanation() + "]";
        LOGGER.debug(msg);
        Exception detail = new IllegalStateException(msg);
        throw new ElasticsearchStatusException("Could not start datafeed [" + datafeedId +"] as indices are being upgraded",
            RestStatus.TOO_MANY_REQUESTS, detail);
    }
    AssignmentFailure assignmentFailure = checkAssignment();
    if (assignmentFailure != null && assignmentFailure.isCriticalForTaskCreation) {
        String msg = "No node found to start datafeed [" + datafeedId + "]; ";
        // ...
    }
}