Spring Batch 파티셔닝 기반 유사도 계산 템플릿

Spring Batch의 파티셔닝을 활용한 유사도 계산 배치 작업에 대한 상세 가이드입니다.

요약

  • Spring Batch의 파티셔닝을 통해 데이터 처리 효율성을 향상할 수 있습니다.
  • 배치 스텝에서 유사도 계산을 위한 코드 구조와 구성 요소를 명확히 이해할 수 있습니다.
  • 성능 최적화를 위한 설정 및 트랜잭션 관리 방법에 대해 배울 수 있습니다.

배경/문제

유사도 계산은 데이터 분석 및 머신러닝 분야에서 널리 사용되는 작업이며, 대량의 데이터를 처리하기 위해 효율적인 배치 프로세스가 필수적입니다. 데이터의 양이 많을 경우, 단일 스레드로 처리하는 것은 비효율적이며 성능 저하를 초래할 수 있습니다. Spring Batch는 이러한 문제를 해결하기 위해 설계된 강력한 프레임워크로, 파티셔닝 기능을 통해 데이터를 여러 섹션으로 나누어 병렬로 처리할 수 있는 기능을 제공합니다. 이 문서는 유사도 계산을 위한 Spring Batch의 파티셔닝 기반 구현 방법을 상세히 다룹니다.

접근/해결 전략

문서에서 설명하는 유사도 계산 배치 작업은 크게 다음과 같은 단계로 구성됩니다:

  1. 마스터 스텝을 통해 데이터를 파티션으로 나눕니다.
  2. 각 파티션은 독립적으로 Worker 스텝에서 병렬로 처리됩니다.
  3. 데이터의 읽기, 처리, 쓰기와 같은 각 단계에서 세심한 Bean 구성을 요구합니다.

이러한 과정을 체계적으로 문서화하여 다른 개발자들이 쉽게 이해하고 활용할 수 있도록 합니다.

구현 포인트

1. 아키텍처 구조

전반적인 아키텍처는 마스터 스텝을 통해 파티셔너를 사용하여 데이터를 N개의 파티션으로 분할하고, 각 파티션은 TaskExecutor를 통해 병렬로 처리됩니다. 다음은 전체 아키텍처의 개요입니다.

┌─────────────────────────────────────────────────────────────┐
│                       Master Step                           │
│   - 파티셔너를 사용하여 데이터를 N개 파티션으로 분할        │
│   - TaskExecutor를 통해 병렬 처리                           │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌──────────────┬──────────────┬──────────────┬──────────────┐
│  Worker #1   │  Worker #2   │  Worker #3   │  Worker #N   │
│  파티션 1    │  파티션 2    │  파티션 3    │  파티션 N    │
│  처리        │  처리        │  처리        │  처리        │
└──────────────┴──────────────┴──────────────┴──────────────┘

2. Steps 클래스

유사도 계산 스텝을 정의하고 필요한 Configuration Bean을 연결합니다. 이 클래스는 Spring Batch의 기본 구조를 따르며, 유사도 계산 스텝 및 삭제 플래그 업데이트 스텝을 포함합니다.

@Component("{domain}SimilaritiesSteps")
@RequiredArgsConstructor
@Slf4j
public class {Domain}SimilaritiesSteps {
    
    private final ApplicationContext applicationContext;

    // 유사도 계산 Step
    public Step calculate{Domain}SimilaritiesStep(JobRepository jobRepository, Date lastUpdatedAt) {
        return applicationContext.getBean("calculate{Domain}SimilaritiesStep", Step.class);
    }

    // 삭제 플래그 갱신 Step
    public Step update{Domain}SimilaritiesDelYnStep(JobRepository jobRepository, Date lastUpdatedAt) {
        return new Update{Domain}SimilaritiesDelYnStep(...).build();
    }
}

3. StepsConfig 클래스

파티셔닝 관련 모든 Bean을 정의하는 설정 파일입니다. 이 구성은 각 단계에서 필요한 Reader, Processor, Writer 등을 설정하여 유기적으로 작동하게 합니다.

@Bean
@StepScope
public JpaPagingItemReader<Object[]> {domain}SimilaritiesPartitionReader(
        @Value("#{stepExecutionContext['startBoundary']}") Long startBoundary,
        @Value("#{stepExecutionContext['endBoundary']}") Long endBoundary,
        @Value("#{stepExecutionContext['partitionNumber']}") Integer partitionNumber) {

    // 파티션 범위에 따른 쿼리 선택
    String queryString = (endBoundary == null)
        ? BatchSql.{DOMAIN}_SIMILARITIES_DATA_LAST
        : BatchSql.{DOMAIN}_SIMILARITIES_DATA;

    return new JpaPagingItemReaderBuilder<Object[]>()
        .name("{domain}SimilaritiesPartitionReader-" + partitionNumber)
        .entityManagerFactory(syworksEntityManagerFactory)
        .queryString(queryString)
        .parameterValues(params)
        .pageSize(PAGE_SIZE)
        .saveState(false) // 멀티스레드 환경에서 restart 충돌 방지
        .build();
}

4. SQL 쿼리 패턴

배치 작업에 사용할 SQL 쿼리는 유사도 계산에 필수적이며, 각 도메인별로 구성됩니다.

1. COUNT 쿼리

-- {DOMAIN}_SIMILARITIES_COUNT
SELECT COUNT(*)
FROM (
    -- 유사도 계산 대상 서브쿼리
) AS subquery

2. 파티션 경계 쿼리

-- {DOMAIN}_SIMILARITIES_PARTITION_BOUNDARY
WITH candidates AS (
    -- 처리 대상 ID 추출
),
boundary_data AS (
    SELECT
        id,
        NTILE(?1) OVER (ORDER BY id) AS partition_num,
        ROW_NUMBER() OVER (ORDER BY id) AS global_row_num
    FROM candidates
),
partition_ranges AS (
    SELECT
        partition_num,
        MIN(id) AS min_id,
        MAX(id) AS max_id
    FROM boundary_data
    GROUP BY partition_num
)
SELECT
    p1.partition_num as partitionNum,
    p1.min_id as startBoundary,
    p2.min_id as endBoundary
FROM partition_ranges p1
LEFT JOIN partition_ranges p2
    ON p1.partition_num = p2.partition_num - 1
ORDER BY p1.partition_num

3. 데이터 조회 쿼리 (범위 포함)

-- {DOMAIN}_SIMILARITIES_DATA
SELECT
    keywordId,
    targetId,
    AVG(cosineSimilarity) as cosineSimilarity,
    AVG(euclideanDistance) as euclideanDistance,
    AVG(manhattanDistance) as manhattanDistance
FROM ...
WHERE id >= :startBoundary AND id < :endBoundary
GROUP BY keywordId, targetId

5. Service 레이어 요구사항

유사도에 대한 Bulk UPSERT 메서드는 다음과 같이 정의됩니다. 이 메서드는 데이터 유효성을 검증하고 데이터베이스에 효율적으로 업데이트합니다.

@Transactional(transactionManager = "syworksTransactionManager", propagation = Propagation.REQUIRES_NEW)
public int bulkUpsert{Domain}Similarities(List<{Domain}SimilaritiesDto> similarities) {
    String sql = String.format("""
        INSERT INTO %s.{table_name} (
            keyword_id, target_id,
            cosine_similarity, euclidean_distance, manhattan_distance,
            del_yn, last_batch_date, last_batch_time
        ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
        ON CONFLICT (keyword_id, target_id)
        DO UPDATE SET
            cosine_similarity = EXCLUDED.cosine_similarity,
            euclidean_distance = EXCLUDED.euclidean_distance,
            manhattan_distance = EXCLUDED.manhattan_distance,
            del_yn = EXCLUDED.del_yn,
            last_batch_date = EXCLUDED.last_batch_date,
            last_batch_time = EXCLUDED.last_batch_time
        """, SCHEMA_NAME);

    // PreparedStatement를 사용한 배치 처리
    // 500건씩 executeBatch() 실행
}

주의사항/트레이드오프

  1. 트랜잭션 관리
    • Bulk UPSERT는 REQUIRES_NEW 전파 수준을 사용하여 별도로 관리해야 합니다. DDL 명령어는 별도 트랜잭션으로 실행할 필요가 있습니다.
  2. 메모리 관리
    • 청크 크기는 기본적으로 5000으로 설정하며, 메모리와 처리 속도 간의 균형을 유지해야 합니다. Reader의 saveState(false) 설정은 멀티스레드 환경에서의 충돌을 방지하기 위해 필수적입니다.
  3. 병렬 처리
    • 파티션 수와 스레드 풀 크기를 동일하게 설정하여 CPU 코어 수를 고려하여 최적의 성능을 유지해야 합니다.
  4. 로깅
    • 처리 진행 상황에 대한 로그를 통해 작업 상태를 모니터링할 수 있으며, 파티션별 독립적인 로깅이 필요합니다.

마무리

새로운 유사도 계산 스텝을 구현하기 위해 아래 체크리스트를 확인해야 합니다:

  1. Entity & DTO 준비
    • JPA Entity 클래스와 DTO 클래스 생성.
  2. Repository 구현
    • JpaRepository 인터페이스와 RepositorySupport 클래스 생성 및 적절한 메서드 구현.
  3. Service 레이어 구성
    • Service 인터페이스와 구현체 생성.
  4. 배치 SQL 쿼리 추가
    • COUNT, PARTITION_BOUNDARY, DATA 쿼리 추가.
  5. Step 및 Config 설정
    • Steps 클래스 및 StepsConfig 클래스 생성하여 필요한 Bean 정의.
  6. Job 등록
    • JobLaunchers에 새로운 Step 추가.

이러한 구성을 통해 Spring Batch를 활용한 유사도 계산 배치 작업을 효율적으로 설계하고 구현할 수 있습니다.


© 2024. Chiptune93 All rights reserved.