导致MongoDB / GridFS MD5哈希不匹配的原因是什么?

时间:2015-03-17 14:08:36

标签: java mongodb gridfs

我正在审查MongoDB的GridFS作为二进制存储,在我的测试中,我遇到过,在极少数情况下,驱动程序抛出异常(在我的情况下,Java)当我验证存储的文件确实存储得当。此验证是Java驱动程序将其刚存储的内容的计算MD5与MongoDB的filemd5命令返回的MD5进行比较的位置。

此异常已记录在案,我可以正常处理它,但是:

我的问题是为什么会发生这种情况(显然存在二进制不匹配,但有没有导致这种情况更频繁发生的事情)?

我能理解它是否发生在系统故障期间,但似乎是随机发生的(尽管不是经常发生)。

1 个答案:

答案 0 :(得分:2)

最后有一些时间来正确地研究这个,这就是我发现的东西!

默认情况下,mongo java驱动程序为mongodb的任何和所有写入设置所谓的NONE / UNACKNOWLEDGED写入问题。这意味着写入mongodb是一个非常异步的过程。驱动程序说“嘿,当你有机会时存储所有这些东西”并且mongo最终存储它,但是响应立即返回给应用程序,因此它继续执行该线程。

Mongo的java驱动程序的GridFSFile对象有一个名为validate的方法,可以在存储文件后调用。此方法使用由java驱动程序在内存中计算的MD5,因为流被分成块并发送到mongodb,然后将其与mongo的filemd5命令的结果进行比较。当mongo发出filemd5请求时,它会获取提供的id,并根据存在的各种二进制数组块的内容计算MD5,这些块包含对提供的id的引用(它们共同代表存储在GridFS中的单个实体)。

至于是什么导致我看到驱动程序的计算MD5和mongo返回的MD5之间频繁不匹配,基本上默认的写入关注为NONE,它将控制返回给应用程序并执行validate / {紧接着{1}}命令,mongo然后处理它的内容的当前状态。在将所有内容实际写入内存之前,MongoDB正在计算MD的MD5是可能的(事实上似乎也是如此),因此它有时会返回一个糟糕的MD5。

此外,这与调试详细信息中的内容一致 - 一旦发生异常,我添加了日志记录以查询存储的文件并读取其内容,此时它始终具有正确的内容和正确的MD5。

解决方案是mongo驱动程序与GridFS的交互必须使用至少为ACKNOWLEDGED的写入问题,这意味着在返回应用程序之前,已写入的数据至少由mongo保留在内存中。我已经为我的测试手动设置了它,并在app启动时为GridFS集合启用它,因为它尚未作为spring-data中的配置选项公开。另外值得注意的是,新的mongo-3.x java驱动程序有一个默认的写入问题ACKNOWLEDGED,所以一旦我使用它,我理论上可以删除额外的bootstrapping。

至于为什么在本地从未见过这种情况,我的机器可能具有mongo所需的可用内存和处理能力,以便足够快地存储内容,以便在filemd5被调用时,一切都已经存在所以MD5返回是正确的。运行大量并发测试的构建代理负载明显较重,资源可能更有限,因此在执行filemd5命令之前,mongodb并不总是完成存储内容。

至于验证这确实是固定的,我之前看到过3-4个测试(大约2000个)因为这个问题而在每次构建时都失败了,我现在已经在构建代理上运行了15套完整的测试而且没有见过它。

我用来纠正这个的实际代码:

validate