개발일기/Spring

[Spring batch] meta data table을 public이 아닌 다른 schema에 생성

ignuy 2024. 11. 7.

실행환경

Spring batch는 버전마다 편차가 심하다. 본 포스팅의 실행 환경을 반드시 확인하자.

Spring boot: 3.3.5

Spring batch: 5.1.2

RDBMS: postgreSQL

Spring batch meta data table 수동 설정

스프링 배치는 그 실행과 관리를 위해 Job, Step, JobParameter 등의 정보를 주로 데이터베이스에 저장하고 관리한다. Spring batch는 DB에 저장된 batch관련 정보들을 활용하여 작업 재실행, 중단 후 재시작, 상태 추적 등의 기능을 효과적으로 지원하게 된다.

Spring batch는 데이터의 스키마를 RDBMS의 종류에 맞게 정의해두었고 application.yml에서 설정을 통해 이 schema를 생성하는 sql 스크립트를 자동으로 실행할 수 있다.

spring:
  batch:
    jdbc:
      initialize-schema: always

다만 script를 자동으로 실행하게 되면 한가지 문제점이 발생한다. 바로 public schema에 batch meta data table이 생성된다는 점이다. public에 서비스 운영에 관련된 데이터들도 들어갈텐데 schema가 상당히 지저분해진다.

데이터 어딨냐..

개발 및 테스트 단계에서 데이터 테이블 구조를 파악하거나 찾기 어려우므로 이 마음에 안드는 상황을 고쳐보자.

Schema 자동 생성 비활성화 & table-prefix 설정

spring:
  batch:
    jdbc:
      initialize-schema: never
      table-prefix: BATCH_META.BATCH_

initialize-schema 설정을 never로 바꿔 수동 설정임을 표시하자. 이 때, Spring batch는 기본적으로 public 스키마를 참조하도록 설정되어 있다. 현재 Job과 Step의 상태 및 실행 기록을 저장할 meta data 테이블이 정상적으로 선언되어 있지 않으므로 Spring Batch는 BadSqlGrammarException 또는 TableNotFoundException을 내뿜는다.

따라서, 수동으로 생성할 테이블의 schema를 포함한 table-prefix를 application.yaml에 적어주자. 필자의 경우 BATCH_META.BATCH_로 하였다.

Schema 생성 스크립트를 찾자.

여기서부터 아래 과정은 중요한 의미를 가지고 있다. Spring batch는 운영환경에서 가급적 수동으로 스크립트를 생성하고 DB에 반영하길 권장하고 있다. 여러 이유가 있는데 제일 하단에 후술하도록 하겠다. schema를 생성, 및 변경을 위한 스크립트의 백본은 spring-batch-core 라이브러리에 들어있다. 앞으로 batch작업에 대해서 sql script가 필요하다면 참조할 레퍼런스로 spring-batch-core를 뒤지면 된다.

 

IntelliJ 기준으로 External Libraries를 열어보자. 의존성으로 등록한 라이브러리들이 위치한 곳인데 여기서 스크롤을 조금 내리다 보면 Gradle: org.springframework.batch:spring-batch-core:5.1.2라이브러리를 확인할 수 있을 것이다. 라이브러리를 열고 다시 스크롤을 조금만 내리면 schema-*.sql 파일을 확인할 수 있을 것이다.

본인의 RDBMS vendor를 아스테리스크(*)에 넣고 파일을 찾아보자. 예를 들어, mysql 사용중이라면 schema-mysql.sql, 필자의 경우 schema-postgresql.sql이다.

schema-*.sql 파일을 열고 스크립트를 복사하자. resources 폴더에 따로 저장할 것이다.

Schem-*.sql 스크립트 수정 및 반영

이제 운영 환경에 반영할 스크립트를 만들 것이다. 우선 prefix에서 설정한 것처럼 Schema를 만들고 생성할 Table에 schema를 명시해 주자. 일일이 테이블마다 수정하기 귀찮은 postgreSQL을 사용하고 있는 개발자들은 아래 script를 복사하여 사용하자.

CREATE SCHEMA BATCH_META;

-- Autogenerated: do not edit this file

CREATE TABLE BATCH_META.BATCH_JOB_INSTANCE
(
    JOB_INSTANCE_ID BIGINT       NOT NULL PRIMARY KEY,
    VERSION         BIGINT,
    JOB_NAME        VARCHAR(100) NOT NULL,
    JOB_KEY         VARCHAR(32)  NOT NULL,
    constraint JOB_INST_UN unique (JOB_NAME, JOB_KEY)
);

CREATE TABLE BATCH_META.BATCH_JOB_EXECUTION
(
    JOB_EXECUTION_ID BIGINT    NOT NULL PRIMARY KEY,
    VERSION          BIGINT,
    JOB_INSTANCE_ID  BIGINT    NOT NULL,
    CREATE_TIME      TIMESTAMP NOT NULL,
    START_TIME       TIMESTAMP DEFAULT NULL,
    END_TIME         TIMESTAMP DEFAULT NULL,
    STATUS           VARCHAR(10),
    EXIT_CODE        VARCHAR(2500),
    EXIT_MESSAGE     VARCHAR(2500),
    LAST_UPDATED     TIMESTAMP,
    constraint JOB_INST_EXEC_FK foreign key (JOB_INSTANCE_ID)
        references BATCH_META.BATCH_JOB_INSTANCE (JOB_INSTANCE_ID)
);

CREATE TABLE BATCH_META.BATCH_JOB_EXECUTION_PARAMS
(
    JOB_EXECUTION_ID BIGINT       NOT NULL,
    PARAMETER_NAME   VARCHAR(100) NOT NULL,
    PARAMETER_TYPE   VARCHAR(100) NOT NULL,
    PARAMETER_VALUE  VARCHAR(2500),
    IDENTIFYING      CHAR(1)      NOT NULL,
    constraint JOB_EXEC_PARAMS_FK foreign key (JOB_EXECUTION_ID)
        references BATCH_META.BATCH_JOB_EXECUTION (JOB_EXECUTION_ID)
);

CREATE TABLE BATCH_META.BATCH_STEP_EXECUTION
(
    STEP_EXECUTION_ID  BIGINT       NOT NULL PRIMARY KEY,
    VERSION            BIGINT       NOT NULL,
    STEP_NAME          VARCHAR(100) NOT NULL,
    JOB_EXECUTION_ID   BIGINT       NOT NULL,
    CREATE_TIME        TIMESTAMP    NOT NULL,
    START_TIME         TIMESTAMP DEFAULT NULL,
    END_TIME           TIMESTAMP DEFAULT NULL,
    STATUS             VARCHAR(10),
    COMMIT_COUNT       BIGINT,
    READ_COUNT         BIGINT,
    FILTER_COUNT       BIGINT,
    WRITE_COUNT        BIGINT,
    READ_SKIP_COUNT    BIGINT,
    WRITE_SKIP_COUNT   BIGINT,
    PROCESS_SKIP_COUNT BIGINT,
    ROLLBACK_COUNT     BIGINT,
    EXIT_CODE          VARCHAR(2500),
    EXIT_MESSAGE       VARCHAR(2500),
    LAST_UPDATED       TIMESTAMP,
    constraint JOB_EXEC_STEP_FK foreign key (JOB_EXECUTION_ID)
        references BATCH_META.BATCH_JOB_EXECUTION (JOB_EXECUTION_ID)
);

CREATE TABLE BATCH_META.BATCH_STEP_EXECUTION_CONTEXT
(
    STEP_EXECUTION_ID  BIGINT        NOT NULL PRIMARY KEY,
    SHORT_CONTEXT      VARCHAR(2500) NOT NULL,
    SERIALIZED_CONTEXT TEXT,
    constraint STEP_EXEC_CTX_FK foreign key (STEP_EXECUTION_ID)
        references BATCH_META.BATCH_STEP_EXECUTION (STEP_EXECUTION_ID)
);

CREATE TABLE BATCH_META.BATCH_JOB_EXECUTION_CONTEXT
(
    JOB_EXECUTION_ID   BIGINT        NOT NULL PRIMARY KEY,
    SHORT_CONTEXT      VARCHAR(2500) NOT NULL,
    SERIALIZED_CONTEXT TEXT,
    constraint JOB_EXEC_CTX_FK foreign key (JOB_EXECUTION_ID)
        references BATCH_META.BATCH_JOB_EXECUTION (JOB_EXECUTION_ID)
);

CREATE SEQUENCE BATCH_META.BATCH_STEP_EXECUTION_SEQ MAXVALUE 9223372036854775807 NO CYCLE;
CREATE SEQUENCE BATCH_META.BATCH_JOB_EXECUTION_SEQ MAXVALUE 9223372036854775807 NO CYCLE;
CREATE SEQUENCE BATCH_META.BATCH_JOB_SEQ MAXVALUE 9223372036854775807 NO CYCLE;

반영된 DB 상태를 확인하고 Spring Boot를 실행해보자. 정상적으로 돌아갈 것이다.

왜 수동 설정이 중요하지?

무엇보다 중요한 이 수동 설정의 목적은 “운영환경에서 신뢰성과 일관성을 보장하자.” 이다. schema를 나누어 meta data를 저장하자는 목적에서 그치지 않고 훨씬 거대한 내용을 포함하고 있다.

구체적으로 알아보자.

  1. 업그레이드와 호환성 관리: Spring Batch 4.x에서 5.x 버전으로 버전이 올라갈 때, DB 스키마도 상당히 많이 변하였다(Spring batch 5.0 Migration Guide - 국문 번역). 이처럼 자동 생성에 의존하면, 배포 시 예상치 못한 스키마 변경이 발생하여 기존 데이터와의 호환성 문제가 생길 수 있다. 수동 스크립트 관리를 통해, 필요할 경우 변경 사항을 사전에 검토하고, 데이터 마이그레이션 등을 준비할 수 있을 것이다.
  2. 운영 환경의 데이터베이스 성능 최적화: 메타데이터 테이블을 수동으로 설정하여 생성하면 테이블의 인덱스, 파티셔닝, 스토리지 엔진 등의 설정을 데이터베이스 성능을 고려하여 조정할 수 있다. 수동 스크립트를 통해 이러한 최적화를 적용하여 Spring Batch의 메타데이터 처리의 효율화를 기대할 수 있을 것이다.
  3. 데이터베이스 구조와 설정에 대한 통제: 운영 환경에서는 데이터베이스 구조와 권한에 대해 더 높은 수준의 제어가 필요하다. 따라서 수동으로 스크립트를 실행하여 테이블 생성 시점과 구성 사항을 명확히 관리함으로써, 자동 생성보다 데이터베이스 구조에 대한 제어를 강화할 수 있다.

댓글