问题现象

Kibana 启动后控制台持续输出:

[version_conflict_engine_exception]:
  [task:endpoint:user-artifact-packager:1.0.0]
  [task:Alerting-alerting_telemetry]
  [task:apm-telemetry-task]
version conflict, document already exists (current version [xx])

三个 “task” 前缀的索引反复报版本冲突。

什么是版本冲突(写给不熟悉 ES 的人)

ElasticSearch 是分布式系统,多个节点可能同时修改同一条数据。ES 使用乐观并发控制来协调:

每次对文档的任何修改,ES 都会给它一个递增的版本号。

  Document A(version=1)
    ├── 节点A 尝试修改 → "基于 version=1 修改" → 成功 → version=2
    └── 节点B 同时尝试修改 → "基于 version=1 修改" → 冲突!version 已经是 2 了
  
  节点B 收到 version_conflict_engine_exception。

这和 Git 的冲突概念相似——你基于旧版本做的修改推不上去,因为别人先改了。

根因分析

Kibana 在升级或重新部署时,会尝试创建/更新 ES 中的内部索引(存仪表盘配置、告警规则、APM 数据等)。但旧的 Kibana 实例或残留的数据可能有不同的版本号。

具体到这几个 task: 前缀的索引,它们是 Kibana 的后台任务调度器内部使用的:

  • task:endpoint:user-artifact-packager — Endpoint 安全组件
  • task:Alerting-alerting_telemetry — 告警遥测
  • task:apm-telemetry-task — APM 监控遥测

升级路径中这些 task 索引的 mapping 或文档格式发生变化,旧的文档版本号与新写入冲突。

两种处置思路

可接受数据丢失:删除索引

# 查看冲突的索引
curl -X GET "localhost:9200/_cat/indices/task*?v"

# 删除
curl -X DELETE "localhost:9200/.kibana_task_manager_*"

Kibana 会在下次启动时重建这些索引。控制台配置、仪表盘存在其他索引中,不受影响。但告警历史、APM 配置可能丢失。

不能丢数据:升级流程

参考 ES 官方文档中的版本控制章节:

核心思路是用 version_type=external 参数强制执行:

curl -X POST "localhost:9200/.kibana_task_manager/_update/xxx?version=999&version_type=external" \
  -H 'Content-Type: application/json' -d '{ ... }'

version_type=external 告诉 ES:只要我的版本号大于当前值就覆盖。这绕过了乐观锁。

从根源避免

Kibana 和 ES 的版本匹配很重要。Kibana 7.x 配 ES 7.x,版本号要一致(都是 7.10 或都是 7.17),跨大版本一定出问题。

问题排查方法论

从这个 bug 学到的最有价值的东西不是修复本身,而是搜索路径:

1. 官方文档(elastic.co/guide)     ← 最快最准
2. GitHub Issue(elastic/elasticsearch) ← 有人遇到过同样的坑
3. Stack Overflow / 中文论坛        ← 最后的手段

官方文档对版本冲突有完整章节——英文阅读的障碍远小于用错误解决方案浪费时间。