포스트

대량 배치 안정성을 높이기 위한 구조 개선: Part 3 - 청크 분할과 병렬 처리로 재설계하기

3편. 청크 분할과 병렬 처리로 배치 구조 재설계하기

들어가며

앞선 두 편에서 문제를 정리했다면, 이번 글부터는 “그래서 어떻게 바꿨는가”에 대한 이야기다.

개선의 출발점은 단순했다.

모든 데이터를 한 번에 처리하지 않는다.

이 원칙을 실제 시스템 구조로 옮기는 과정에서 가장 먼저 손을 댄 것이 청크 분할과 병렬 처리였다.


전체를 나누는 순간, 문제가 다르게 보이기 시작했다

기존 구조에서는 데이터가 늘어날수록 선택지는 하나뿐이었다.

  • 더 오래 기다리거나
  • 더 큰 장애를 감수하거나

하지만 데이터를 작은 단위로 나누자, 문제의 성격 자체가 달라졌다.

  • 실패는 전체가 아니라 일부가 되고
  • 재시도는 전체가 아니라 특정 범위가 되며
  • 성능 개선의 여지가 생기기 시작했다

청크 분할 전략: 얼마나, 어떻게 나눌 것인가

1. 청크 단위의 기준

청크 크기를 정할 때 가장 먼저 고려한 것은 “이 단위가 실패했을 때 감당 가능한가”였다.

  • 너무 크면 실패 비용이 커지고
  • 너무 작으면 오버헤드가 커진다

결과적으로 다음 기준을 적용했다.

  • 하나의 청크는 수 초 내 처리 가능
  • 실패 시 재시도가 부담되지 않는 범위
  • DB 락을 오래 점유하지 않는 크기

이 기준을 바탕으로 고정 크기 청크를 선택했다.


2. 데이터 경계 명확히 하기

청크 분할에서 중요한 것은 경계가 명확해야 한다는 점이다.

  • 범위 기준(ID, 날짜, 해시 등)
  • 중복 없이 모든 데이터를 포함
  • 병렬 처리 시에도 서로 간섭하지 않도록

이 경계를 명확히 하지 않으면 병렬 처리 자체가 또 다른 정합성 문제를 만든다.


병렬 처리 도입 시 가장 먼저 고려한 것들

병렬 처리는 성능을 끌어올리는 강력한 도구지만, 무작정 스레드를 늘리는 것은 오히려 독이 된다.

1. DB 커넥션 풀 한계

병렬 작업 수는 DB 커넥션 풀 크기를 넘지 않도록 제한했다.

  • 배치가 DB를 독점하지 않도록
  • 일반 트래픽과의 간섭 최소화
  • 최악의 경우에도 시스템 전체가 멈추지 않도록

2. 락 경합과 Deadlock 가능성

병렬 삭제는 특히 위험하다.

  • 잘못 설계하면 서로 다른 청크가 같은 인덱스를 두고 경쟁
  • 삭제 순서에 따라 Deadlock 발생 가능

이를 피하기 위해:

  • 청크 간 데이터 범위가 절대 겹치지 않도록 설계
  • 항상 동일한 순서로 락을 획득하도록 쿼리 구조 통일

삭제 쿼리 성능 튜닝: 병렬 처리의 전제 조건

병렬 처리 이전에 반드시 선행되어야 했던 작업이 있다.

삭제 쿼리 자체가 빨라야 한다.

1. 수평 분산 관점의 삭제 설계

대량 삭제를 한 테이블에 몰아 넣는 대신:

  • 데이터 분포를 기준으로 수평 분할
  • 특정 범위만 선택적으로 삭제
  • 불필요한 전체 스캔 제거

이를 통해 각 삭제 작업의 부담을 크게 줄였다.


2. 인덱스 재설계

기존 인덱스는 조회 중심으로 설계되어 있었고, 삭제 조건에는 최적화되어 있지 않았다.

  • 삭제 조건을 선두 컬럼으로 재정렬
  • 불필요한 복합 인덱스 제거
  • 삭제 시 인덱스 업데이트 비용 최소화

이 작업만으로도 단일 청크 삭제 시간이 눈에 띄게 줄었다.


결과: 구조를 바꿨을 뿐인데

청크 분할 + 병렬 처리 + 삭제 쿼리 튜닝을 적용한 결과는 명확했다.

  • 전체 삭제 시간 2시간 → 5분
  • 배치 실행 중 CPU·메모리 사용량 안정화
  • 장기 트랜잭션 제거로 롤백 리스크 사실상 제거
  • 실패 시 재처리 범위 최소화

성능 개선도 중요했지만, 무엇보다 큰 변화는 “예측 가능성”이었다.


얻은 교훈

이 과정에서 가장 크게 느낀 점은 하나였다.

대규모 배치에서 중요한 것은 얼마나 빠르냐보다, 얼마나 안전하게 실패할 수 있느냐다.

청크 분할은 단순한 성능 기법이 아니라 실패를 통제 가능한 단위로 바꾸는 설계 선택이었다.


다음 편 예고

다음 글에서는 청크 분할 이후에도 반복적으로 발생하던 문제, 분산 락 환경에서의 Race Condition을 다룬다.

  • 락이 있는데도 순서가 깨진 이유
  • 장애·타임아웃 상황에서 발생한 실제 시나리오
  • 로그 분석을 통한 원인 규명 과정

👉 4편. 분산 락이 있음에도 Race Condition이 발생한 이유에서 이어진다.


  1. 1 대량 배치 안정성을 높이기 위한 구조 개선: Part 1 - 시스템을 압박하기 시작한 배치
  2. 2 대량 배치 안정성을 높이기 위한 구조 개선: Part 2 - 전체 삭제 후 전체 등록 구조의 위험성
  3. 3 대량 배치 안정성을 높이기 위한 구조 개선: Part 3 - 청크 분할과 병렬 처리로 재설계하기
  4. 4 대량 배치 안정성을 높이기 위한 구조 개선: Part 4 - 분산 락이 있어도 레이스가 발생한 이유
  5. 5 대량 배치 안정성을 높이기 위한 구조 개선: Part 5 - 배타적 락과 조건부 해제로 순서를 보장하기
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.

댓글

아직 댓글이 없습니다