如何获取MongoDB每个块的数据大小

最近发现MongoDB分片集群的流量不太均衡,研究之后发现根本原因在于数据分布不均衡。虽然数据分布均衡不等于流量均衡,但还是应该尽量使得数据分布在不同shard之间基本均衡。三个shard的数据分布大概这样:

Shard Data Size
mongo-0 10.55 GB
mongo-1 25.76 GB
mongo-2 10.04 GB

mongo-1这个分片的数据大小显著高于其他分片,而三个分片的chunk数目是基本一致的,所以需要分析不同分片上的chunk大小分布。

坏消息是并没有直接获取每个chunk数据大小的API。虽然chunk的基本信息存储在config.chunks表中,但这个表并没有data size类似的字段。假设有一个cxx collection,使用Uuid作为片键,查看config.chunks表,它的某一个chunk的信息长这样:

{
    "_id": {
        "$oid": "603348a8b74404eea898cc25"
    },
    "lastmod": {
        "$timestamp": {
            "t": 0,
            "i": 773
        }
    },
    "lastmodEpoch": {
        "$oid": "5ff83e4ba85a6bd465831542"
    },
    "ns": "cxx",
    "min": {
        "Uuid": "044B96CA34334FBE860D47BD63339B8E"
    },
    "max": {
        "Uuid": "0494E87F8ED34B0E9ECF6BE5363BBD3C"
    },
    "shard": "mongo-2",
    "history": [{
            "validAfter": {
                "$timestamp": {
                    "t": 6261,
                    "i": 1632930119
                }
            },
            "shard": "mongo-2"
        }
    ]
}

好消息是这个信息包括了一个chunk中所含数据的min/max key。因此,我们可以通过 dataSize API 来间接获取chunk数据大小:

{
   dataSize: <string>,
   keyPattern: <document>,
   min: <document>,
   max: <document>,
   estimate: <boolean>
}

原理也很简单,就是使用dataSize API计算在此chunk中的所有文档的大小总和。就上面的chunk的例子,可以在mongo shell中使用如下命令获取它的实际大小(注意指定命令执行的最大超时时间maxTimeMS):

db.runCommand({ dataSize: "cxx", keyPattern: { "Uuid": 1 }, min: { "Uuid": "044B96CA34334FBE860D47BD63339B8E" }, max: { "Uuid": "0494E87F8ED34B0E9ECF6BE5363BBD3C" }, maxTimeMS:1000 })

为了分析某个collection的所有chunk的数据大小分布,可以通过遍历config.chunks表中的所有chunk并逐个获取它的数据大小来完成。最终的脚本如下(按需修改nsUuid等字段):

var ns = "";
db.getSiblingDB("config").chunks.find({ns : ns}).forEach(function(chunk) {
  chunkSize = db.runCommand({ dataSize: ns, keyPattern: { "Uuid": 1 }, min: { "Uuid": chunk.min.Uuid }, max: { "Uuid": chunk.max.Uuid }, maxTimeMS:1000 })
  print(chunk.shard + "  " + chunk.min.Uuid + ": " + tojson(chunkSize.size/1024/1024) + "MB")
  })

示例输出如下:

mongo-0  00020DFCE1B64BE28098133E09F0DFF9: 27.868586540222168MB
mongo-0  020FC0A3F7DC456D8CA48787A22BFEF5: 0.03055095672607422MB
mongo-1  02109DCC630C4EB68D890BB1C664C732: 2.049802780151367MB
mongo-1  02394113C1FF4C33BB067299D00F2A57: 0.17893218994140625MB
mongo-0  023CB90536CB4D9A83E88BC362CDA80A: 5.774362564086914MB
mongo-0  02AD2533642349398B6B7518914C87E7: 8.088775634765625MB
mongo-1  03463C80D8844550A3F1F259345807DA: 3.041494369506836MB
mongo-0  037F4D692AE34A3FB7F4B5A3205121C2: 1.5527820587158203MB
mongo-1  039C5810056F4205B1FC476A67F003BF: 6.535520553588867MB
mongo-2  04197554460047ADBD5B62B35F4956B6: 2.715306282043457MB
...