分片是随机分布在 MongoDB 中的机器上还是按顺序分布?

Chr*_*row 6 mongodb

分片是随机分布在 MongoDB 中的机器上还是按顺序分布?

例如,如果我有一个跨两台机器分片的 MongoDB 集群,并且我的分片键是一个人的名字,那么以“am”开头的名字会出现在第一台机器(或副本集)上,并且以“nz”开头的名字会出现第二台机器?

非常感谢!

Ada*_*m C 6

一般来说,不,它们不是按顺序分布的。但是,有一种方式可以在正常操作期间发生这种(或至少近似这种)分布。解释:

如果您在单个分片 (az) 上拥有所有数据,然后添加第二个分片,则平衡器将通过迁移块将数据重新分配到新分片。

平衡器选择要迁移的块的方式通常非常简单,它将选择具有最多块(例如“a”块)的分片上最低的可用范围,并将其移动到具有最少数量的分片大块。冲洗并重复,直到块平衡。

因此,如果您将所有数据放在一个分片上并添加第二个分片,则低范围块 (am) 都将从原始分片移动到新分片,您最终可以得到这种几乎有序的分布.

在您的示例中,您最终会得到一个奇怪的均匀分布的数据,并没有造成真正的伤害。但是,从性能角度来看,对于跨大部分数据的基于范围的查询可能存在问题。考虑一个按顺序遍历索引的查询 - 它一次只会访问一个分片(新分片,然后是旧分片),而不是使用两者的资源来更好地分配数据。

在其他情况下,这种行为会导致数据分布特别差。假设您有一个基于时间的分片键(由于各种原因不好,但仍然很常见)并且您定期删除旧数据。结合上面的场景,新的分片最终将没有数据(低范围,旧,块中的数据都将被删除)。请记住,就平衡而言,一个空块(无数据)与 60MB 块一样多(平衡器纯粹是查看每个分片上的块数,而不是其中的数据量)。

此外,如果您有 2 个分片开始然后插入数据,这一切都不会发生,因为拆分和迁移通常会更随机且分布更广。MongoDB 还将尝试移动最大块以帮助实现这种分布。

总而言之 - 如果您发现了这种类型的分布问题,您可以通过在自己周围移动块来采取措施来修复它。看一看moveChunk 命令(这通常是一个好主意,但不是必需的,在您执行此操作时关闭平衡器,否则您可能无法获得所需的锁)。

查看所有这些的最简单方法是运行sharding status 命令并传递true,即 的参数sh.status(true)。这将打印所有分片集合的详细信息,块所在的位置等。它从配置数据库中提取其信息并使用简单的 Map Reduce 来聚合信息。

有了这些信息,您还可以检查更改日志集合以确定已迁移的内容以及迁移的时间(这也将记录在您的主mongod日志中,但在繁忙的系统上可能难以解析)。

最后,我意识到这有点超出了这个答案的范围,但我已经编写了几个 Javascript 函数(您可以从 MongoDB shell 使用它们),可以让您确定给定集合的分片上的对象和数据分布,其他地方不容易获得的东西。希望你会发现它们很有用:)

请注意:这些功能可能需要大量运行,因此请在生产环境中谨慎使用。

第一个函数以 CSV 格式打印给定命名空间的块信息。它使用命令中的estimate选项datasize来使用计数(而不是扫描所有对象)来计算每个块的大小。删除estimate选项将给出一个更准确的结果(特别是如果你的文档大小而异),但如果数据集不是在RAM中,可以非常耗费资源。

AllChunkInfo = function(ns){
    var chunks = db.getSiblingDB("config").chunks.find({"ns" : ns}).sort({min:1}); //this will return all chunks for the ns ordered by min
    //some counters for overall stats at the end
    var totalChunks = 0;
    var totalSize = 0;
    var totalEmpty = 0;
    print("ChunkID,Shard,ChunkSize,ObjectsInChunk"); // header row
    // iterate over all the chunks, print out info for each 
    chunks.forEach( 
        function printChunkInfo(chunk) { 

        var db1 = db.getSiblingDB(chunk.ns.split(".")[0]); // get the database we will be running the command against later
        var key = db.getSiblingDB("config").collections.findOne({_id:chunk.ns}).key; // will need this for the dataSize call
        // dataSize returns the info we need on the data, but using the estimate option to use counts is less intensive
        var dataSizeResult = db1.runCommand({datasize:chunk.ns, keyPattern:key, min:chunk.min, max:chunk.max, estimate:true});
        // printjson(dataSizeResult); // uncomment to see how long it takes to run and status           print(chunk._id+","+chunk.shard+","+dataSizeResult.size+","+dataSizeResult.numObjects); 
        totalSize += dataSizeResult.size;
        totalChunks++;
        if (dataSizeResult.size == 0) { totalEmpty++ }; //count empty chunks for summary
        }
    )
    print("***********Summary Chunk Information***********");
    print("Total Chunks: "+totalChunks);
    print("Average Chunk Size (bytes): "+(totalSize/totalChunks));
    print("Empty Chunks: "+totalEmpty);
    print("Average Chunk Size (non-empty): "+(totalSize/(totalChunks-totalEmpty)));
}
Run Code Online (Sandbox Code Playgroud)

您可以在 a 中的任何分片命名空间上调用它mongos,如下所示:

mongos> AllChunkInfo("test.users");
ChunkID,Shard,ChunkSize,ObjectsInChunk
test.users-_id_MinKey,shard0000,0,0
test.users-_id_10000.0,shard0000,525420,26271
test.users-_id_36271.0,shard0001,1120640,56032
test.users-_id_92303.0,shard0001,153940,7697
***********Summary Chunk Information***********
Total Chunks: 4
Average Chunk Size (bytes): 450000
Empty Chunks: 1
Average Chunk Size (non-empty): 600000
Run Code Online (Sandbox Code Playgroud)

接下来让您再次使用估计找到特定块的信息。这在没有估计的情况下使用更安全,但仍应谨慎使用:

ChunkInfo = function(ns, id){
    var configDB = db.getSiblingDB("config");
    var db1 = db.getSiblingDB(ns.split(".")[0]);
    var key = configDB.collections.findOne({_id:ns}).key;
    var chunk = configDB.chunks.find({"_id" : id, }).limit(1).next();
    var dataSizeResult = db1.runCommand({datasize:chunk.ns, keyPattern:key, min:chunk.min, max:chunk.max, estimate:true});
    print("***********Chunk Information***********");
    printjson(chunk);
    print("Chunk Size: "+dataSizeResult.size)
    print("Objects in chunk: "+dataSizeResult.numObjects)
}
Run Code Online (Sandbox Code Playgroud)

示例输出:

mongos> ChunkInfo("test.users", "test.users-_id_10000.0")
***********Chunk Information***********
{
        "_id" : "test.users-_id_10000.0",
        "lastmod" : Timestamp(3000, 0),
        "lastmodEpoch" : ObjectId("518373f0a962406e4467b054"),
        "ns" : "test.users",
        "min" : {
                "_id" : 10000
        },
        "max" : {
                "_id" : 36271
        },
        "shard" : "shard0000"
}
Chunk Size: 525420
Objects in chunk: 26271
Run Code Online (Sandbox Code Playgroud)