이전까지 shard key는 한 번 정하면 수정할 수 없었으나,
4.4 버전부터 refineCollectionShardKey를 통해 suffix를 붙이는 형태로 부분 수정이 가능해졌고,
5.0 버전부터 shard key를 완전히 변경하는 reshard가 가능해짐.
refineCollectionShardKey
v 4.4 부터 가능.
지정한 shard key의 cardinality가 부족해서 chunk가 제대로 나뉘지 않아 jumbo chunk가 생성되거나 할 때,
shard key의 뒷부분에 cardinality를 높여주는 필드를 하나 더 추가하는 방법.
// 만약 shard key가 이렇고
user_id: 1
// 여기에 order_id를 추가해서 shard key를 만들고 싶다면, 우선 해당 인덱스를 하나 만들고
db.COL_NAME.createIndex({user_id:1, order_id:1})
// refineCollectionShardKey 실행
db.adminCommand({
refineCollectinShardKey: 'DB_NAME.COL_NAME',
key: { user_id:1, order_id:1 }
})
// sh.status()로 확인해보면 shardKey 변경 확인가능
unique index인 경우라든지 신경써야 되는 부분들이 있으므로 공식문서 참조할 것.
https://www.mongodb.com/docs/manual/reference/command/refineCollectionShardKey/
Reshard
v 5.0 부터 가능
필수 확인 사항
다음의 조건을 만족하지 않는다면 reshard가 힘들 수 있음.
- reshard 되는 동안 2초 간의 write block을 견딜 수 있어야 함
- 어지간하면 이정도는 괜찮지 않을까...
- 아래 하드웨어 조건을 만족해야 함
- 최소 컬렉션 사이즈의 1.2배의 여유공간
- ex) 컬렉션 사이즈가 1T 라면 1.2T의 여유공간 필요
- I/O가 50% 이하
- CPU load가 80% 이하
- 최소 컬렉션 사이즈의 1.2배의 여유공간
- 다음 둘 중 하나를 해줘야 함
- 어플리케이션의 query가 이전 샤드키와 새로 변경할 샤드키를 모두 포함하거나
- 어플리케이션을 중단하고
- 어플리케이션의 query가 새로운 샤드키를 포함하게 하기
- $currentOp를 통해 reshard가 완료될 때까지 대기한 다음
- 어플리케이션 재배포
- 만약 이전 샤드키와 새로 변경할 샤드키를 모두 포함하지 않거나 _id 를 포함하지 않는다면 다음 query들은 에러를 발생시킴
- deleteOne(), findAndModify(), findOneAndDelete(), findOneAndReplace(), findOneAndUpdate(), replaceOne()
- 최적의 성능을 위해 다른 query들도 새로운 샤드키를 포함하도록 변경하는 것을 권장
- 실행중인 인덱스 빌드가 없어야 함
- db.currentOp() 로 확인 가능
제한사항
- 한 번에 하나의 컬렉션만 reshard 가능
- writeConcernMajorityJournalDefault는 반드시 true
- unique index가 있는 컬렉션은 reshard 불가능
- unique index는 새로운 샤드키가 될 수 없음
- reshard 중 다음 명령어들은 사용할 수 없음
- collMod, convertToCapped, createIndexes, createIndex(), drop, drop(), dropIndexes, dropIndex(), renameCollection, renameCollection()
- addShard, removeShard, db.createCollection(), dropDatabase
- shard된 time series 컬렉션은 reshard 불가
reshard 과정
mongos에 접속해서 reshardCollection 실행
db.adminCommand({
reshardCollection: 'DB_NAME.COL_NAME',
key: SHARD_KEY
})
reshard 과정 모니터링
db.getSiblingDB('admin').aggregate([
{ $currentOp: { allUsers: true, localOps: false } },
{
$match: {
type: 'op',
'originatingCommand.reshardCollection': 'DB_NAME.COL_NAME'
}
}
])
// 그럼 아래와 같은 결과가 나옴
[
{
shard: SHARD_NAME,
type: 'op',
desc: 'ReshardingRecipientService 혹은 ReshardingDonorService 혹은 ReshardingCoordinatorService RESHARDING UUID',
op: 'command',
ns: 'DB_NAME.COL_NAME',
originatingCommand: {
reshardCollection: 'DB_NAME.COL_NAME',
key: SHARD_KEY,
unique: <boolean>,
collation: { locale: 'simple' }
},
// 경과시간
totalOperationTimeElapsedSecs: <number>,
// 예상 남은시간
remainingOperationTimeEstimatedSec: <number>,
...
},
...
]
reshard 완료
- reshard가 진행되다가 예상 남은시간이 2초 이하가 되면 MongoDB는 write를 block하고 reshard를 마무리 함
- reshard가 완료되면 ok: 1 반환
{
ok: 1,
'$clusterTime': {
clusterTime: <timestamp>,
signature: {
hash: Binary(Buffer.from("0000000000000000000000000000000000000000", "hex"), 0),
keyId: <number>
}
},
operationTime: <timestamp>
}
sh.status()로 reshard가 완료되었는지 확인.
reshard 중지는 아래 방법으로 가능.
// 다음 명령어로 실행 중인 reshard 중지 가능
db.adminCommand({
abortReshardCollection: 'DB_NAME.COL_NAME'
})
기타 신경써야 하는 부분들 있으므로 공식문서 참조할 것.
https://www.mongodb.com/docs/manual/core/sharding-reshard-a-collection
'DataBase' 카테고리의 다른 글
[MongoDB] Time Series Collection (0) | 2023.07.11 |
---|---|
[MongoDB] ChangeStream (0) | 2023.07.05 |
[MongoDB] 트랜잭션 (Transaction) (0) | 2023.06.01 |
[MongoDB] 인덱스 사용량 확인 (check index usage) (0) | 2023.05.30 |
[MongoDB] vm.max_map_count is too low warning 발생시 (0) | 2023.05.09 |