대량 배치 안정성을 높이기 위한 구조 개선: Part 1 - 시스템을 압박하기 시작한 배치
1편. 대량 배치 작업이 시스템을 압박하기 시작했을 때
들어가며
서비스가 성장하면서 데이터는 자연스럽게 누적된다. 문제는 “언제부터 기존 구조가 한계에 도달했는지”를 시스템이 아니라 사람이 먼저 체감한다는 점이다.
이번 글에서는 실행 시점마다 수십만 건 이상의 데이터를 처리해야 하는 배치 작업이 어떻게 시스템 전체의 안정성을 위협하게 되었는지, 그리고 왜 구조 개선이 불가피했는지를 다룬다.
우리가 마주한 배치 작업의 특성
해당 배치 작업은 다음과 같은 특징을 가지고 있었다.
- 실행 시점마다 80만 건 이상의 데이터 처리
- 특정 기준에 따라 기존 데이터 전체 삭제 후 신규 데이터 등록
- 하루에도 여러 번 실행될 수 있는 구조
- 실행 시간 동안 다른 시스템 기능에도 영향을 주는 고부하 작업
처음 설계 당시에는 데이터 규모가 크지 않았고, 단순한 구조가 오히려 유지보수에 유리하다고 판단했다.
그래서 초기 구조는 매우 직관적이었다.
한 번의 트랜잭션 안에서 전체 삭제 → 전체 등록
단일 트랜잭션 구조의 현실적인 문제
데이터가 수십만 건 단위로 증가하면서, 이 단순한 구조는 점점 위험한 선택이 되어갔다.
1. 장기 트랜잭션이 만드는 DB 부하
전체 데이터를 하나의 트랜잭션으로 묶다 보니,
- 트랜잭션 지속 시간이 수십 분 단위로 증가
- 해당 테이블에 대한 락 점유 시간이 비정상적으로 길어짐
- 다른 쿼리들이 대기 상태에 빠지는 현상 발생
특히 삭제 쿼리는 대량의 레코드를 대상으로 수행되면서 I/O 부하와 인덱스 정비 비용을 동시에 발생시켰다.
2. 실패 시 모든 작업이 무효가 되는 구조
배치 실행 중 단 하나의 예외라도 발생하면 상황은 더 심각해졌다.
- 이미 수십 분간 수행된 삭제·등록 작업이 전부 롤백
- 재실행 시 동일한 고부하 작업이 다시 반복
- 운영자는 “이번엔 끝날까?”를 지켜볼 수밖에 없는 상황
즉, 작업이 길어질수록 실패 비용도 기하급수적으로 증가하는 구조였다.
3. 운영 환경에서 드러난 체감 문제
운영 환경에서는 이런 문제들이 더 노골적으로 드러났다.
- 배치 실행 시간 동안 CPU·메모리 사용량 급증
- DB 커넥션 고갈로 인해 다른 서비스 API 응답 지연
- 배치 실패 시 재실행 여부를 수동으로 판단해야 하는 불안정한 운영
이 시점부터 문제는 더 이상 “성능”의 문제가 아니었다.
시스템 전체의 신뢰성과 운영 안정성을 위협하는 구조적 문제였다.
왜 단순한 구조는 더 이상 통하지 않았을까
초기 구조는 분명 합리적인 선택이었다.
- 코드가 단순했고
- 실패 시 롤백으로 정합성이 보장되며
- 구현과 이해가 쉬웠다
하지만 데이터 규모가 커진 이후에도 같은 구조를 유지하는 것은 환경 변화에 대한 대응 실패였다.
대규모 배치 환경에서는 다음 질문에 답해야 했다.
- 모든 데이터를 한 번에 처리해야 할 이유가 있는가?
- 실패 비용을 줄일 수 있는 구조는 없는가?
- 일부 작업 실패가 전체 실패로 이어져야 하는가?
이 질문들이 바로 이후 리팩토링의 출발점이 되었다.
다음 편 예고
다음 글에서는 “전체 삭제 → 전체 등록” 구조가 왜 대규모 환경에서 특히 위험한지, 그리고 어떤 기준으로 개선 방향을 설정했는지를 다룬다.
- 단일 트랜잭션의 구조적 한계
- 대량 데이터 처리에서 반드시 분리해야 할 책임
- 성능보다 먼저 고려해야 할 안정성의 기준
👉 2편. 전체 삭제 → 전체 등록 구조의 위험성에서 이어진다.
댓글
아직 댓글이 없습니다