관리자 DB 풀에 쌓이던 좀비 연결 정리하기
목차
관리자 DB 연결이 계속 누수되던 문제를 발견하고 고정했다. globalThis에 고정된 커넥션 풀 인스턴스가 idle 타임아웃을 제때 회수하지 못하면서 발생한 메모리 누수였다.
싱글톤 풀의 숨은 위험성
DB 커넥션 풀을 globalThis에 attach해서 서버 런타임 동안 재사용하는 패턴은 흔하다. 인스턴스를 반복 생성하지 않아 효율적이고, 연결을 재사용해 오버헤드를 줄일 수 있기 때문이다. 하지만 이 방식은 생각보다 까다로운 부분이 있다.
특히 admin 전용 DB 세션을 관리할 때 문제가 컸다. 관리 작업(배치, 데이터 정정, 보고서 생성 등)은 불규칙한 간격으로 실행되고, 각 작업 후 연결을 명시적으로 반환해야 한다. 그런데 어느 순간부터 폴 내 유휴 연결이 계속 쌓이고만 있었다. 커넥션 객체는 메모리에 남아있는데, 실제 사용되지는 않는 "좀비" 상태였다.
문제의 근본 원인은 이랬다: globalThis에 고정된 풀 인스턴스가 idle timeout을 올바르게 발동하지 못했던 것이다. 일반적으로 커넥션 풀은 설정된 시간 동안 사용되지 않은 연결을 자동으로 정리해야 한다. 그런데 풀 인스턴스 자체가 메모리에 고착되어 있으니, 정리 로직이 제대로 작동해도 풀의 상태 관리가 꼬일 수 있었다.
// 이런 패턴에서 쌓인 유휴 연결이 정리 안 되는 상황
globalThis.adminDbPool = globalThis.adminDbPool || createPool({
// ... 설정
idleTimeoutMs: 30000 // 이 타임아웃이 작동하지 않음
})
풀 상태 초기화 + 타임아웃 정책 강화
해결 방법은 두 가지를 조합했다.
1. globalThis 풀 참조 재점검 — 풀이 확실히 한 번만 생성되고, 새 서버 워크플로우가 시작될 때마다 상태가 깨끗한지 검증하도록 했다. 구체적으로는 풀 인스턴스 생성 로직을 정리해서 stale connection이 이미 풀에 쌓여있는 상황을 방지했다.
2. idle 타임아웃 강제 회수 — idle timeout을 더 적극적으로 설정하고, 타임아웃 초과 연결을 동기적으로 정리하는 로직을 추가했다. 단순히 타임아웃 시간만 설정해서는 부족했고, 풀이 주기적으로 유휴 연결을 검사하고 닫도록 명시적으로 구현했다.
// src/lib/db.ts 개선 로직 (예시)
function getAdminPool() {
if (!globalThis.adminDbPool) {
globalThis.adminDbPool = createPool({
database: 'admin_db',
idleTimeoutMs: 30000,
// idle 연결을 주기적으로 정리하는 백그라운드 작업
maintenanceInterval: 10000
})
}
return globalThis.adminDbPool
}
이 변경으로 불필요한 연결이 메모리에 머물러 있지 않게 되었다.
팀장 관점: 언제 이런 버그를 조기에 잡을 수 있을까
내가 이번 건으로 배운 점은 모니터링의 중요성이다. 메모리 누수, 커넥션 누수 같은 문제는 기능 테스트만으로는 드러나지 않는다. 로그도 에러도 없고, 앱이 느려지다가 어느 순간 뻗는 식이다.
비슷한 상황을 미리 감지하려면:
- 커넥션 풀 메트릭 수집: 활성/유휴 연결 수, 대기 큐 길이, 타임아웃 발생 건수 등을 주기적으로 로깅
- globalThis 사용처 코드리뷰: 싱글톤 패턴을 쓸 때마다 "이 인스턴스의 생명주기는 어디까지인가", "상태 초기화는 누가 하는가" 확인
- 부하 테스트: 실제 운영 패턴을 모방한 스트레스 테스트에서 장시간 실행해 누수 여부 확인
팀원들과 리뷰할 때도 이런 포인트를 강조했다. "이 풀이 언제 정리되나요?" "타임아웃이 정말 작동하나요?" 같은 질문이 기술 부채를 조기에 걸러낸다.
닫으며
데이터베이스 연결 관리는 단순해 보이지만, 실제로는 메모리, 타이밍, 상태 일관성이 맞아떨어져야 한다. 특히 admin이나 백그라운드 작업 같은 비메인 경로의 DB 접근은 쉽게 간과되기 쉬운데, 이번 건은 그 함정을 명확히 보여줬다. 앞으로도 단순한 기능 동작뿐만 아니라 리소스 관리 측면의 건강성까지 함께 챙기려 한다.
🛒 이 글과 어울리는 추천 상품
*위 링크는 쿠팡파트너스 활동의 일환이며, 일정액의 수수료를 제공받을 수 있습니다.
댓글 0
첫 댓글 달아줘.