MongoDB 복제 지연 문제 해결: 원인과 해결 방법
MongoDB 복제 세트에서 복제 지연을 진단하고 해결하는 방법을 알아보세요. 이 가이드는 높은 쓰기 부하, 하드웨어 병목 현상, 네트워크 문제 등 일반적인 원인을 다룹니다. `rs.printReplicationInfo()`를 사용한 실용적인 모니터링 기술과 데이터 동기화를 유지하여 모든 데이터베이스 노드에서 고가용성과 읽기 일관성을 보장하는 실용적인 솔루션을 알아보세요.
MongoDB 복제 지연 문제 해결: 원인과 해결 방법
MongoDB 복제 지연은 대개 사소한 운영상의 불편으로 시작됩니다. 차트가 오르기 시작합니다. 세컨더리가 15초, 그다음 2분씩 뒤처집니다. 누군가 읽기가 오래된 데이터인지 묻습니다. 다른 누군가는 노드를 재시작하자고 제안합니다. 그렇게 하기 전에, 속도를 늦추고 복제의 어떤 부분이 뒤처지고 있는지 파악하세요.
MongoDB 세컨더리는 프라이머리의 oplog에서 작업을 복사하여 로컬에 적용합니다. 복제 지연은 세컨더리가 프라이머리만큼 최근에 작업을 적용하지 않았음을 의미합니다. 이는 세컨더리 읽기, 세컨더리에서 가져온 백업, 분석 작업 및 장애 조치에 영향을 미칠 수 있습니다. 또한 더 큰 위험을 숨길 수 있습니다. 세컨더리가 oplog 윈도우보다 더 뒤처지면 oplog에서 전혀 따라잡지 못할 수 있습니다.
가장 빠른 문제 해결 방법은 세 가지 질문에 답하는 것입니다.
- 모든 세컨더리가 지연되고 있습니까, 아니면 하나만 지연되고 있습니까?
- 지연이 일시적입니까, 안정적입니까, 아니면 증가하고 있습니까?
- 세컨더리가 여전히 oplog 윈도우 내에 있습니까?
그 답변에 따라 다음에 수행할 작업이 결정됩니다.
추측 없이 지연 측정
mongosh에서 시작하세요:
rs.status()
프라이머리를 찾고 optimeDate를 각 세컨더리의 optimeDate와 비교하세요. 또한 비정상적인 멤버, 하트비트 메시지, RECOVERING 또는 STARTUP2와 같은 상태에 갇힌 멤버를 찾으세요.
더 친숙한 요약을 보려면 다음을 실행하세요:
rs.printSecondaryReplicationInfo()
일부 오래된 자료에서는 rs.printSlaveReplicationInfo()를 사용합니다. 이전 시스템을 유지 관리하는 경우 여전히 해당 도우미를 볼 수 있습니다. 현대적인 표현은 "secondary"입니다.
그런 다음 oplog 윈도우를 확인하세요:
rs.printReplicationInfo()
oplog 윈도우는 현재 oplog에 보존된 기록의 양입니다. 세컨더리가 40분 뒤쳐져 있고 oplog 윈도우가 며칠이라면 문제 해결을 위한 여유가 있습니다. 세컨더리가 40분 뒤쳐져 있고 피크 트래픽 시간에 oplog 윈도우가 1시간이라면 재구축 상황에 가까운 것입니다.
단일 도구의 SecondsBehind 스타일 값에만 의존하지 마세요. 시계 차이, 지연된 멤버, 짧은 버스트로 인해 하나의 숫자가 오해를 불러일으킬 수 있습니다. 상태 출력을 쓰기 볼륨, 디스크 대기 시간, CPU 및 네트워크 처리량에 대한 모니터링 그래프와 비교하세요.
모든 세컨더리가 지연되는 경우
모든 세컨더리가 거의 동시에 뒤쳐질 때, 원인은 일반적으로 단일 세컨더리의 상위에 있습니다. 먼저 프라이머리의 쓰기 워크로드를 살펴보세요.
일반적인 트리거는 다음과 같습니다:
- 대량 가져오기 또는 백필.
- 대규모
updateMany또는deleteMany작업. - 백로그 기간 후 TTL 정리.
- 쓰기 볼륨을 변경한 애플리케이션 배포.
- 인덱스 빌드 또는 스키마 유지 관리.
- 많은 oplog 항목을 생성하는 소량 쓰기의 갑작스러운 증가.
지연이 시작된 동시에 무엇이 변경되었는지 물어보세요. 야간 작업이 시작될 때 정확히 시작되는 스파이크는 거의 MongoDB 미스터리가 아닙니다.
프라이머리에서 활성 작업을 검사하세요:
db.currentOp({ active: true })
일괄 작업을 찾은 경우 최대 속도로 완료하도록 두는 대신 제한하는 것을 고려하세요. 예를 들어, _id 범위로 문서를 처리하고, 배치 사이에 대기하고, 지연을 관찰하세요. 이는 30분 안에 완료하는 것보다 복제 세트를 정상 상태로 유지하는 것이 덜 중요한 정리 작업에 특히 유용합니다.
지속적인 쓰기 볼륨이 복제 세트가 처리할 수 있는 것보다 단순히 더 높다면 용량 또는 아키텍처 변경이 필요합니다. 더 나은 디스크, 더 많은 CPU, 다른 인스턴스 클래스, 쓰기 경로 최적화 또는 샤딩이 올바른 답일 수 있습니다. 읽기 설정을 변경해도 세트가 적용할 수 있는 것보다 더 많은 작업을 생성하는 프라이머리를 수정할 수 없습니다.
하나의 세컨더리만 지연되는 경우
하나의 지연된 세컨더리는 일반적으로 로컬 문제를 나타냅니다. 해당 호스트에 로그인하여 기본 사항을 확인하세요:
iostat -xz 1
vmstat 1
top
MongoDB 내부에서 다음을 사용하세요:
mongostat --host secondary.example.com:27017
mongotop --host secondary.example.com:27017
디스크는 일반적인 원인입니다. 프라이머리보다 느린 스토리지를 사용하는 세컨더리는 정상 트래픽 중에는 괜찮다가 버스트 중에 뒤쳐질 수 있습니다. 클라우드 볼륨은 처리량 또는 IOPS 한도에 도달할 수도 있습니다. 높은 사용률, 높은 대기 시간 및 큐잉을 찾으세요.
CPU는 워크로드에 많은 업데이트, 압축, 암호화 또는 동일한 멤버에 대한 많은 쿼리 트래픽이 포함될 때 중요합니다. 메모리 압력은 세컨더리가 쓰기를 적용하는 동안 핫 데이터와 인덱스를 캐시에 유지할 수 없을 때 중요합니다.
또한 호스트에서 실행 중인 다른 항목을 확인하세요. 백업, 바이러스 백신 검사, 파일 시스템 스냅샷, 로그 압축 및 보고 쿼리는 모두 복제와 경쟁할 수 있습니다. 지연된 노드가 모든 사람이 임시 분석을 실행하는 "안전한 장소"이기도 하다면 아마도 문제를 찾은 것입니다.
세컨더리 읽기로 인해 지연이 발생할 수 있음
세컨더리 읽기는 무료가 아닙니다. 복제에 필요한 동일한 캐시, CPU 및 디스크를 사용합니다. 대규모 컬렉션을 스캔하는 단일 집계는 사용량이 많은 기간 동안 세컨더리가 뒤쳐지기에 충분할 수 있습니다.
장기 실행 읽기를 찾으세요:
db.currentOp({ active: true })
애플리케이션이 세컨더리로 읽기를 보내는 경우 읽기 설정을 검토하세요. secondary는 지연된 멤버로 읽기를 강제할 수 있습니다. secondaryPreferred는 여전히 오래된 데이터를 반환할 수 있습니다. 자체 쓰기를 읽어야 하는 사용자 흐름의 경우 프라이머리를 사용하세요. 최종적으로 일관된 읽기의 경우 maxStalenessSeconds를 설정하여 드라이버가 너무 뒤쳐진 세컨더리를 피하도록 하세요.
보고 워크로드의 경우 숨겨진 세컨더리 또는 별도의 분석 파이프라인을 고려하세요. 숨겨진 멤버는 여전히 복제할 수 있지만 드라이버는 일반 읽기에 대해 이를 선택하지 않습니다. 따라서 적절한 크기로 조정하는 한 백업 또는 제어된 보고 작업에 더 나은 장소가 됩니다.
Oplog 크기는 복구 여유이며 속도 수정이 아님
너무 작은 oplog는 일반적으로 자체적으로 지연을 유발하지 않습니다. 지연을 위험하게 만듭니다. 세컨더리가 뒤쳐져 필요한 oplog 항목을 덮어쓰면 정상적으로 따라잡을 수 없습니다.
oplog 윈도우는 현실적인 중단 및 유지 관리 시나리오보다 길어야 합니다. 패치 중에 세컨더리가 6시간 동안 오프라인 상태가 될 수 있다면 4시간 oplog 윈도우로는 충분하지 않습니다. 분기별 가져오기가 몇 시간 안에 oplog를 소진한다면 해당 워크로드에 맞게 크기를 조정하거나 가져오기 실행 방식을 변경하세요.
지원되는 버전에서는 더 큰 oplog가 필요한 각 멤버에서 replSetResizeOplog로 크기를 조정하세요:
use admin
db.adminCommand({ replSetResizeOplog: 1, size: 20480 })
이 예제는 약 20GB를 요청합니다. 관리형 플랫폼에서는 관리형 구성 방법을 사용하세요. 신중하게 테스트된 복구 절차를 따르지 않는 한 oplog를 삭제하고 다시 생성하는 오래된 조언은 피하세요.
oplog를 늘린 후에는 기본 지연 문제를 계속 해결하세요. 더 큰 oplog는 더 많은 시간을 제공합니다. 디스크 포화, 네트워크 제한 또는 과도한 쓰기 버스트를 제거하지는 않습니다.
실제로 도움이 되는 네트워크 확인
네트워크 문제는 지연이 원격 세컨더리, 하나의 가용성 영역 또는 하나의 데이터 센터 경로에 영향을 미칠 때 더 가능성이 높습니다. 간단하게 시작하세요:
ping primary.example.com
traceroute primary.example.com
그런 다음 대기 시간 이상을 살펴보세요. 복제에는 안정적인 처리량이 필요합니다. 패킷 손실, 방화벽 검사, VPN 제한, 리전 간 대역폭 한도 또는 과부하된 네트워크 인터페이스는 ping이 허용 가능해 보일 때도 지연을 생성할 수 있습니다.
리전 간 멤버만 지연되는 경우 동일한 쓰기 부하에서 로컬 세컨더리와 비교하세요. 다른 토폴로지, 더 큰 링크 또는 원격 멤버가 최신 읽기보다는 재해 복구용이라는 더 명확한 기대가 필요할 수 있습니다.
데이터 및 인덱스 드리프트
복제 세트 멤버는 동일한 인덱스를 가져야 합니다. 그렇지 않으면 oplog 적용이 느려지거나 실패할 수 있습니다. 이는 일반적으로 수동 변경, 실패한 유지 관리 또는 일관성 없는 소스에서 복원된 멤버로 인해 발생합니다.
핫 컬렉션의 인덱스를 비교하세요:
db.orders.getIndexes()
프라이머리와 지연된 세컨더리에서 실행하세요. 정의가 다른 경우 의도적으로 드리프트를 수정하세요. 대규모 인덱스를 다시 빌드하면 더 많은 부하가 추가될 수 있으므로 신중하게 예약하거나 차이가 광범위한 경우 깨끗한 소스에서 멤버를 다시 빌드하세요.
데이터 발산은 더 심각합니다. 복제 오류에 누락된 레코드 또는 중복 키가 표시되면 지연이 더 이상 유일한 문제가 아닙니다. 오류를 검사하고, 데이터를 비교하고, 테이블 수준 복구, 재동기화 또는 전체 재구축 중 어떤 것이 가장 안전한 경로인지 결정해야 합니다.
재시작 및 초기 동기화에 신중해야 함
지연된 세컨더리를 재시작하는 것은 프로세스가 일시적인 문제 뒤에 멈춰 있는 경우 때때로 도움이 됩니다. 보편적인 해결책은 아닙니다. 멤버가 oplog 윈도우 가장자리에 가까우면 재시작으로 인해 복구 불가능한 상태로 빠져들기에 충분한 시간이 소요될 수 있습니다.
재시작하기 전에 다음을 확인하세요:
- 현재 지연.
- 현재 oplog 윈도우.
- 멤버가 동기화 중인지 여부.
- 다른 정상 세컨더리가 존재하는지 여부.
- 복제 세트가 멤버가 다운되는 것을 견딜 수 있는지 여부.
초기 동기화는 세컨더리가 따라잡을 수 없거나 데이터를 신뢰할 수 없을 때 깔끔한 해결책입니다. 또한 무겁습니다. 데이터를 복사하고, 인덱스를 빌드하고, 다른 멤버의 리소스를 소비합니다. 한 번에 하나의 멤버를 다시 빌드하고, 노드가 다시 빌드되는 동안 투표 구성이 여전히 안전한 선거를 지원하는지 확인하세요.
서둘러 수정하지 말아야 할 때
일부 지연은 제어된 작업 중에 예상됩니다. 계획된 백필을 실행 중이거나, 세컨더리를 복원 중이거나, 과거 데이터를 가져오는 중이라면 유용한 질문은 세컨더리가 허용 가능한 속도로 따라잡고 있는지 여부입니다. 20분 동안 상승했다가 꾸준히 떨어지는 지연 그래프는 개입이 필요하지 않을 수 있습니다. 매일 상승하고 기준선으로 돌아오지 않는 지연 그래프는 그렇습니다.
이 구분은 일부 수정이 파괴적일 수 있기 때문에 중요합니다. 일괄 작업을 종료하면 애플리케이션 데이터가 절반만 업데이트된 상태로 남을 수 있습니다. 세컨더리를 재시작하면 캐시 웜이 손실되어 따라잡기가 더 느려질 수 있습니다. 멤버를 다시 빌드하면 단순히 백로그를 적용하도록 두는 것보다 더 많은 네트워크와 디스크를 소비할 수 있습니다.
계획된 작업의 경우 작업이 시작되기 전에 지연 예산을 설정하세요. 예를 들어, 유지 관리 백필이 보고 세컨더리에서 최대 10분의 지연을 생성할 수 있지만 장애 조치 후보에서는 생성하지 않도록 결정할 수 있습니다. 작업이 실행되는 동안 지연, oplog 윈도우 및 쓰기 속도를 관찰하세요. 작업이 예산에 근접하면 일시 중지하거나 배치 크기를 줄이세요.
또한 사용자 대면 복제본을 유지 관리 복제본과 분리하는 것이 도움이 됩니다. 애플리케이션 읽기에 사용되는 세컨더리는 백업에 사용되는 숨겨진 멤버보다 더 엄격한 지연 허용 오차를 가져야 합니다. 모든 세컨더리가 다른 작업을 가지고 있다면 경고 임계값은 전체 세트에 대해 하나의 숫자를 사용하는 대신 해당 작업을 반영해야 합니다.
인시던트 중 기록할 사항
올바른 증거를 저장하면 사후에 복제 인시던트를 훨씬 쉽게 이해할 수 있습니다. 구성을 변경하기 전에 다음을 캡처하세요:
rs.status()
rs.conf()
rs.printReplicationInfo()
rs.printSecondaryReplicationInfo()
또한 프라이머리와 지연된 세컨더리에서 호스트 수준 메트릭(디스크 대기 시간, CPU, 메모리 및 네트워크 처리량)을 저장하세요. 일괄 작업 또는 배포가 실행 중인 경우 시작 시간과 명령 또는 릴리스 버전을 기록하세요.
이것은 그 자체로 서류 작업이 아닙니다. 타임라인이 없으면 다음 인시던트는 0부터 시작합니다. 타임라인이 있으면 지연이 항상 특정 내보내기, 백업 또는 정리 작업 이후에 발생한다는 것을 알 수 있습니다. 이는 막연한 데이터베이스 문제를 예약 가능한 용량 문제로 바꿉니다.
실용적인 수정 맵
증상을 사용하여 다음 이동을 선택하세요:
| 증상 | 가능한 영역 | 다음 조치 |
|---|---|---|
| 모든 세컨더리가 일괄 작업 중 지연됨 | 쓰기 버스트 | 작업 제한 또는 분할 |
| 하나의 세컨더리가 항상 지연됨 | 로컬 리소스 문제 | 디스크, CPU, 메모리 및 로컬 읽기 확인 |
| 원격 멤버에서만 지연 증가 | 네트워크/토폴로지 | 처리량, 패킷 손실 및 리전 간 설계 확인 |
| 지연이 oplog 윈도우에 가까움 | 복구 위험 | oplog 증가 및 지연 소스 감소 |
| 세컨더리가 오래된 읽기를 제공함 | 읽기 설정 | 최신 읽기를 위해 프라이머리 사용 또는 maxStalenessSeconds 설정 |
| 멤버가 다운타임 후 따라잡을 수 없음 | oplog 기록 누락 | 백업 또는 초기 동기화에서 재구축 |
좋은 MongoDB 복제 문제 해결은 대부분 훈련된 관찰입니다. 프라이머리가 너무 많은 작업을 생성하고 있는지, 세컨더리가 너무 느리게 적용하고 있는지, 아니면 둘 사이의 링크가 제한되어 있는지 찾으세요. 그런 다음 일반적인 재시작, 재동기화 또는 구성 조정을 적용하는 대신 실제로 복제를 제한하는 것을 변경하세요.