2TB 컬렉션을 샤딩하고 24시간 이내에 모든 샤드에 데이터를 배포해야 합니까? 리샤딩을 활용하여 데이터 마이그레이션을 가속화하세요!
면책 조항: 저는 MongoDB 직원이지만 표현된 모든 의견과 관점은 제 자신의 것입니다.
이 게시물에서는 리샤딩을 사용하여 클러스터의 샤드 전체에 데이터를 빠르게 분산시키는 "리샤드-샤드"라는 기술을 다룹니다.
우리는 다음을 다룰 것입니다:
샤딩을 처음 접하거나 MongoDB가 수평 확장성을 제공하는 방법에 대해 다시 알고 싶다면 다음을 확인하세요.
컬렉션이 다중 샤드 클러스터에서 처음으로 샤딩되면 밸런서는 최근 샤딩된 컬렉션을 보관하는 샤드에서 클러스터의 다른 샤드로 데이터를 마이그레이션하여 샤드 전체에 컬렉션을 균등하게 배포하기 시작합니다. 밸런서가 데이터를 마이그레이션할 때 샤드는 마이그레이션이 필요한 컬렉션 수에 관계없이 한 번에 하나의 마이그레이션에만 참여할 수 있습니다. 즉, 3개의 샤드 클러스터에서는 한 번에 2개의 샤드만 데이터를 마이그레이션할 수 있습니다. 리샤딩은 내부 실행 차이로 인해 동일한 제한 사항을 공유하지 않습니다.
리샤딩은 모든 데이터를 다시 쓰기 때문에 클러스터의 모든 샤드에 걸쳐 데이터를 병렬로 쓸 수 있어 처리량이 증가하고 밸런서가 수행할 수 있는 작업에 비해 샤드 간에 데이터를 마이그레이션하는 시간이 크게 단축됩니다. 리샤딩은 기존 컬렉션을 애플리케이션에서 활용할 수 있도록 유지하면서 각 샤드의 백그라운드에 새 샤드 키를 사용하여 새 컬렉션을 구축합니다. 모든 문서가 새 컬렉션에 복제되면 컷오버가 발생합니다. 이전 분할 키가 있는 기존 컬렉션은 리샤딩 작업으로 구축된 새 컬렉션을 위해 삭제됩니다.
첫째, 훨씬 빠릅니다! 리샤딩을 활용하여 고객은 22.5시간 만에 3.5TB 컬렉션을 4개의 샤드에 샤딩하고 배포할 수 있었습니다. 밸런서의 기본 청크 마이그레이션 방법을 그대로 사용했다면 동일한 프로세스가 30일이 걸렸을 것입니다.
둘째, 작업량에 최소한의 영향을 미칩니다! 밸런서는 데이터를 마이그레이션한 후 다음과 같은 정리 작업을 수행해야 합니다.
셋째, 디스크 공간을 자동으로 회수합니다! 이전 컬렉션을 삭제하면 다음과 같은 작업을 실행하지 않고도 컬렉션에서 사용할 수 있는 저장 공간이 확보됩니다.
예를 들어, 고객은 가장 큰 컬렉션의 리샤딩 작업이 완료되기 전에 shard0에서 거의 2.8TB를 소비했습니다.
리샤딩이 완료되면 바로 1.9TB의 저장공간이 반환되었습니다! 2.7TB의 스토리지를 사용하던 것에서 873GB의 스토리지를 소비하게 되었습니다.
답변: 처음에 샤드 수에 관계없이 모든 크기의 컬렉션을 샤딩하는 경우입니다.
밸런싱이 더 빠를 수 있는 일부 시나리오(예: 100GB 미만)가 있지만 여전히 범위 삭제 및 압축 또는 초기 동기화를 통한 스토리지 회수를 고려해야 합니다. 따라서 용량이 있는 경우 샤딩하려는 컬렉션의 크기에 관계없이 다시 샤딩하여 샤딩하는 것을 권장합니다.
다음과 같은 경우에는 재샤딩-샤딩 전략을 사용하면 안 됩니다.
기본적으로 리샤딩되는 컬렉션에 대해 쓰기를 차단할 수 있는 기간은 2초이며, 차단 기간을 수정할 수 있는 구성 가능한 매개 변수가 있습니다.
위에 나열된 시나리오의 경우 컬렉션을 샤딩하고 밸런서가 데이터를 마이그레이션하도록 하는 전통적인 방법을 사용합니다.
MongoDB 5.0 이상을 실행하는 MongoDB 클러스터
컬렉션에 적합한 샤드 키를 선택해야 합니다.
임시 분할 키와 원하는 분할 키를 모두 지원하는 데 필요한 인덱스를 구축합니다.
또한 데이터 마이그레이션 속도를 높이기 위해 리샤딩을 사용하게 되므로 다음 사항을 숙지하시기 바랍니다.
리샤딩 작업을 성공적으로 실행하려면 클러스터에 다음이 있어야 합니다.
리샤딩을 실행하기 위한 스토리지, I/O, CPU 요구 사항을 클러스터가 충족하지 못하는 Atlas를 사용하는 고객은 일시적으로 쉽게
리샤딩-샤딩 작업을 실행하는 두 가지 매우 간단한 단계가 있습니다.
먼저 임시 분할 키로 분할해야 하는 이유는 무엇이며, 이로 인해 내 애플리케이션이 손상되지 않습니까?
설명하자!
현재 리샤딩은 동일한 샤드 키로의 리샤딩을 지원하지 않습니다. 이미 원하는 상태에 있으므로 "no-op"로 성공합니다. 이 제한 사항을 해결하려면 샤드 재샤딩 기술을 사용하려면 원하는 샤드 키와 다른 임시 샤드 키로 의도적으로 샤딩해야 합니다. 범위 샤딩과 해시 샤딩 모두에 대한 MongoDB의 지원으로 인해 임시 샤드 키는 컬렉션에 대해 선택한 원하는 샤드 키에서 아주 약간 수정될 수 있습니다.
임시 분할 키는 분할 키 필드 중 하나에 대해서만 다른 분할 전략을 선택해야 합니다. 쿼리에 분할 키를 포함해야 하는 updateOne(), updateMany(), deleteOne() 등과 같은 특정 쿼리에 대한 제한으로 인해 다른 분할 전략을 사용하게 됩니다. MongoDB는 클러스터의 샤드에 데이터를 배포하는 방법을 결정하는 방법으로 만 파티셔닝 전략을 사용하며 문서의 값을 변경하지 않습니다. 이는 애플리케이션이 두 분할 전략 모두와 함께 분할 키가 필요한 updateOne
또는 다른 쿼리를 활용할 수 있음을 의미합니다.
예를 들어, 컬렉션에 대해 선택한 원하는 분할 키가 다음과 같은 경우:
{"_id": "hashed"}
컬렉션에 처음 사용할 임시 샤드 키는 다음과 같아야 합니다.
{"_id": 1}
복합 분할 키의 경우 임시 분할 키에 원하는 분할 키의 접두사를 사용할 수 있습니다. 예를 들어, 컬렉션에 대해 선택한 원하는 분할 키가 다음과 같은 경우:
{ launch_vehicle: 1, payload: 1}
임시 샤드 키는 다음과 같아야 합니다.
{ launch_vehicle: 1}
샤딩 간 전략에서는 임시 샤드 키를 사용한 컬렉션의 초기 샤딩이 완료된 후 장기적으로 사용할 샤드 키로 거의 즉시 재샤딩이 필요합니다. 이는 리샤딩 작업이 실행되는 동안 하나의 샤드에 데이터의 99% 이상을 유지하여 브로드캐스트 쿼리의 영향을 크게 줄입니다.
리샤딩 작업이 수행되는 동안 임시 및 원하는 분할 키에 대한 인덱스를 모두 구축하게 되므로 원하는 분할 키를 활용하는 쿼리는 컬렉션이 일시적으로 분할되는 동안 원하는 분할 키에 대한 인덱스를 활용할 수 있으므로 성능이 뛰어납니다. 임시 샤드 키로.
두 번째 단계는 리샤딩 작동 방식의 부작용을 활용하는 경우를 제외하고 일반적인 리샤딩 작업을 실행하는 것입니다.
리샤딩에는 4가지 주요 단계가 있습니다.
초기화 - 리샤딩 중인 컬렉션이 샘플링되고 새 샤드 키를 기반으로 새로운 데이터 배포가 결정됩니다.
인덱스 - 리샤딩 작업은 새 샤드 키를 기반으로 모든 샤드에 새로운 빈 임시 샤딩 컬렉션을 생성하고 기존 컬렉션을 지원하는 비샤드 키 인덱스를 포함하는 인덱스를 구축합니다.
복제, 따라잡기 및 적용 - 문서는 새 분할 키에 따라 분할된 데이터베이스에 복제되고, 리샤딩 작업이 실행되는 동안 문서에 대한 모든 수정 사항이 적용됩니다.
커밋 - 임시 컬렉션의 이름이 변경되고 리샤딩되는 컬렉션을 대신하며 현재 이전 컬렉션은 삭제됩니다.
위의 단계를 검토한 후 빠른 데이터 이동, 작업이 완료되면 샤드 전체에 균등하게 분산되는 샤드 컬렉션, 한 번에 여유 저장 공간의 이점을 얻을 수 있는 방법을 확인할 수 있습니다.
재샤딩 작업이 완료되면 임시 분할 키 인덱스 삭제, 안정적인 상태 요구 사항에 맞게 클러스터 및/또는 스토리지 축소 등의 정리 작업을 수행할 수 있습니다.
항공편이 지연될 가능성이 있는 경우 고객에게 알릴 수 있도록 상업용 항공기를 추적하는 애플리케이션을 작업 중이라고 가정해 보겠습니다. 애플리케이션의 쿼리 패턴을 연구하고 좋은 분할 키에 기여하는 속성을 검토했습니다.
컬렉션에 대해 선택한 샤드 키는 다음과 같습니다.
{ airline: 1, flight_number: 1, date: "hashed" }
샤드 키가 결정되면 샤드 재샤딩 작업을 실행하기 위한 전제 조건 확인을 시작할 수 있습니다. 먼저 임시 분할 키를 생성합니다. 이전에 설명한 대로 임시 분할 키가 원하는 분할 키의 아주 약간 수정된 버전이기를 원합니다.
따라서 선택한 임시 샤드 키는 다음과 같습니다.
{ airline: 1, flight_number: 1 }
다음으로 임시 분할 키와 최종 분할 키를 모두 지원하는 인덱스를 구축합니다.
db.collection.createIndex()
또는 db.collection.createIndexes()
통해 Mongo 쉘을 사용하여 인덱스를 생성할 수 있습니다.
원하는 분할 키는 복합 분할 키이므로 db.collection.createIndexes()
통해 하나의 인덱스만 생성하면 됩니다.
db.flight_tracker.createIndex( { "airline": 1, "flight_number": 1, date: "hashed" } )
인덱스 빌드는 다음 명령을 통해 mongo 쉘을 사용하여 모니터링할 수 있습니다.
db.adminCommand({ currentOp: true, $or: [ { op: "command", "command.createIndexes": { $exists: true } }, { op: "none", "msg" : /^Index Build/ } ] })
MongoDB 클러스터가 Atlas에 배포된 경우 Atlas UI를 사용하여 클러스터에 사용 가능한 충분한 여유 스토리지와 리샤딩 작업을 수행하는 데 필요한 CPU 및 I/O 헤드룸이 있음을 알려주는 사용 가능한 측정항목을 쉽게 검토할 수 있습니다.
사용 가능한 스토리지 공간이나 I/O 헤드룸이 충분하지 않은 경우 스토리지를 확장할 수 있습니다. CPU 헤드룸이 부족한 경우 클러스터를 확장할 수 있습니다. 스토리지와 클러스터의 확장은 Atlas UI를 통해 쉽게 수행됩니다.
클러스터 구성에 액세스하는 것은 간단하며 그룹에 배포된 모든 클러스터를 표시하는 그룹 개요 화면에서 수행할 수 있습니다.
모든 전제 조건이 충족되면 리샤딩-샤딩 프로세스의 첫 번째 부분인 임시 샤드 키를 사용하여 컬렉션 샤딩을 시작할 수 있습니다.
그런 다음 Mongo 셸과 sh.shardCollection() 명령을 사용하여 컬렉션을 샤딩할 수 있습니다.
sh.shardCollection("main.flight_tracker", { airline: 1, flight_number: 1 })
sh.shardCollection()은 완료되면 문서를 반환하고, 작업이 성공하면 ok 필드의 값은 1이 됩니다.
{ collectionsharded: 'main.flight_tracker', ok: 1, '$clusterTime': { clusterTime: Timestamp({ t: 1684160896, i: 25 }), signature: { hash: Binary(Buffer.from("7cb424a56cacd56e47bf155bc036e4a4da4ad6b6", "hex"), 0), keyId: Long("7233411438331559942") } }, operationTime: Timestamp({ t: 1684160896, i: 21 }) }
컬렉션이 샤딩되면 하나의 청크가 클러스터의 모든 샤드로 마이그레이션될 때까지 기다립니다. mongo 쉘의 sh.status()를 통해 각 샤드에 청크가 있는지 확인할 수 있습니다.
sh.status()
컬렉션을 원하는 분할 키로 다시 분할하려면 mongo 셸에서 sh.reshardCollection()을 사용하세요.
sh.reshardCollection("main.flight_tracker", { airline: 1, flight_number: 1, date: "hashed" })
mongo 셸에서 sh.status() 명령을 실행하면 출력에 새 컬렉션의 이름 형식이 <db_name>.system.resharding.<UUID>
인 새 컬렉션이 표시됩니다. 리샤딩은 원하는 샤드키에 따라 데이터를 구축하고 배포하는 컬렉션입니다.
flight_tracker 컬렉션에 대한 리샤딩 작업 상태를 모니터링하려면 다음 명령을 사용할 수 있습니다.
db.getSiblingDB("admin").aggregate([ { $currentOp: { allUsers: true, localOps: false } }, { $match: { type: "op", "originatingCommand.reshardCollection": "main.flight_tracker" } } ])
명령 출력은 현재 리샤딩 작업이 실행 중인 단계와 남은OperationTimeEstimatedSecs 필드를 통해 예상 완료 시간을 알려줍니다. 재공유 예상 완료 시간은 비관적이며 재샤딩 작업에는 보고된 것보다 훨씬 짧은 시간이 소요됩니다.
리샤딩되는 컬렉션의 크기를 클러스터의 샤드 수로 나눈 만큼 각 샤드의 데이터 크기가 증가하면 리샤딩 작업이 거의 완료되어야 합니다. 예를 들어 4개 샤드에 걸쳐 1TB 컬렉션을 리샤딩하는 경우 각 샤드가 250GB를 기록하면 리샤딩 작업이 완료되어야 합니다(샤드에 삽입, 업데이트 또는 삭제되는 다른 데이터는 고려하지 않음).
클러스터가 Atlas에 배포된 경우 클러스터의 메트릭 탭을 사용하여 Atlas UI를 통해 리샤딩 작업의 진행 상황을 모니터링할 수도 있습니다.
MongoDB 6.0 이상을 실행하는 Atlas 클러스터의 경우 샤드 데이터 크기 표시 옵션을 사용한 다음 <db_name>.system.resharding.<UUID>
구문으로 컬렉션을 선택할 수 있습니다. 이 보기는 임시 컬렉션을 분리하고 새 컬렉션의 데이터 크기 증가만 표시합니다.
MongoDB 5.0을 실행하는 Atlas 클러스터의 경우 db 논리적 데이터 크기 표시 옵션을 사용할 수 있습니다. 이 보기는 컬렉션 수준 격리를 허용하지 않습니다.
리샤딩이 실행되는 동안 주로 모니터링해야 하는 클러스터의 세 가지 측정항목은 다음과 같습니다.
리샤딩이 클러스터에 부정적인 영향을 미칠까 봐 걱정 된다면 다음 명령을 통해 프로세스의 커밋 부분에 도달하기 전에 리샤딩 작업을 즉시 중단할 수 있습니다.
sh.abortReshardCollection("main.flight_tracker")
리샤딩 작업이 완료되면 작업 성공 여부가 호출 클라이언트에 반환됩니다.
리샤딩은 장기 실행 작업이고 해당 Mongo 셸 세션을 닫았을 수 있으므로 세부 정보를 원할 경우 리샤딩 모니터링 집계를 사용하거나 __ sh.status() __를 사용하여 샤딩 작업이 아직 실행 중인지 확인할 수 있습니다. 컬렉션이 출력에 여전히 존재합니다. 리샤딩 집계가 아무것도 반환하지 않거나 sh.status() 출력에 더 이상 임시 컬렉션이 표시되지 않으면 리샤딩 작업이 종료된 것입니다.
db.collection.getShardDistribution
사용하여 작업이 성공했는지 확인할 수 있습니다.
db.flight_tracker.getShardDistribution()
리샤딩이 성공적으로 완료되면 샤드 전체에 걸쳐 분포가 동일한 출력이 표시됩니다.
MongoDB 6.0 이상의 경우 균일성은 샤드당 데이터 크기에 따라 결정되므로 db.collection.getShardDistribution 출력에서 각 샤드에 거의 동일한 양의 데이터가 표시되어야 합니다.
MongoDB 5.0의 경우 균등성은 샤드당 청크 수에 따라 결정되므로 db.collection.getShardDistribution 출력에서 각 샤드에 동일한 수의 청크가 표시되어야 합니다.
클러스터가 Atlas에 배포된 경우 메트릭 탭을 통해 Atlas UI를 사용하여 리샤딩 작업이 성공했는지 확인할 수 있습니다.
MongoDB 6.0 이상을 실행하는 Atlas 클러스터의 경우 샤드 데이터 크기 표시 옵션을 사용한 다음 리샤딩된 컬렉션을 선택할 수 있습니다. 샤드당 동일한 양의 데이터가 표시되어야 합니다.
MongoDB 5.0을 실행하는 Atlas 클러스터의 경우 청크 표시 옵션을 사용한 다음 리샤딩된 컬렉션을 선택할 수 있습니다. 클러스터의 모든 샤드에 거의 동일한 수의 청크가 표시되어야 합니다.
샤드 데이터 크기와 청크 수 모두에 대해 Atlas UI는 이름을 바꾸고 이전 이름을 삭제하기 전에 일시적으로 <db_name>.system.resharding.<UUID>
라는 컬렉션 이름 형식을 사용한 재샤딩으로 인해 관련 측정항목의 급격한 증가를 표시합니다. 이전 샤드 키를 사용하여 수집합니다.
리샤딩이 중단되면 db.collection.getShardDistribution
의 출력에는 컬렉션이 처음 샤딩된 샤드에 있는 대부분의 데이터가 표시될 가능성이 높습니다. 리샤딩으로 인한 중단은 드물며 리샤딩으로 인해 2초 이내에 수집 컷오버를 수행할 수 없기 때문에 발생할 가능성이 높습니다.
이 경우 클러스터의 트래픽이 적은 기간 동안 커밋을 시도하도록 리샤딩 시작 시간을 정하는 것이 좋습니다.
재샤딩 작업이 완료되면 임시 분할 키 인덱스 삭제, 안정적인 상태 요구 사항에 맞게 클러스터 및/또는 스토리지 축소 등의 정리 작업을 수행할 수 있습니다.
리샤드에서 샤딩으로 전환하는 데 시간이 얼마나 걸리나요?
이는 컬렉션 크기, 컬렉션에 대한 인덱스 수와 크기, 클러스터의 샤드 수에 따라 다르지만 48개의 샤드에 걸쳐 10개의 인덱스가 있는 4TB 컬렉션을 다시 샤딩하여 샤딩할 수 있다고 확신합니다. 시간 이하. 밸런서가 마이그레이션을 처리하도록 하는 데는 30일 이상이 소요됩니다.
밸런서가 데이터를 마이그레이션하도록 하는 것보다 리샤딩이 더 빠른 이유는 무엇입니까?
밸런서와 리샤딩이 데이터를 마이그레이션하는 방식의 내부가 다릅니다. 리샤딩은 청크 마이그레이션과 다른 순서로 문서를 읽으며 리샤딩은 이전 컬렉션을 삭제하는 것으로 끝나기 때문에 디스크 공간을 해제하기 위해 범위 삭제를 기다리지 않습니다.
고유성 제약 조건이 있고 해시 인덱스가 고유성 적용을 지원하지 않는 컬렉션에 대해 샤드 분할을 사용하고 싶습니다.
컬렉션에 고유성 제약 조건이 있는 경우 샤딩 간 재샤딩을 사용할 수 있지만 다른 접근 방식을 취해야 합니다. 분할 전략을 변경하는 대신 임시 분할 키에 추가 필드를 추가하면 원하는 분할 키로 다시 분할할 수 있는 기능이 잠금 해제됩니다. 예를 들어 원하는 분할 키가 다음과 같은 경우:
{ launch_vehicle: 1, payload: 1}
임시 샤드 키는 다음과 같습니다:
{ launch_vehicle: 1, payload: 1, launch_pad: 1}
쿼리에 전체 분할 키를 포함해야 하는 쿼리(예: updateOne(), updateMany(), deleteOne())에 대한 제한 사항에 유의하세요. 리샤딩 작업이 완료될 때까지 쿼리를 성공적으로 실행하려면 전체 분할 키가 필요한 모든 시나리오에서 애플리케이션에 임시 분할 키를 포함 해야 합니다 .
진행 중인 리샤딩 작업을 어떻게 모니터링합니까?
다음 명령을 실행하십시오.
db.getSiblingDB("admin").aggregate([ { $currentOp: { allUsers: true, localOps: false } }, { $match: { type: "op", "originatingCommand.reshardCollection": "<database>.<collection>" } } ])
진행 중인 리샤딩 작업을 중지하려면 어떻게 해야 합니까?
리샤딩 작업을 즉시 중단하는 다음 명령을 실행합니다.
sh.abortReshardCollection("<database>.<collection>")
리샤딩이 클러스터 성능에 영향을 미칠까 걱정됩니다.
이전에 설명한 리샤딩 요구 사항을 충족하는 경우 작업이 클러스터 성능에 영향을 미치지 않아야 합니다. 그러나 클러스터가 Atlas에 배포된 경우 샤딩 간 작업을 실행하는 동안 일시적으로 클러스터를 확장하고 작업이 완료된 후 클러스터를 다시 축소할 수 있습니다.
리샤딩 작업이 실행되는 동안 클러스터의 어떤 지표를 모니터링해야 합니까?
사용 가능한 저장 공간 - 샤드에 사용 가능한 저장 공간이 100GB 미만인 경우 재샤딩을 중단해야 합니다.
CPU 사용률 - 클러스터가 사용 가능한 모든 컴퓨팅 리소스를 소비하는 경우 리소스 경합이 발생할 수 있으며 리샤딩을 중단해야 합니다.
I/O 소비 - 클러스터가 사용 가능한 IOPS를 모두 소비하는 경우 리소스 경합이 발생할 수 있으므로 리샤딩을 중단해야 합니다.
임시 컬렉션이 모든 샤드에 균등하게 분산되어 있는 것 같습니다. 리샤딩이 완료되지 않는 이유는 무엇입니까?
Pexels에서 발견된 panumas nikhomkhai 의 헤드라인 사진.