[MongoDB] chunk 관리

DataBase 2024. 7. 4. 17:24

 

 

 

MongoDB 7.0 기준

 

chunk migration 기준이 chunk count에서 data size 차이로 변경되었으므로, 사실상 chunk count나 jumbo chunk는 의미가 없긴 함...

 

Sharding 상태 확인

// mongosh로 접속해서 sh.status() 실행
// https://www.mongodb.com/docs/manual/reference/method/sh.status

// 매개변수는 verbose. 기본값은 false이며 chunk 수가 20개 이상일 경우 다 보여주지 않음.
// 다 보고 싶다면 sh.status(true)로 실행하면 됨. active mongoses에 대한 정보도 더 자세히 보여줌.
// 하지만 chunk가 너무 많으면 이렇게 해도 다 보여주지 않음.

// 출력되는 데이터에 대한 자세한 설명은 아래 페이지 참조
// https://www.mongodb.com/docs/manual/reference/method/sh.status/#output-fields

 

 

 

Migration Thresholds

https://www.mongodb.com/docs/manual/core/sharding-balancer-administration/#std-label-sharding-migration-thresholds

/*

collection의 dataSize가 shard간에 range size의 3배 이상 차이가 나면 balancer가 구동되어야 한다고 판단함.
range size의 기본값은 128MB, 그러므로 shard같 dataSize가 384MB 이상 차이가 나면 migration이 일어남.

balanced 여부를 알아보기 가장 편한 명령어는 sh.balancerCollectionStatus(<namespace>)
https://www.mongodb.com/docs/manual/reference/method/sh.balancerCollectionStatus/#mongodb-method-sh.balancerCollectionStatus

*/

// 실행 예시
sh.balancerCollectionStatus('DB_NAME.COLLECTION_NAME')

// imbalanced이므로 migration thresholds를 넘어 migration이 필요한 상태
// 자세한 내용은 다음 문서 참조
// https://www.mongodb.com/docs/manual/reference/command/balancerCollectionStatus/#std-label-cmd-balancer-CollectionStatus-output
{
  chunkSize: 128,
  balancerCompliant: false,
  firstComplianceViolation: 'chunksImbalance',
  ok: 1,
  '$clusterTime': {
    clusterTime: Timestamp({ t: 1719818567, i: 5 }),
    signature: {
      hash: Binary.createFromBase64('RyYg+SSngFNblyMwtgVgrkCw3pg=', 0),
      keyId: Long('7348622497232715799')
    }
  },
  operationTime: Timestamp({ t: 1719818566, i: 4 })
}

 

 

migration이 불가능한 제약사항도 있는데,

chunk 자체의 데이터 사이즈가 range size를 넘어선 jumbo chunk 외에도,

range의 document 수가 너무 많으면 migration이 실패함.

range의 document 수가 설정된 range size(기본값: 128MB)를 평균 document size(db.collections.stats().avgObjSize)로 나눈 수 x 2 보다 많으면 migration이 일어나지 않음.

https://www.mongodb.com/docs/manual/reference/limits/#mongodb-limit-Maximum-Number-of-Documents-Per-Range-to-Migrate

 

 

그리고 balancer 설정 중 attemptToBalanceJumboChunks를 true로 하면 jumbo chunk도 migration 할 수 있으나,

정상적인 관리를 위해 해당 chunk를 수동으로 split 하거나 shard key를 추가/변경해야 하는게 좋음.

https://www.mongodb.com/docs/manual/tutorial/manage-sharded-cluster-balancer/#std-label-balance-chunks-that-exceed-size-limit

 

 

 

 

 

Chunk 상태 확인

// mongosh 접속 상태에서

config = db.getSiblingDB('config')

// 우선 컬렉션의 uuid를 알아내야 함
myCol = config.collections.findOne({ _id: 'DB_NAME.COLLECTION_NAME' })
uuid = myCol.uuid;

// 이제 uuid 정보로 chunk를 열람할 수 있음

// 특정 컬렉션의 전체 chunk 수
config.chunks.countDocuments({ uuid: uuid });

// 특정 컬렉션의 chunk 중 특정 shard에 존재하는 chunk 수
config.chunks.countDocuments({ 
    uuid: uuid,  
    shard: 'SHARD_NAME'
});


// 특정 chunk의 dataSize
chunk = config.chunks.findOne({
    uuid: uuid,
    shard: 'SHARD_NAME'
})
myKey = myCol.key
myDB = db.getSiblingDB('DB_NAME')
dataSize = myDB.runCommand({
    dataSize: 'DB_NAME.COLLECTION_NAME',
    keyPattern: myKey,
    min: chunk.min,
    max: chunk.max
})

 

 

위의 정보를 바탕으로 응용하여 여러가지 정보를 열람할 수 있음.

아래처럼 함수로 만들어서 ~/.mongoshrc.js에 등록해놓으면 mongosh에서 언제든 함수호출을 통해 편하고 빠르게 확인 가능.

/**
 * 특정 namespace의 shard별 chunk 수 출력
 */
function getChunkCount(ns=null)
{
    if (!ns) {
        print('ns를 입력해주세요.')
        return;
    }
    
    const config = db.getSiblingDB('config');
    const col = config.collections.findOne({ _id: ns });
    if (!col) {
        print(`존재하지 않는 namespace입니다: ${ns}`);
        return;
    }
    
    config.shards.find().sort({ _id: 1 }).forEach((shard)=>{
        const chunkCount = config.chunks.countDocuments({
            uuid: col.uuid,
            shard: shard._id
        });
        
        print(`${shard._id} = ${chunkCount}`);
    });
}

// 위 함수를 호출하면 각 shard별 ns별 chunk count 확인 가능
getChunkCount('DB_NAME.COLLECTION_NAME');
shard_001 = 224
shard_002 = 220
...
shard_XXX = 227



/**
 * 특정 namespace의 chunk중 지정한 dataSize 이상되는 크기의 chunk 정보 출력
 */
function getJumboChunk(ns, sizeMB=128, shard='')
{
    if (!ns) {
        print('ns를 입력해주세요.');
        return;
    }
    
    const config = db.getSiblingDB('config');
    const col = config.collections.findOne({ _id: ns });
    if (!col) {
        print(`존재하지 않는 namespace입니다: ${ns}`);
        return;
    }
    
    const myDB = db.getSiblingDB(ns.split('.')[0]);
    
    const q = {
        uuid: col.uuid
    };
    if (shard !== '') {
        q['shard'] = shard;
    }
    
    const size = sizeMB * 1024 * 1024;
    
    const jumboChunkList = [];
    
    config.chunks.find(q).forEach((chunk)=>{
        const dataSize = {
            dataSize: ns,
            keyPattern: col.key,
            min: chunk.min,
            max: chunk.max
        };
        
        if (dataSize.size > size) {
            jumboChunkList.push({
                shard: chunk.shard,
                size: dataSize.size,
                sizeMB: `${(dataSize.size / 1024 / 1024).toFixed(1)}`,
                count: dataSize.numObjects,
                min: chunk.min,
                max: chunk.max
            });
        }
    });
    
    jumboChunkList.sort((a,b)=>{
        return b.size - a.size;
    });
    
    jumboChunkList.forEach((chunk)=>{
        print(`[${chunk.shard}] sizeMB=${chunk.sizeMB}, count=${chunk.count}, min=${JSON.stringify(chunk.min)}, max=${JSON.stringify(chunk.max)}`);
    });
}

// 위 함수를 호출하면 기준값을 초과하는 jumbo chunk를 알아낼 수 있음
getJumboChunk('DB_NAME.COLLECTION_NAME', 256);
[shard_003] sizeMB=524.1 MB, count=115382, min={id:'aaa', no:1}, max={id:'acd', no:1324}

 

 

 

 

 

chunk split

balancer에 모든걸 맡겨 자동으로 split/migration이 동작하도록 하는게 정상이지만,

초반에 대용량 데이터를 밀어넣거나 이런저런 이유 등으로 jumbo chunk가 만들어졌고,

이런저런 이유로 balancer가 해당 chunk를 제대로 split 하지 못하고 있다고 간주되면 수동으로 chunk split을 해야함.

https://www.mongodb.com/docs/manual/tutorial/split-chunks-in-sharded-cluster/

 

chunk split을 하기 위해 sh.splitFind()와 sh.splitAt()을 이용할 수 있음.

// sh.splitFind()
// https://www.mongodb.com/docs/manual/reference/method/sh.splitFind/
// query에 shard key를 지정하여 해당 shard key가 포함되어 있는 chunk를 절반으로 나눔

// sh.splitAt()
// https://www.mongodb.com/docs/manual/reference/method/sh.splitAt/
// query에 shard key를 지정하여 chunk를 해당 shard key 지점을 기준으로 나눔

 

 

 

 

 

 

'DataBase' 카테고리의 다른 글

[MongoDB] BSON  (0) 2024.07.19
[MongoDB] chunk/range size 변경  (0) 2024.07.11
[MongoDB] oplog 분석  (0) 2024.05.29
[MongoDB] mongosh에서 JavaScript 사용하기  (0) 2024.02.27
[MongoDB] mongosh editor  (0) 2024.02.20
Posted by bloodguy
,