如何确定分片 MongoDB 集群中的块分布(数据和文档数量)?

Ada*_*m C 4 mongodb sharding

做了所有正确的事情 - 选择了一个合适的分片键,水平扩展,将我的数据分布在几个分片中,我发现我现在没有真正的方法来确定数据在文档计数和数据大小方面的平衡程度。该sh.status()命令将告诉我块是如何根据计数分布的,但不会告诉我这些块是由什么组成的。

有很多方法可以推断出这些东西——但它们都有一个缺点。数据库大小计算方式的变幻莫测意味着如果数据库中有大量删除,统计数据可能无法准确反映数据分布。如果我查看每个分片的流量,这可能会给我一些线索,但前提是我的流量良好且可预测。

那么,我如何确定每个块中文档的分布、每个块的相对大小以及(当然)这些块当前所在的位置?

Ada*_*m C 11

目前没有内置的方法可以做到这一点,所以需要一个小功能。出于此答案的目的,我按照这些说明创建了一个包含约 100 万个文档的 2 个分片集群。接下来我使用这个函数来检查这些文件:

AllChunkInfo = function(ns, est){
    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:est});
        // 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)

目前这是非常基本的,但它可以完成工作。我也在github 上添加了它,并可能在那里进一步扩展它。不过就目前而言,它会做需要的事情。在开始描述的测试数据集上,输出如下所示(为简洁起见,删除了一些数据):

mongos> AllChunkInfo("chunkTest.foo", true);
ChunkID,Shard,ChunkSize,ObjectsInChunk
chunkTest.foo-_id_MinKey,shard0000,0,0
chunkTest.foo-_id_0.0,shard0000,599592,10707
chunkTest.foo-_id_10707.0,shard0000,1147832,20497
chunkTest.foo-_id_31204.0,shard0000,771568,13778
chunkTest.foo-_id_44982.0,shard0000,771624,13779
// omitted some data for brevity
chunkTest.foo-_id_940816.0,shard0000,1134224,20254
chunkTest.foo-_id_961070.0,shard0000,1145032,20447
chunkTest.foo-_id_981517.0,shard0000,1035104,18484
***********Summary Chunk Information***********
Total Chunks: 41
Average Chunk Size (bytes): 1365855.024390244
Empty Chunks: 1
Average Chunk Size (non-empty): 1400001.4
Run Code Online (Sandbox Code Playgroud)

解释传递给函数的参数:

第一个参数是要检查的命名空间(一个字符串),第二个(一个布尔值)是是否使用估计选项。对于任何生产环境,建议使用estimate:true——如果不使用,则需要检查所有数据,这意味着将其拉入内存,这将是昂贵的。

虽然该estimate:true版本不是免费的(它使用计数和平均对象大小),但即使在大型数据集上运行也至少是合理的。如果对象大小在某些分片上倾斜,因此估计版本也可能会有些偏差,因此平均大小不具有代表性(这通常非常罕见)。