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

适用版本: 7.x-8.x

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

failed to read operation from translog 表示 Elasticsearch 在执行实时读取(realtime get)时,试图直接从 translog 中恢复最近写入的操作记录,但读取过程失败并抛出了 IOException

在 Elasticsearch 内部,实时获取文档(get API)的流程是:先检查 translog 中是否存在尚未刷新到 Lucene 段的最新操作,如果存在则直接从 translog 读取并返回。这样设计是为了保证刚写入的文档能立即被读取到,而不必等待一次 refresh。当 translog 文件本身损坏、被截断或底层存储不可读时,这个读取路径就会失败,引擎会调用 maybeFailEngine("realtime_get", e) 将该错误标记为可能导致引擎失效的严重问题。

常见现象 #

  • 调用 GET /<index>/_doc/<id> 时返回 500 内部服务器错误,响应体中包含 failed to read operation from translog
  • 节点日志中出现 EngineException: failed to read operation from translog,并伴随 IOException 堆栈。
  • 受影响的索引分片可能进入 REDYELLOW 状态,具体取决于是否有可用副本。
  • 如果该分片随后被标记为失败,集群可能出现分片重分配、恢复任务或类似 relocation failed 的后续异常。

典型报错与异常栈 #

org.elasticsearch.index.engine.EngineException: failed to read operation from translog
    at org.elasticsearch.index.engine.InternalEngine.getFromTranslog(InternalEngine.java:...)
    at org.elasticsearch.index.engine.InternalEngine.get(InternalEngine.java:...)
Caused by: java.io.IOException: Input/output error
    at java.io.FileInputStream.readBytes(Native Method)
    at java.io.FileInputStream.read(FileInputStream.java:...)

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

failed to read operation from translog 的根源几乎总是 translog 文件或其所在的存储层出了问题。translog 是 Elasticsearch 保证数据可靠性的关键组件,每个分片在本地磁盘上都维护着一组 translog 文件(.tlog / translog-*.tlog),一旦这些文件无法被正确读取,实时获取路径就会中断。

常见原因包括:

  • translog 文件损坏或截断:节点异常宕机、被 kill -9 强制终止、或磁盘空间耗尽导致 translog 写入不完整,重启后文件内容不一致。
  • 磁盘 I/O 异常或文件系统错误:底层磁盘出现坏道、文件系统元数据损坏、或因内核 I/O 错误导致读取返回 EIO
  • 云盘或容器存储卷瞬时故障:云厂商块存储短时不可用、容器运行时挂载点异常、或 Pod 被驱逐后存储卷未及时卸载。
  • 分片本地数据不一致:节点异常重启后,translog 中记录的操作与 Lucene 段状态不匹配,引擎在重放 translog 时校验失败。
  • 多个故障叠加:例如磁盘即将写满时又发生节点重启,translog 既不完整又无法扩展,进一步放大了恢复失败的概率。

3. 如何排查这个异常 #

建议按"先定位范围、再排查根因、后评估修复方案"的顺序处理:

  1. 在日志中搜索同一时间窗口内是否同时出现 engine failuretragic eventdetected engine failureIOExceptionI/O error 或磁盘相关报错,确认问题的严重程度。
  2. 从异常堆栈中定位具体索引和分片 ID(shardId),确认故障是发生在主分片还是副本分片上。
  3. 检查该节点磁盘使用率(df -h)、inode 使用率、以及 dmesg / journalctl 中的存储层错误日志。
  4. 通过 _cat/shards/<index_name> 或 INFINI Console 确认分片当前状态,判断是否存在健康副本可以替代。
  5. 如果问题只影响单个副本且主分片正常,通常可以通过分片重新分配解决;如果主分片也受损,则需要考虑快照恢复。

排查时需要注意的问题 #

  • translog 错误往往是结果而非原因,务必同时核查磁盘健康、节点近期重启记录和存储层告警,避免只修复表象。
  • 如果集群开启了 index.translog.durability: request(默认是 async),translog 在每次写入后都会 fsync,磁盘故障对其影响更为直接。
  • 在容器化环境中,注意区分"存储卷本身故障"和"挂载点权限/生命周期问题"两种不同场景。

4. 如何解决这个错误 #

常用修复思路 #

  • 优先修复底层存储问题:确认磁盘或云盘恢复正常后再进行后续操作,否则任何基于该节点的恢复都会再次失败。
  • 利用健康副本重建:如果该索引有其他正常副本,可以执行 _cluster/reroute 或通过自动分片分配让 Elasticsearch 自动重建受损副本:
    # 查看分片分配状态
    GET _cat/shards/<index_name>?v
    
    # 如果副本分片卡住,可以尝试手动触发分片分配
    POST _cluster/reroute
    {
      "commands": [
        {
          "allocate_replica": {
            "index": "<index_name>",
            "shard": 0,
            "node": "<target_node_name>"
          }
        }
      ]
    }
    
  • 从快照恢复:如果主分片和所有副本都受损,且集群配置了快照仓库,可以从最近的快照恢复该索引:
    POST _snapshot/<repo_name>/<snapshot_name>/_restore
    {
      "indices": "<index_name>",
      "include_global_state": false
    }
    
  • 作为最后手段清空分片数据:如果无快照可用且数据可以丢失,可以停止该节点、删除对应分片目录下的 translog/ 文件夹,再重启节点让分片重新从主分片同步(仅限测试环境或可接受数据丢失的场景)。

预防措施与最佳实践 #

  • 为节点磁盘配置监控告警(使用率 > 85% 时预警),避免磁盘写满导致 translog 损坏。
  • 定期创建快照,确保任何分片数据都可以在极端情况下从快照恢复。
  • 避免对生产节点使用 kill -9 强制终止进程,优先使用 kill -15 或系统的服务管理命令优雅关闭。
  • 在云环境或 Kubernetes 中,为 Elasticsearch 数据目录使用可靠的持久化存储,并设置合理的 fsgroup 和挂载选项。
  • 使用 INFINI Console 持续监控集群健康状态、分片分配情况和节点磁盘趋势,在问题扩大前及时介入。

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

  • INFINI Console 可以直观展示分片状态、节点磁盘使用率和异常趋势,帮助快速判断 translog 错误是局部问题还是系统性存储故障。
  • INFINI Gateway 部署在 Elasticsearch 前端,可以做请求审计和异常流量控制,减少因突发写入风暴导致的磁盘压力,从源头降低 translog 写入异常的概率。

5. 小结 #

failed to read operation from translog 不是普通查询异常,而是引擎在读取事务日志时遇到的 I/O 级别故障,通常预示着 translog 文件损坏或底层存储异常。排查时应先确认磁盘和存储层健康状态,再根据是否有健康副本决定是重建分片还是从快照恢复。做好磁盘监控和定期快照,是降低此类问题恢复成本的最有效手段。

相关错误 #

附:日志上下文 #

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

if (operation != null) {
    return getFromTranslog(get, (Translog.Index) operation, mappingLookup, documentParser, searcherWrapper);
} catch (IOException e) {
    maybeFailEngine("realtime_get", e); // lets check if the translog has failed with a tragic event
    throw new EngineException(shardId, "failed to read operation from translog", e);
}