English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
서론
MongoDB(버전 3.2.9),sharded cluster는 데이터 집합을 여러 shard에 분산 저장하여 데이터베이스 성능을 수준 확장하는 방법입니다. 각 shard는 데이터 집합의 일부만 저장하며, MongoDB는 각 shard 간에 중복 데이터가 없도록 보장합니다. 모든 shard가 저장한 데이터의 합이 전체 데이터 집합이 됩니다. sharded cluster는 데이터 집합을 분산 저장하여 여러 shard에 부담을 분산시키며, 각 shard는 데이터 집합의 일부를 읽기/쓰기만 담당하므로, 각 shard의 시스템 자원을 최대한 활용하여 데이터베이스 시스템의 토큰륨을 높입니다.
데이터 집합은 데이터 블록(chunk)으로 분할되며, 각 데이터 블록은 여러 doc를 포함합니다. 데이터 블록은 분산 저장소에 저장되며, MongoDB는 데이터 블록이 shard에서 어떻게 배치되는지 추적합니다. 각 shard가 어떤 데이터 블록을 저장하는지, 이를 shard의 메타데이터라고 하며, config server의 데이터베이스 config에 저장됩니다. 일반적으로3모든 config server에서의 config 데이터베이스는 완전히 동일해야 합니다. mongos를 통해 직접 데이터베이스 config에 접근하여 shard의 메타데이터를 확인할 수 있습니다; mongo shell은 sh 보조 함수를 제공하여, shard 클러스터의 메타데이터 정보를 안전하게 확인할 수 있습니다.
모든 shard를 조회하면, collection이 현재 shard에서의 데이터 부분집합을 가져오지만, 전체 데이터 집합은 아닙니다. Application은 mongos에만 연결하고, 그에 대한 읽기/쓰기 작업을 수행하면, mongos가 자동으로 읽기/쓰기 요청을 해당 shard로 전달합니다. MongoDB는 mongos를 통해 shard의 하부 구현을 Application에 투명하게 제공하며, Application에서는 전체 데이터 집합에 접근하는 것처럼 보입니다.
주 분리쉽}}
분리된 클러스터에서 모든 콜렉션이 분포 저장되지 않습니다. 콜렉션을 분리시키기 위해 sh.shardCollection() 명령어를 명시적으로 사용한 경우에만, 해당 콜렉션이 여러 shard에 분포 저장됩니다. 비 분리쉽 콜렉션(un-sharded collection)의 데이터는 주 분리쉽(Primary shard)에만 저장되며, 기본적으로 주 분리쉽은 데이터베이스가 최초로 생성된 shard로, 비 분리쉽 콜렉션의 데이터를 저장하는 데 사용됩니다. 각 데이터베이스는 하나의 주 분리쉽을 가집니다.
분리된 클러스터의 각 데이터베이스는 모든 비 분리된 콜렉션을 저장하는 주 분리쉽을 가집니다.-그 데이터베이스에 대한 분리된 콜렉션. 각 데이터베이스는 자신의 주 분리쉽을 가집니다.
예를 들어, 분리된 클러스터는 세 개의 분리를 가지고 있습니다: shard1을 생성하면, 데이터베이스 blog는 Shard2을 생성하면, 데이터베이스 blog는 Shard3에서 분리된 shard1를 분리시키면, MongoDB는 자동으로 shard2을 생성하면, 데이터베이스 blog는 Shard3shard1에서 생성된 데이터베이스 blog는 구조가 동일합니다.
그림에서, Collection2의 주 분리쉽은 ShardA입니다.
movePrimary 명령어를 사용하여 데이터베이스의 기본 주 분리쉽을 변경하면, 비 분리쉽 콜렉션은 현재 쉽에서 새로운 주 분리쉽으로 이동합니다.
db.runCommand({ movePrimary : "test", to : "shard0001})
movePrimary 명령어를 사용하여 데이터베이스의 주 분리쉽을 변경한 후, config server의 구성 정보는 최신이지만, mongos 캐시의 구성 정보는 고장났습니다.MongoDB는 명령어를 제공합니다: flushRouterConfig로 mongos가 config server에서 최신 구성 정보를 가져와 mongos 캐시를 새로운 구성으로 업데이트합니다.
db.adminCommand({"flushRouterConfig":}1})
2. 스파인의 메타데이터
config 서버에 직접 가지 않고 스파인 클러스터의 메타데이터 정보를 확인하지 마세요. 이 데이터는 매우 중요하며, 안전한 방법은 mongos를 통해 config 데이터베이스에 연결하여 확인하거나 sh辅助 함수를 사용하는 것입니다。
sh辅助 함수를 사용하여 확인합니다
sh.status()
config 데이터베이스의 콜렉션에 연결됩니다
mongos> use config
1,shards 집합은 스파인 정보를 저장합니다
db.shards.find()
스파인의 데이터는 host에서 지정된 replica set 또는 standalone mongod에 저장됩니다。
{ "_id" : "shard_name", "host" : "replica_set_name"/host:port", "tag":[shard_tag1,shard_tag2] }
2,databases 집합은 스파인 클러스터에 있는 모든 데이터베이스의 정보를 저장합니다. 스파인 여부에 관계없이
db.databases.find()
데이터베이스에 sh.enableSharding(“db_name”)을 실행하면 partitioned 필드 값은 true이 됩니다;primary 필드는 데이터베이스의 주 스파인(primary shard)을 지정합니다。
{ "_id" : "test", "primary" : "rs0", "partitioned" : true }
3,collections 집합은 모든 이미 스파인된 콜렉션의 정보를 저장합니다. 비스파인된 콜렉션(un-sharded collections)
key는:스파인의 스키입니다
db.collections.find() { "_id" : "test.foo", "lastmodEpoch" : ObjectId("57dcd4899bd7f7111ec15f16") "lastmod" : ISODate("1970-02-19T17:02:47.296Z"), "dropped" : false, "key" : { "_id" : 1 }, "unique" : true }
4,chunks 집합은 데이터 블록 정보를 저장합니다.
ns:스파인의 집합,구조는:db_name.collection_name
min 과 max: 스키의 최소값과 최대값
shard:块所在的分片
db.chunks.find() { "_id" : "test.foo"-_id_MinKey", "lastmod" : Timestamp(1, 1), "lastmodEpoch" : ObjectId("57dcd4899bd7f7111ec15f16") "ns" : "test.foo", "min" : { "_id" : 1 }, "max" : { "_id" : 3087 }, "shard" : "rs0" }
5changelog 컬렉션은 분할 클러스터의 작업을 기록하며, chunk의 분할과 이동 작업, shard의 추가와 제거 작업을 포함합니다.
what 필드: 작업 유형을 나타냅니다. 예를 들어: multi-split은 chunk의 분할을 의미합니다.
"what" : "addShard", "what" : "shardCollection.start", "what" : "shardCollection.end", "what" : "multi",-split",
6tags는 shard의 tag와 대응하는 piece 키 범위를 기록합니다.
{ "_id" : { "ns" : "records.users", "min" : { "zipcode" : "10001} "ns" : "records.users", "min" : { "zipcode" : "10001} "max" : { "zipcode" : "10281} "tag" : "NYC" }
7settings 컬렉션은 밸런서 상태와 chunk 크기를 기록하고, 기본적인 chunk 크기는64MB.
{"_id" : "chunksize", "value" :} 64 } {"_id" : "balancer", "stopped" : false }
8locks 컬렉션은 분산 락(distributed lock)을 기록하고, 하나의 mongos 인스턴스만이 분할 클러스터에서 관리 작업을 수행할 수 있도록 보장합니다.
mongos가 balancer로 동작할 때, 분산 락을 가져오고 config.locks에 doc를 삽입합니다.
로크 컬렉션은 분산 락을 저장합니다. 이는 클러스터에서 동시에 하나의 mongos 인스턴스만 관리 작업을 수행할 수 있도록 보장합니다. 밸런서로 동작하는 mongos는 아래와 같은 문서를 로크 컬렉션에 삽입하여 락을 가져옵니다.
{ "_id" : "balancer" "process" : "example.net:40000:1350402818:16807", "state" : 2, "ts" : ObjectId("507daeedf40e1879df62e5f3") "when" : ISODate("2012-10-16T19:01:01.593Z"), "who" : "example.net:40000:1350402818:16807:Balancer:282475249", "why" : "doing balance round" }
3. 셰드 삭제
셰드를 삭제할 때는 해당 셰드에 있는 데이터가 다른 셰드로 이전되었는지 확인해야 합니다. 셰드된 셋의 경우 밸런서를 사용하여 데이터 블록을 이전하며, 비셰드 셋의 경우 셋의 메인 셰드를 변경해야 합니다.
1,이미 셰드된 셋의 데이터를 삭제
step1,밸런서가 켜져 있는 것을 보장
sh.setBalancerState(true);
step2,이미 셰드된 셋을 다른 셰드로 이전
use admin db.adminCommand({"removeShard":"shard_name"})
removeShard 명령어는 데이터 블록을 현재 셰드에서 다른 셰드로 이전시킵니다. 셰드에 데이터 블록이 많을 경우 이전 과정이 오랜 시간이 걸릴 수 있습니다.
step3,데이터 블록 이전 상태 확인
use admin db.runCommand( { removeShard: "shard_name" } )
removeShard 명령어를 사용하여 데이터 블록 이전 상태를 확인할 수 있으며, remaining 필드는 남은 데이터 블록의 수를 나타냅니다
{ "msg" : "draining ongoing", "state" : "ongoing", "remaining" : { "chunks" : 42, "dbs" : 1 }, "ok" : 1 }
step4,데이터 블록 이전 완료
use admin db.runCommand( { removeShard: "shard_name" } ) { "msg" : "removeshard completed successfully", "state" : "completed", "shard" : "shard_name", "ok" : 1 }
2분할되지 않은 데이터베이스를 삭제하려면
step1분할되지 않은 데이터베이스를 확인하려면
분할되지 않은 데이터베이스는 두 부분으로 나뉩니다:
1데이터베이스가 분할되지 않았습니다. 이 데이터는 sh.enableSharding(“db_name”)을 사용하지 않았으며, 데이터베이스 config에서 해당 데이터베이스의 partitioned 필드는 false입니다
2데이터베이스에 콜렉션이 분할되지 않았습니다. 즉, 현재 분할은 해당 콜렉션의 주 shard입니다
use config db.databases.find({$or:[{"partitioned":false},{"primary":"shard_name"}]})
partitioned=false인 데이터베이스는 모든 데이터가 현재 shard에 저장됩니다; partitioned=true, primary="shard_name"인 데이터베이스는 비분할(un-sharded collection이 해당 데이터베이스에 저장되어 있으면, 이러한 콜렉션의 주 shard를 변경해야 합니다.
step2주 데이터베이스의 shard를 변경합니다
db.runCommand( { movePrimary: "db_name", to: "new_shard" })
4. 분할 추가
데이터 세트의 일부를 저장하는 분할을 위해, 데이터의 고可用성을 보장하기 위해, Replica Set을 shard로 사용하는 것이 좋습니다. Replica Set에 포함된 멤버가 하나라도 있다면 그렇습니다. mongos에 연결하여 sh 도움 기능을 사용하여 분할을 추가합니다.
sh.addShard("replica_set_name/host:port)
standalone mongod를 shard로 사용하지 않는 것을 권장하지 않습니다.
sh.addShard("host:port")
5. 거대한 블록
일부 경우, chunk이 지속적으로 증가하여 chunk size의 제한을 초과하여 거대한 블록(jumbo chunk)이 되며, 거대한 블록이 생기는 이유는 chunk 내의 모든 doc이 동일한 shard 키(shard key)를 사용하기 때문입니다. 이 chunk이 지속적으로 증가하면, chunk의 분포가 불균형적이고 성능瓶颈이 될 수 있습니다.
chunk 이동 시, 제한이 있습니다: 각 chunk의 크기는2.5만 개의 doc, 또는1.3설정 값의 배수입니다. chunk size의 기본 설정 값은64MB, 초과된 chunk는 MongoDB에서 거대한 블록(jumbo chunk)으로 표시되며, MongoDB는 거대한 블록을 다른 shard에 이동할 수 없습니다.
MongoDB는 블록에 포함된 문서 수가 특정한 값을 초과하면 블록을 이동할 수 없습니다. 250000 documents 또는 1.3 configured chunk size를 average document size로 나눈 결과의 times
1特大 블록을 확인합니다
sh.status()를 사용하여特大 블록을 발견할 수 있으며,特大 블록의 뒤에는 jumbo 레이블이 있습니다.
{ "x" : 2 } -->> { "x" : 3 } on : shard-Timestamp(2, 2) jumbo
2特大 블록을 배포합니다
特大 블록은 분할되지 않으며, 균형기로 자동으로 배포되지 않으므로 수동으로 배포해야 합니다.
step1balancer를 종료합니다
sh.setBalancerState(false)}
step2chunk size의 설정 값을 증가시킵니다
MongoDB는 크기가 제한을 초과하는特大 블록을 이동하지 않기 때문에, 임시로 chunk size의 설정 값을 증가시켜特大 블록을 균형 있게 분산하도록 해야 합니다.
use config db.settings.save({"_id":"chunksize","value":"1024"})
step3特大 블록을 이동합니다
sh.moveChunk("db_name.collection_name",{sharded_filed:"value_in_chunk"},"new_shard_name")
step4balancer를 활성화합니다
sh.setBalancerState(true)
step5mongos의 설정 캐시를 새로운 것으로 업데이트합니다
mongos가 config server에서 설정 정보를 동기화하고 캐시를 새로운 것으로 업데이트하도록 강제합니다.
use admin db.adminCommand({ flushRouterConfig: 1 })
6. 균형기
balancer는 mongos로 변환됩니다. 즉, mongos는 쿼리를 해당 shard로 라우팅하는 것뿐만 아니라 데이터 블록의 균형을 책임집니다. 일반적으로 MongoDB는 자동으로 데이터 균형을 처리하며, config.settings를 통해 balancer 상태를 확인하거나 sh辅助함수를 통해 확인할 수 있습니다.
sh.getBalancerState()
true를 반환하면, balancer가 실행 중임을 나타내며, 데이터 균형을 자동으로 처리하며, sh辅助함수를 사용하여 balancer를 종료할 수 있습니다.
sh.setBalancerState(false)}
balancer는 즉시 실행 중인 블록 이동 작업을 중지할 수 없으며, mongos가 balancer로 변할 때 balancer lock을 요청하여 config.locks 컬렉션을 확인합니다.
use config db.locks.find({"_id":"balancer"}) --또는 sh.isBalancerRunning()
만약 state=2،이는 balancer가 활성 상태라는 의미입니다. state=0이면 balancer가 닫혔다는 의미입니다.
균형 과정은 실제로 데이터 블록을 하나의 shard에서 다른 shard로 이동시키거나, 큰 chunk을 작은 chunk으로 분할한 후 작은 chunk을 다른 shard로 이동시키는 것입니다. 블록 이동과 분할은 시스템의 IO 부하를 증가시키므로, 균형기를 활성화한 시간을 시스템의 비활성 시간에 제한하는 것이 좋습니다. balancer의 활성화 시간 창을 설정하여 balancer가 지정된 시간区间 내에서 데이터 블록의 분할과 이동 작업을 제한할 수 있습니다.
use config db.settings.update( {"_id":"balancer"}, "$set":{"activeWindow":{"start":"23:00","stop":"04:00"}}), true )
균형기를 분할하고 이동하는 대상은 chunk입니다. 균형기는 각 shard에서 chunk 수가 균형을 이루도록 보장하지만, 각 chunk에 포함된 doc 수는 반드시 균형을 이루지 않습니다. 일부 chunk에는 많은 doc이 포함되었을 수 있으며, 일부 chunk에는 거의 doc이 포함되지 않을 수도 있습니다. 따라서, 분할의 인덱스 키, 즉 키를 신중하게 선택해야 합니다. 하나의 필드가 대부분의 쿼리 요구를 충족하며 doc 수가 균형을 이루도록 도와주는 경우, 이 필드는 키의 최적 선택입니다.
결론
이 글의 전체 내용은 끝이며, 여러분의 학습이나 업무에 도움이 되길 바랍니다. 의문이 있으시면 댓글을 달아 주세요.