文档长度不等于缓冲区

Document length is not equal to buffer

我 运行 在尝试使用 PHP 脚本浏览我的 collection 中的所有文档时遇到了问题。 collection 有大约 500k 个文档。数据库是 运行ning Mongo 2.6.9,运行ning Ubuntu 14.04。我正在使用此语法搜索集合:

$mongo = new MongoClient("mongodb://192.168.2.2:27017,192.168.2.3:27017/products?replicaSet=preplset");
$products = $mongo->products->content;
$cursor = $products->find();
while($cursor->hasNext() !== false) {
    echo "some information";
}

我收到以下错误消息(堆栈转储):

object(MongoCursorException)#24 (8) {
    ["message":protected]=> string(61) "Document length (74 bytes) is not equal to buffer (219 bytes)"
    ["string":"Exception":private]=> string(0) ""
    ["code":protected]=> int(42)
    ["file":protected]=> string(41) "...script.php"
    ["line":protected]=> int(29)
    ["trace":"Exception":private]=>
    array(1) {
        [0]=> array(6) {
            ["file"]=> string(41) "...value.php"
            ["line"]=> int(29)
            ["function"]=> string(7) "getNext"
            ["class"]=> string(11) "MongoCursor"
            ["type"]=> string(2) "->"
            ["args"]=> array(0) {}
        }
    }
    ["previous":"Exception":private]=> NULL
    ["host":"MongoCursorException":private]=> NULL
}

长度改变了。我见过十几种不同的长度。每次我 运行 这个脚本,它都会通过不同百分比的 collection。有时它会在 4k 文档后抛出此异常,有时会在 180k 后抛出此异常。我确定我一直在对 collection 进行更改,它是一个不断更新的生产数据库

对于将来可能遇到此问题的任何人,我将 post 我确定的问题原因以及我采取的解决步骤。

首先,最后一次重启我的 mongodb 服务器解决了我的问题。如果您是 运行 功能复制集,这可能值得首先尝试(在我下面概述的所有工作之前)。

问题是由某人在我们的复制集的 PRIMARY 节点上创建索引而没有明确指示创建索引造成的 "in the background"(这是有问题的)。然后我使用 "background" 选项集创建了各种索引(不是问题的一部分)。当我开始收到此错误消息时,我删除了所有索引,但它们仍保留在内存中(甚至可能在 PRIMARY --unverified 上的文件锁定中)。

为了解决这个问题,我让每个成员(一个接一个)离线,然后让他们在另一个(随机)端口上线(这样他们就不会与集合通信):

sudo mongod --port 44444 --dbpath /path/to/mongodb/files/ #default is /data/db

(需要路径,因为我的位置不是默认位置)

一旦每个服务器都自行加载,我就删除了所有索引并仅重新创建了我真正想要的索引(然后重新索引以确保它们是干净的):

db.collection.dropIndexes() #this drops all indexes except _id index
db.collection.createIndex( { *indexfield*: 1 } ) #1 or -1 for ASC or DESC
db.collection.reIndex() #probably not necessary

然后我退出了mongodb服务,正常情况下重启,这样就又是副本集的一部分了。

这些步骤应该足以解决问题,但我发现每个节点(特别是 PRIMARY)的完全重启对于我的错误消息最终消失是必要的。这可能值得一开始尝试。