故障排除数据损坏
编辑故障排除数据损坏
编辑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 上,fio
和 stress-ng
工具都可以生成具有挑战性的 I/O 工作负载并验证其写入数据的完整性。使用 0.12.01 或更高版本的 stress-ng
,因为早期版本没有足够强的完整性检查。使用诸如 diskchecker.pl
之类的脚本验证持久写入在断电后是否仍然存在。或者,使用诸如 strace
之类的工具来观察 Elasticsearch 在写入数据时进行的系统调用的序列,并确认此序列无法解释报告的损坏。
为了缩小损坏源的范围,系统地更改集群环境中的组件,直到损坏停止。具体细节将取决于您环境的确切配置,但可能包括以下内容
- 尝试不同的文件系统或不同的内核。
- 尝试依次更改每个硬件组件,理想情况下更改为不同的型号或制造商。
- 尝试每个硬件组件的不同固件版本。
- 删除可能修改 Elasticsearch 数据路径内容的任何第三方软件。