SSG.COM 의 장보기 지원금 소멸 알림 배치가 수십만 건을 병렬 발송하다 간헐적으로 "Connection is not available, request timed out"으로 실패한 문제를, Spring Batch 의 DB 커넥션 점유 구조를 손봐 해결한 사례를 다룬다. 발송 API 가 느린 게 아니라, 발송 응답을 기다리는 동안 DB 커넥션을 계속 붙잡는 chunk 구조가 진짜 원인이었다.
핵심 포인트- 대량 알림을 병렬 처리하자 여러 chunk 가 동시에 발송 API 응답을 기다리며 커넥션 풀을 고갈시켜 배치가 실패했다.
- 병목은 발송 API 속도가 아니라, chunk 가 메시지 발송 대기 구간에도 DB 커넥션을 점유하는 구조였다.
- Spring Batch 의 ResourcelessTransactionManager 로 chunk 트랜잭션이 DB 리소스를 직접 관리하지 않게 바꿨다.
- DB 사용 구간과 발송 대기 구간을 분리해, 발송을 기다리는 동안 커넥션을 점유하지 않도록 했다.
- 발송 API 자체는 그대로 두고 커넥션 점유 범위만 줄여 안정성을 확보했다.
상세 정리- 배경: 장보기 지원금 소멸 알림을 수십만 건 발송하는데, 단일 흐름이 느려 병렬 처리를 도입했더니 간헐적 배치 실패가 생겼다.
- 증상: "Connection is not available, request timed out"으로 DB 커넥션 타임아웃이 발생했다.
- 기존 구조: Spring Batch chunk(Reader→Processor→Writer)에서 DB 리소스 점유 → 메시지 생성 → 발송 API 호출·응답 대기까지 한 트랜잭션이 커넥션을 계속 붙잡았다.
- 원인: 대량 발송에 병렬 처리가 겹치며 여러 chunk 가 동시에 API 응답을 기다려 커넥션 풀 부담이 급증했다.
- 해결: ResourcelessTransactionManager 를 적용해 chunk 트랜잭션이 DB 리소스를 직접 관리하지 않게 하고, DB 사용 구간과 발송 대기 구간을 명확히 분리했다.
- 개선 흐름: DB 리소스 사용 후 커넥션을 반환하고, 그다음 메시지 생성·발송 대기는 커넥션을 비점유 상태로 진행한다.
- 효과: 커넥션 점유 시간이 줄어 풀 부담이 완화되고 병렬 처리 시 배치 실패가 감소했다.
왜 읽나Spring Batch 로 외부 API 호출이 포함된 대량 발송을 처리하는 백엔드 개발자에게, 커넥션 점유 범위를 줄여 풀 고갈을 막는 패턴 레퍼런스.