Batch Module Development

5 minute read

Published:

배치 모듈 개발기…

배치 모듈 개발

202X년 여름, 저는 회사 서비스의 백오피스 및 배치 모듈 개발을 담당하게 되었습니다.
서비스는 A, B, C, D의 4가지로 구성되어 있으며, 데이터는 하루에 약 30만 ~ 50만 건이 쌓입니다.
다음은 프로젝트 시작 전 전달받았던 요구사항입니다.

  1. 데이터를 10분, 일별, 월별 단위로 나누어 처리해야 한다.
  2. 다중화된 서버 환경에서의 데이터 처리를 고려해야 한다.
  3. 30분 이전의 데이터를 통계 내어야 한다.
  4. 결과 통계가 명확해야 한다.

데이터 동기화와 쿼리 최적화

처음에는 어떻게 배치모듈을 개발해야 할지 고민했습니다.

“4개의 서비스 사용 건수를 10분 단위로 집계하고, 이를 다시 일별로, 일별 데이터를 월별로 집계하는 방식으로 진행하면 되겠다!”

라는 아이디어를 떠올렸습니다.

고려사항 및 방법

  • 데이터의 일관성과 정확성을 유지하면서 빠른 처리가 가능한 DB 쿼리 최적화 방안.
  • 다중화된 서버 환경에서 데이터 처리 작업의 분산 처리.
  • 코드를 알아보기 쉽고 유지보수하기 편하게 만들기.

조회와 삽입을 동시에 처리하기

데이터의 일관성과 처리 속도를 동시에 고려하여 조회와 삽입 작업을 동시에 수행하는 쿼리를 작성했습니다.

INSERT INTO 테이블
(X_DATE, A_ID, B_ID, C_ID, D_TYPE, E_CNT, F_CNT, G_CNT, H_CNT, I_DATE)
SELECT '현재시간' AS X_DATE
     , A_ID
     , B_ID
     , C_ID
     , '지정된타입' AS D_TYPE
     , COUNT(E_TX_ID) AS E_CNT
     , COUNT(
          CASE            
          WHEN F_TYPE = 'fTypeA' AND G_CODE IN ('1234')
                  OR F_TYPE = 'fTypeB'
                  OR F_TYPE = 'fTypeC'
                  THEN 1
              END
       ) AS F_CNT
     , COUNT(
          CASE            
          WHEN F_TYPE = 'fTypeC' AND G_CODE IN ('1234')
                  OR F_TYPE = 'fTypeB' AND G_CODE IN ('1234')
                  THEN 1
              END
       ) AS G_CNT
     , '시간 변수' AS I_DATE
FROM LMNOP_TBL
WHERE 1 = 1
  AND I_DATE >= '조회시간'
  AND I_DATE < '조회시간'
GROUP BY B_ID, C_ID, A_ID

쿼리 최적화를 위해 DB 인덱싱을 통해 데이터베이스 점유 시간을 최소화했습니다.

조회와 삽입을 분리하여 사용하는 방법의 장단점

장점:

  1. 명확한 로직 분리와 확장성.
  2. 유연한 유지보수.
  3. 오류 예방.

단점:

  1. 통신 횟수 증가.
  2. 트랜잭션 관리 어려움.
  3. 일관성 유지의 어려움.
  4. 복잡한 예외 처리.
  5. 리소스 비효율.

조회와 삽입을 동시에 사용하는 쿼리의 장단점

장점:

  1. 통신 횟수 감소.
  2. 일관성 보장.
  3. 트랜잭션 관리의 간소화.

단점:

  1. 로직 복잡성.
  2. 오류 예방의 어려움.
  3. 튜닝의 어려움.

동기화 처리와 DB Lock 테이블

데이터의 순차적인 삽입 처리를 위해 DB lock 테이블을 생성하여 관리했습니다.

CREATE TABLE `STAT_UPDATE_LOCK` (
  `STAT_TYPE` varchar(10) NOT NULL COMMENT '배치 종류. 서비스명 + MIN,DAY,MONTH : 분,일,월',
  `LOCK_YN` char(1) NOT NULL COMMENT '잠금 여부. (Y : 사용, N : 미사용)',
  `LAST_UPDATE` timestamp NULL DEFAULT NULL COMMENT '마지막 업데이트 시간',
  PRIMARY KEY (`STAT_TYPE`)
)

테스트와 문제 해결

한 달치 평균 mock data를 생성하여 배치모듈을 테스트했지만, 통계 데이터 처리 과정에서 여러 문제가 발생했습니다. 특히 모든 Exception을 롤백시키지 않는다는 점을 발견했습니다. @Transactional 어노테이션에 대해 추가로 공부하며, 사용자 정의 Exception이 롤백되지 않는 문제를 해결했습니다.

@Transactional 활용

@Transactional 어노테이션을 활용하여 데이터의 안정성과 정확성을 확보했습니다. 트랜잭션의 주요 목적은 데이터 무결성과 일관성을 보장하는 것이며, 이를 통해 복잡한 트랜잭션 관리가 간소화되었습니다.

롤백 처리

@Transactional(rollbackFor = CustomException.class)
    
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();

배치 모듈 개발 시 주의사항

1. 데이터 일관성 및 무결성 유지

  • 트랜잭션 관리: 배치 작업은 대량의 데이터를 처리하므로 트랜잭션 관리를 철저히 하여 데이터 일관성과 무결성을 보장해야 합니다. 예를 들어, 모든 작업이 성공적으로 완료되지 않으면 전체 작업을 롤백하는 메커니즘을 구현해야 합니다.
  • 락(Lock) 사용: 데이터의 동시 접근을 방지하기 위해 필요시 락을 사용해야 합니다. 특히 다중 서버 환경에서는 락 메커니즘을 통해 데이터 충돌을 방지할 수 있습니다.

2. 성능 최적화

  • 쿼리 최적화: 배치 작업에 사용되는 SQL 쿼리를 최적화하여 데이터베이스 부하를 최소화해야 합니다. 인덱스를 적절히 사용하고, 불필요한 풀 스캔을 피하기 위해 조인과 필터링 조건을 최적화합니다.
  • 리소스 관리: 배치 작업이 많은 리소스를 사용하지 않도록 메모리 사용량을 관리하고, 적절한 쓰레드 수를 설정하여 시스템의 성능을 최적화합니다.

3. 스케줄링 및 모니터링

  • 스케줄링: 배치 작업을 적절한 시간에 실행하도록 스케줄링합니다. 일반적으로 시스템 부하가 적은 시간대에 배치 작업을 실행하는 것이 좋습니다.
  • 모니터링: 배치 작업의 실행 상태를 모니터링하여 오류나 성능 문제를 신속히 감지하고 대응할 수 있도록 합니다. 로그를 체계적으로 관리하고, 알림 시스템을 통해 이상 상황을 즉시 파악할 수 있어야 합니다.

4. 예외 처리

  • 예외 상황 대비: 배치 작업 도중 발생할 수 있는 다양한 예외 상황을 대비하여 적절한 예외 처리를 구현합니다. 각 단계에서 발생할 수 있는 예외를 예측하고, 이를 처리할 수 있는 로직을 설계합니다.
  • 재시도 메커니즘: 일시적인 오류로 인해 배치 작업이 실패할 경우 자동으로 재시도할 수 있는 메커니즘을 도입합니다.

5. 확장성 및 유지보수성

  • 모듈화: 배치 작업을 작은 모듈로 나누어 구현하면 확장성과 유지보수성이 향상됩니다. 각 모듈은 독립적으로 테스트하고 배포할 수 있어야 합니다.
  • 코드 가독성: 코드를 읽기 쉽고 이해하기 쉽게 작성하여 유지보수를 용이하게 합니다. 주석을 적절히 사용하고, 명확한 네이밍 규칙을 따릅니다.

6. 로깅 및 감사 추적

  • 로깅: 배치 작업의 각 단계에서 적절한 로그를 남겨 작업의 흐름을 추적할 수 있도록 합니다. 오류 발생 시 신속하게 원인을 파악하고 대응할 수 있도록 상세한 로그를 기록합니다.
  • 감사 추적: 배치 작업의 결과를 검증하고, 필요시 감사할 수 있도록 데이터를 추적합니다. 이는 데이터 처리의 신뢰성을 높이는 데 중요합니다.

7. 테스트 및 검증

  • 철저한 테스트: 배치 작업은 다양한 상황에서 제대로 동작하는지 철저히 테스트해야 합니다. 특히 대량의 데이터를 처리하는 배치 작업의 경우, 성능 테스트와 부하 테스트를 통해 시스템의 안정성을 검증합니다.
  • 데이터 검증: 배치 작업 후 데이터가 정확하게 처리되었는지 검증하는 절차를 마련합니다. 샘플 데이터를 기반으로 테스트하여 예상치 못한 오류를 사전에 방지합니다.

8. 보안 고려

  • 데이터 보안: 배치 작업 중 처리되는 데이터의 보안을 철저히 관리해야 합니다. 민감한 데이터는 암호화하여 저장하고 전송해야 합니다.
  • 접근 제어: 배치 작업을 실행할 수 있는 권한을 엄격히 관리하고, 필요한 사용자에게만 권한을 부여합니다.

배치 모듈 개발 프로젝트는 데이터 동기화와 쿼리 최적화, 트랜잭션 관리의 중요성을 깨닫게 되었습니다.
이 경험을 통해 복잡한 데이터 처리를 효율적으로 관리하고, 유지보수하기 쉬운 코드를 작성하는 방법을 익힐 수 있었습니다.

이번 프로젝트를 통해 얻은 교훈을 바탕으로, 앞으로의 개발에서도 더 나은 성능과 안정성을 갖춘 시스템을 설계하고 구현할 수 있도록 노력하겠습니다.