故障排除数据损坏

编辑

Elasticsearch 期望它从磁盘读取的数据与之前写入的数据完全相同。如果它检测到磁盘上的数据与它写入的数据不同,它将报告某种异常,例如:

  • org.apache.lucene.index.CorruptIndexException
  • org.elasticsearch.gateway.CorruptStateException
  • org.elasticsearch.index.translog.TranslogCorruptedException

通常,这些异常是由于校验和不匹配引起的。Elasticsearch 写入磁盘的大部分数据都跟有一个校验和,该校验和使用一种称为 CRC32 的简单算法,该算法计算速度快,并且能够很好地检测使用故障存储时可能发生的各种随机损坏。CRC32 校验和不匹配绝对表明存在故障,当然,匹配的校验和并不能证明没有数据损坏。

验证校验和的成本很高,因为它涉及读取文件的每个字节,这需要付出大量的精力,并且可能会从文件系统缓存中逐出更多有用的数据,因此系统通常不会经常验证文件的校验和。这就是为什么您往往只在发生不寻常的事情时才会遇到数据损坏异常。例如,在合并、分片移动和快照期间经常会检测到数据损坏。这并不意味着这些过程导致了数据损坏:它们是少数需要读取整个文件的例子。Elasticsearch 会同时利用这个机会验证校验和,这时会检测到并报告数据损坏。它没有说明数据损坏的原因或发生的时间。数据损坏可能会在数月内未被检测到。

组成 Lucene 索引的文件是从头到尾按顺序写入的,然后永远不会被修改或覆盖。这种访问模式意味着校验和计算非常简单,可以在文件初始写入时动态进行,并且也可以避免在文件写入时,由于用户空间错误而导致校验和不正确的可能性。Elasticsearch 中计算校验和的部分非常简单,应用广泛并且经过了充分测试,因此您可以非常确信校验和不匹配确实表明从磁盘读取的数据与 Elasticsearch 之前写入的数据不同。

如果文件头损坏,则 Elasticsearch 可能无法计算出如何甚至开始读取文件,这可能会导致诸如以下之类的异常:

  • org.apache.lucene.index.IndexFormatTooOldException
  • org.apache.lucene.index.IndexFormatTooNewException

如果 Elasticsearch 需要的文件完全丢失,也可能会报告数据损坏,并出现诸如以下的异常:

  • java.io.FileNotFoundException
  • java.nio.file.NoSuchFileException

组成 Lucene 索引的文件在被使用之前会被完整写入。如果需要文件在重启后恢复索引,则您的存储系统之前已向 Elasticsearch 确认该文件已持久同步到磁盘。在 Linux 上,这意味着 fsync() 系统调用已成功返回。Elasticsearch 有时会报告索引已损坏,因为恢复索引所需的文件丢失,或者该文件存在但已被截断或缺少页脚。这可能表明您的存储系统错误地确认了持久写入。

Elasticsearch 在您的集群中检测到数据损坏有很多种可能的解释。像 Elasticsearch 这样的数据库会产生具有挑战性的 I/O 工作负载,这可能会发现其他测试可能会遗漏的微妙的基础设施问题。已知 Elasticsearch 会将以下问题暴露为文件损坏:

  • 文件系统错误,尤其是在较新的和非标准的文件系统中,这些文件系统可能没有经过足够的实际生产使用,无法确信它们能够正常工作。
  • 内核错误.
  • 驱动器或 RAID 控制器上运行的固件中的错误。
  • 配置不正确,例如将 fsync() 配置为在所有持久写入完成之前报告成功。
  • 硬件故障,可能包括驱动器本身、RAID 控制器、您的 RAM 或 CPU。
  • 修改 Elasticsearch 写入的文件的第三方软件。

除了校验和不匹配之外,数据损坏通常不会导致其他问题证据。不要将其解释为您的存储子系统工作正常,因此 Elasticsearch 本身导致了数据损坏的迹象。故障存储除了数据损坏外很少显示任何问题证据,但是数据损坏本身强烈表明您的存储子系统工作不正常。

要排除 Elasticsearch 作为数据损坏的来源,请使用 Elasticsearch 以外的其他方式生成 I/O 工作负载,并查找数据完整性错误。在 Linux 上,fiostress-ng 工具都可以生成具有挑战性的 I/O 工作负载,并验证它们写入的数据的完整性。使用 0.12.01 或更新版本的 stress-ng,因为早期版本没有足够强大的完整性检查。使用诸如 diskchecker.pl 之类的脚本验证持久写入在断电后是否仍然存在。或者,使用诸如 strace 之类的工具来观察 Elasticsearch 在写入数据时进行的系统调用序列,并确认该序列不能解释报告的损坏。

要缩小数据损坏的来源,请系统地更改集群环境中的组件,直到数据损坏停止。详细信息取决于您环境的确切配置,但可能包括以下内容:

  • 尝试不同的文件系统或不同的内核。
  • 尝试依次更换每个硬件组件,最好更换为不同的型号或制造商。
  • 尝试每个硬件组件的不同固件版本。
  • 删除任何可能修改 Elasticsearch 数据路径内容的第三方软件。