갑자기 트래픽이 10배 증가했고, DB 커넥션 풀이 고갈되어 서비스가 느려진다면

Hermaeus Mora · · Devops

어떻게 대응할 것인가? 우리는 cnpg를 사용중이고, pg와 pg바운서를 사용하며, transactional 모드를 사용중이다(트랜잭션이 끝나면 즉시 커넥션 반환한다.

풀 고갈이 **"그냥 요청이 많아서"**인지, **"DB가 느려져서 커넥션을 오래 붙잡아서"**인지 구분하는 지표들입니다.

PgBouncer 쪽

SHOW POOLS: 지금 이 순간의 풀 상태

  • cl_active: 서버 커넥션을 할당받아 쿼리 중인 클라이언트 수
  • cl_waiting: 서버 커넥션이 없어 줄 서서 대기 중인 클라이언트 수. 0보다 크면 풀이 꽉 찼다는 뜻
  • sv_active: PG에 실제로 일하고 있는 커넥션 수. default_pool_size에 붙어 있으면 포화 상태
  • maxwait: 대기열에서 가장 오래 기다린 클라이언트의 대기 시간(초). 이 값이 곧 사용자가 느끼는 추가 지연

SHOW STATS: 누적 통계와 평균

  • avg_xact_time: 트랜잭션 하나가 서버 커넥션을 붙잡고 있는 평균 시간(μs)
  • avg_wait_time: 클라이언트가 커넥션을 받기까지 기다린 평균 시간

핵심은 avg_xact_time입니다. 풀 처리량은 대략 pool_size ÷ avg_xact_time입니다.

  • 평소와 같다면: DB는 정상이고 순수하게 요청량이 많은 것. 풀 증설이 효과가 있습니다.
  • 평소보다 늘었다면: DB가 느려져 커넥션 회전이 막힌 것. 풀을 늘리면 오히려 악화됩니다.

CNPG Pooler는 exporter로 cnpg_pgbouncer_pools_cl_waiting, cnpg_pgbouncer_stats_avg_xact_time 같은 메트릭을 노출하니 Grafana로 평소 값과 비교하면 편합니다.

PG 쪽

CPU와 IO: 노드나 파드의 CPU 사용률, 디스크 IOPS와 latency를 봅니다. CPU가 100%에 가깝거나 IO wait가 높으면 DB 자체가 병목입니다.

pg_stat_activity: 백엔드 하나하나가 지금 뭘 하는지 보여줍니다.

SELECT state, wait_event_type, wait_event, count(*)
FROM pg_stat_activity
WHERE backend_type = 'client backend'
GROUP BY 1,2,3 ORDER BY 4 DESC;
  • wait_event_type = Lock: 행이나 테이블 락 경합. 커넥션을 늘리면 경합이 더 심해집니다.
  • wait_event_type = IO: 디스크 대기. 캐시 미스나 풀스캔을 의심해 볼 수 있습니다.
  • wait_event가 NULL이고 state = active: CPU를 쓰며 실제 실행 중인 상태

idle in transaction: 트랜잭션을 열어둔 채 아무것도 안 하는 세션입니다. transaction 모드에서도 이 상태로는 커넥션이 반환되지 않아서 풀을 그냥 점유합니다. 앱이 트랜잭션 안에서 외부 API를 호출하는 경우가 대표적입니다.

SELECT pid, now() - xact_start AS dur, query
FROM pg_stat_activity
WHERE state = 'idle in transaction'
ORDER BY dur DESC;

슬로우 쿼리: 지금 오래 걸리고 있는 쿼리는 now() - query_start로 정렬해서 찾습니다. 누적으로 부하를 많이 주는 쿼리는 pg_stat_statements를 total_exec_time 순으로 보면 됩니다. 락을 잡고 있는 범인은 pg_blocking_pids(pid)로 추적합니다.

판단 요약

관찰해석대응
cl_waiting↑, avg_xact_time 그대로, DB CPU 여유순수 트래픽 증가풀 증설
avg_xact_time↑, CPU나 IO 포화DB 과부하부하 차단, 레플리카 분산, 캐시
wait_event Lock 다수락 경합블로커 확인, 필요시 kill
idle in transaction 다수앱이 커넥션을 붙잡고 있음timeout 설정, 앱 수정