web-dev-qa-db-ja.com

シャードMongoDBクラスターでチャンクの分散(データとドキュメントの数)を決定する方法

適切なシャードキーを選択し、水平方向にスケーリングし、データを複数のシャードに分散した後、ドキュメント数とデータサイズの観点からデータのバランスがどれほど優れているかを判断する実際的な方法がないことがわかりました。 sh.status() コマンドは、チャンクがカウントでどのように分散されるかを通知しますが、それらのチャンクを構成するものは通知しません。

これらのことを推測する方法はたくさんありますが、それらにはすべてマイナス面があります。データベースサイズの計算方法のばらつきは、データベースで大幅な削除が行われた場合、統計がデータ分布を正確に反映していない可能性があることを意味します。各シャードにヒットするトラフィックを確認すると、いくつかの手掛かりが得られる可能性がありますが、それは、トラフィックが適切で予測可能である場合に限られます。

それでは、各チャンク内のドキュメントの分布、各チャンクの相対的なサイズ、および(もちろん)それらのチャンクが現在どこに存在するかをどのように決定しますか?

4
Adam C

現在、これを行う組み込みの方法はないため、小さな関数が必要です。この回答の目的で、私は これらの指示 に従って、最大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)));
}  

現時点ではかなり基本的ですが、それで十分です。私も 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

関数に渡される引数を説明するには:

最初の引数は調べる名前空間(文字列)で、2番目の引数(ブール値)は推定オプションを使用するかどうかです。本番環境ではestimate:trueを使用することをお勧めします。使用しない場合は、すべてのデータを調査する必要があります。つまり、メモリにデータを取り込む必要があり、コストが高くなります。

estimate:trueバージョンは無料ではありませんが(カウントと平均オブジェクトサイズを使用します)、大規模なデータセットでも実行することは少なくとも妥当です。オブジェクトサイズが一部のシャードで歪んでいて、平均サイズが代表的でない場合(これは一般的にかなりまれです)、推定バージョンも少しずれている可能性があります。

11
Adam C
db.collection.getShardDistribution()

それは私がこのようなことのために頻繁に使用するかなり良いコマンドです。合計チャンク、平均チャンクサイズ、ドキュメント数がすべてシャードごとに表示されます。上記の答えのように各チャンクのデータを提供しませんが、これは非常に迅速であり、探しているものの概要を提供します。

3
Landon