MongoDB 드라이버의 SDAM 하트비트는 백그라운드에서 주기적으로 replica set 토폴로지를 추적한다
·수정 1회
요약
- SDAM(Server Discovery And Monitoring)은 MongoDB 드라이버가 replica set의 각 노드에 주기적으로
hello핑(하트비트)을 보내 토폴로지(누가 primary인지, 어느 노드가 살아있는지)를 추적하는 메커니즘이다. - 애플리케이션이 직접 쿼리를 안 보내도 드라이버가
heartbeatFrequencyMS(기본 10초)마다 알아서 노드 상태를 갱신한다. - 하트비트는 노드 IP를
getaddrinfo로 해석해야 하므로, DNS 해석이 느려지는 환경(예: libuv 스레드풀 starvation)에서 간헐적 연결 실패의 숨은 트리거가 된다.
본문
왜 필요한가
MongoDB는 단일 서버가 아니라 replica set(primary 1 + secondary N)으로 구성되는 게 일반적이다. 드라이버는 항상 다음을 알고 있어야 정상 동작한다:
- 누가 primary인지 (쓰기는 primary로만)
- 어느 노드가 살아있는지 / 죽었는지
- failover로 primary가 바뀌었는지, 노드가 추가/제거됐는지
이 상태를 유지하려고 드라이버가 각 노드에 주기적으로 핑을 날리는 게 SDAM, 그 핑 하나하나가 하트비트(heartbeat) 다.
동작
- 드라이버가 각 노드에
hello명령(과거isMaster)을 보냄 - 기본 주기:
heartbeatFrequencyMS = 10000(10초) - 응답으로 "나 secondary고 살아있어, primary는 누구야" 같은 토폴로지 정보를 받아 내부 상태 갱신
- 하트비트가 실패하면 해당 노드를 unknown으로 표시하고, 그 노드의 커넥션 풀을 비움 →
MongoPoolClearedError
핵심: 백그라운드 + DNS 의존
- 하트비트는 애플리케이션 코드와 무관하게 백그라운드에서 자동으로 돈다. 테스트/요청이 직접 그 노드를 안 건드려도 10초마다 발생.
- 노드에 핑을 보내려면 먼저 호스트네임을 IP로 해석해야 한다 → Node에서는
dns.lookup(getaddrinfo) 경로 → libuv 스레드풀(기본 4개) 위에서 실행.
트러블슈팅 사례 — 통합 테스트 간헐 getaddrinfo ENOTFOUND
증상: 통합 테스트 557개 중 1~2개가 랜덤하게 MongoNetworkError: getaddrinfo ENOTFOUND <atlas-node-host> → MongoPoolClearedError로 실패. 매번 실패하는 테스트가 바뀜.
원인이 아니었던 것 (실측으로 배제):
- DNS 서버 과부하 ❌ —
dns.lookup5,000회 + 동시 400개 burst에도 0 실패 - jest 워커 수 ❌ —
--runInBand(완전 직렬)로도 발생
진짜 원인:
- 테스트의 bcrypt/pbkdf2/fs 등 블로킹 작업이 libuv 스레드풀 4개 슬롯을 점유
- 그 사이 SDAM 하트비트의
getaddrinfo가 큐에 밀려 드라이버 timeout 초과 (스레드풀 포화 시 DNS lookup이 최대 ~5초까지 지연되는 것 확인) - →
getaddrinfo ENOTFOUND로 표출 + 해당 노드 pool clear → 진행 중이던 쿼리 실패
즉 SDAM 하트비트가 DNS 해석을 필요로 한다는 점이, 스레드풀이 막힌 타이밍과 겹쳐 랜덤 실패를 만든 것. 실패 테스트가 매번 바뀐 이유도 "특정 테스트의 버그"가 아니라 "백그라운드 하트비트가 우연히 겹친 테스트가 희생됨"이기 때문.
해결: UV_THREADPOOL_SIZE=64로 키우니 getaddrinfo가 큐에 안 밀려 557/557 통과, ENOTFOUND 0건.
UV_THREADPOOL_SIZE=64 pnpm test:integration
교훈
- "특정 DB 노드 해석 실패"가 코드/네트워크 무관하게 간헐 발생하면, 애플리케이션 쿼리가 아니라 **드라이버의 백그라운드 하트비트(SDAM)**를 의심한다.
- Node에서
getaddrinfo기반 작업은 libuv 스레드풀을 공유하므로, CPU 바운드 블로킹 작업(해싱 등)이 많은 워크로드에서 DNS 해석이 starvation에 걸릴 수 있다.
관련 노트
- 서비스 디스커버리는 동적 환경에서 서비스 인스턴스의 네트워크 위치를 등록, 제거, 조회하는 메커니즘이다.
- mongodb에서 ttl index 동작
- database replication 종류
- connection pool에서 connection 순환 속도을 고려하지 않으면 조용히 서비스 성능이 악화된다.