MongoDB를 sharding 해서 돌리면 각 shard별로 데이터를 chunk 단위로 관리하는데,

일반적으로는 알아서 잘 균등분배 해주지만 대용량을 미친 속도로 batchInsert 하거나 하다보면,

초거대 슈퍼메가 chunk가 생길 때가 있다.


그러든 아니든 chunk 단위별 사이즈를 체크하고 너무 큰 chunk는 나누는 법.





1. db.col.stats()

stats()를 해봤는데 shards 데이터를 보고, count, size가 균등분배 되었는지 확인.

만약 shards 데이터의 각 shard별로 count나 size가 균등분배 되어 있지 않고 차이가 심하다면 직접 chunk를 나눌 필요가 있다.



2. chunk size 

MongoDB 명령어인 dataSize를 이용하여 각 chunk 별 사이즈 확인하기

<?PHP

$m = new MongoClient(CONNECTION_STRING);

$db = $m->DB_NAME;


// config.chunks collection에 우리가 원하는 chunk meta data가 들어 있음.

$config_chunks = $m->config->chunks;

// chunk 사이즈를 알고자 하는 collection의 name space 지정

$ns = 'DB_NAME.COLLECTION_NAME';

$q = array('ns' => $ns);


$c = $config_chunks->find($q);

foreach ($c as $v) {

    // chunk별 사이즈 알아내기

    $cmd = array(

        'dataSize' => $ns,

        'keyPattern' => SHARD_KEY,

        'min' => $v['min'],

        'max' => $v['max']

    );

    $r = $db->command($cmd);


    // shard 이름

    $shard = $v['shard'];

    // 해당 chunk의 최소키

    $min_key = json_encode($v['min']);

    // 해당 chunk의 최대키

    $max_key = json_encode($v['max']);

    // 해당 chunk의 data size

    $chunk_size = $r['size'];

    // 해당 chunk에 들어있는 object 수

    $chunk_count = $r['count'];

    // dataSize 명령어 실행완료 시간 (millis)

    $cmd_time = $r['millis'];


    printf("[%s] %s ---> %s\tSIZE=%d, COUNT=%d (%.3f)\n", $shard, $min_key, $max_key, $chunk_size, $chunk_count, $cmd_time);

}




3. chunk split

위와 같은 형태의 스크립트를 실행하면 chunk들의 사이즈가 주루룩 나오는데,

잘 살펴보고 혼자만 사이즈나 object count가 많은 용납할 수 없는 chunk가 나오면 분리하자.

분리할 땐 mongos 로 접속하여 sh.splitFind() 명령어를 이용한다.

sh.splitFind(NAMESPACE, QUERY) 명령어는 NAMESPACE에서 QUERY에 해당하는 chunk를 절반으로 나눈다.

QUERY는 나누고자 하는 chunk의 min ~ max 사이에 있는 아무거나 지정될 수 있으면 된다.


// chunk size list가 있고 shard key가 id-date 형태이고 아래와 같은 chunk size 리스트가 나온다면

bloodguy_20140101   ~ cooltohate_20140201 size=1000000

cooltohate_20140201 ~ drum004_20140101    size=  500000

drum004_20140101    ~ effect1324_20140201  size=  500000


// bloodguy_20140101 ~ cooltohate_20140201 chunk가 다른 chunk들에 비해 2배의 크기이므로 절반으로 나누고자 한다.

// 해당 컬렉션에서 min ~ max 사이에 있는 아무거나 하나 가져온 다음,

db.COLLECTIION.findOne({id:{$gt:'bloodguy', $lt:'cooltohate'}})

--> {id:'bloodguyz', date:20140102, name:'백충덕'} // 뭐 이런게 하나 나왔다 치자.


// 아래처럼 명령어를 실행하면 저 chunk 는 절반으로 나뉜다.

sh.splitFind('DB_NAME.COLLECTION', {id:'bloodguyz'})


// chunk 만 나눠 놓으면 나머지는 balancer가 알아서 해준다.

// balancer가 shard간 chunk를 이동시키는 threshold는 아래와 같다.

// chunk가 20개 이하라면 shard간 chunk수가 2개 이상 차이가 날 경우 balancer 동작

// chunk가 21개에서 80개 사이라면 shard간 chunk수가 4개 이상 차이가 날 경우 balancer 동작

// chunk가 80개보다 많으면 shard간 chunk수가 8개 이상 차이가 날 경우 balancer 동작




MongoDB가 균등분배 잘해줄거라고 찰떡같이 믿고 있다가 shard 하나만 초거대 chunk를 만드는 배신을 당했다.

무조건 믿지 말고 직접 확인하자.



[참조]

dataSize: http://docs.mongodb.org/manual/reference/command/dataSize/

sh.splitFind : http://docs.mongodb.org/manual/reference/method/sh.splitFind/

sharded collection balancing : http://docs.mongodb.org/manual/core/sharding-balancing/





Posted by bloodguy
,