Skip to content

필사 모드: 금융권 배치와 일마감(EOD) — 새벽을 지배하는 아키텍처

한국어
0%
정확도 0%
💡 왼쪽 원문을 읽으면서 오른쪽에 따라 써보세요. Tab 키로 힌트를 받을 수 있습니다.
원문 렌더가 준비되기 전까지 텍스트 가이드로 표시합니다.

들어가며 — 은행의 하루는 자정에 끝나지 않는다

은행 영업점이 문을 닫고 모바일 앱 사용자가 잠든 새벽, 은행의 데이터센터는 하루 중 가장 바쁜 시간을 보냅니다. 수천 개의 배치 잡이 의존성 그래프를 따라 흘러가며 이자를 계산하고, 연체를 전이시키고, 보고서를 만들고, 원장을 마감합니다. 이 과정 전체를 일마감(EOD, End of Day)이라고 부릅니다.

"요즘 같은 실시간 시대에 왜 아직도 배치인가"라는 질문을 자주 받습니다. 이 글에서는 그 질문에 대한 답부터 시작해, EOD 처리의 범위, 잡 스케줄러와 의존성 관리, 대용량 처리 기법, 온라인과 배치의 공존, 실패 복구, 그리고 배치 현대화 흐름까지 금융권 배치 아키텍처의 전체 그림을 그려보겠습니다.

이 글은 시스템 아키텍처 관점의 기술 자료이며, 특정 기관의 내부 구현이나 규제 해석에 대한 자문이 아닙니다.

금융권에서 배치가 여전히 핵심인 이유

배치가 사라지지 않는 이유는 기술 부채 때문만이 아닙니다. 본질적으로 배치일 수밖에 없는 업무가 있습니다.

1. **기준 시점이 필요한 업무**: 이자 계상, 자산분류, 보고서는 "어느 시점의 상태"를 기준으로 전 계좌에 일괄 적용해야 합니다. 기준 시점 없이 흘러가는 스트림으로는 "오늘자 잔액 기준 이자"를 정의할 수 없습니다.

2. **규제 보고의 단위가 일 단위**: 금융감독원 업무보고서, 한국은행 보고, 예금보험 관련 산출물 대부분이 영업일 단위 스냅샷을 요구합니다.

3. **대사와 정산의 구조**: 타기관과의 정산(금융결제원, 카드사, 증권예탁)은 파일 교환과 일 단위 확정이라는 프로토콜 자체가 배치입니다.

4. **처리 효율**: 1천만 계좌의 이자 계상을 건건이 온라인 트랜잭션으로 처리하는 것보다, 셋 기반(set-based) 일괄 처리가 수십 배 효율적입니다.

즉 "배치 vs 실시간"은 양자택일이 아니라, **기준 시점이 필요한 업무는 배치, 즉시성이 필요한 업무는 온라인**이라는 역할 분담의 문제입니다.

EOD 처리의 범위 — 새벽에 일어나는 일들

일마감 윈도우에서 처리되는 대표 업무를 정리하면 다음과 같습니다.

| 업무 | 내용 | 특징 |

| --- | --- | --- |

| 이자 계상 | 예금·대출 계좌별 일할 이자 계산 및 누적 | 전 계좌 대상, 계산 집약 |

| 기산일 처리 | 마감 후 도착 거래의 영업일 귀속 확정 | 날짜 전환과 맞물림 |

| 연체 전이 | 상환일 도과 대출의 연체 상태 전환, 연체이자 기산 | 상태 머신, 규정 의존 |

| 자산건전성 분류 | 정상/요주의/고정 등 분류 재산정 | 여신 전체 재평가 |

| 만기 처리 | 예적금 만기 해지·재예치, 대출 기일 처리 | 상품 규칙 다양 |

| 수수료·정산 | 일 단위 수수료 집계, 타기관 정산 파일 생성 | 외부 인터페이스 |

| 총계정원장 전기 | 거래 원장 집계 후 GL 반영 | 차대 평형 게이트 |

| 보고서·정보계 적재 | 규제 보고 산출, DW/정보계 ETL | 마감 확정 후 실행 |

핵심은 이 업무들이 **순서 의존성**을 가진다는 점입니다. 이자 계상 전에 당일 거래가 확정되어야 하고, 자산분류는 연체 전이 후에, GL 전기는 모든 원장 변동이 끝난 뒤에 가능합니다.

배치 아키텍처 — 스케줄러와 의존성 DAG

수천 개의 잡을 사람이 순서대로 실행할 수는 없으므로, 잡 스케줄러가 의존성 그래프(DAG)를 따라 잡을 기동합니다.

[EOD 의존성 DAG (단순화)]

온라인 마감 선언

당일 거래 확정 ──────┬─────────────┐

│ │ │

▼ ▼ ▼

이자 계상 수수료 집계 만기 처리

│ │ │

▼ │ │

연체 전이 ◀──────────┘ │

│ │

▼ │

자산건전성 분류 ◀──────────────────┘

원장 검증 (차대 평형) ── 실패 시 전체 중단 게이트

GL 전기 ──▶ 보고서 생성 ──▶ 정보계 적재

날짜 전환 ──▶ 온라인 재개

전통적으로 금융권은 상용 엔터프라이즈 스케줄러(Control-M, TWS/IWS, AutoSys, JobScheduler 계열 등)를 써왔고, 최근에는 Airflow 같은 오픈소스를 도입하는 곳도 늘었습니다. 관점 비교는 다음과 같습니다.

| 관점 | 상용 스케줄러 | Airflow 등 오픈소스 |

| --- | --- | --- |

| 의존성 모델 | 잡·캘린더 중심, 운영자 친화 GUI | 코드 기반 DAG, 개발자 친화 |

| 영업일 캘린더 | 휴일·영업일 캘린더 내장이 강력 | 직접 구현 또는 플러그인 필요 |

| 재기동·예외 처리 | 운영 콘솔에서 즉시 개입 용이 | 태스크 단위 retry, UI 개입 가능 |

| 감사·권한 | 금융권 요구 수준의 통제 기능 성숙 | RBAC 가능하나 구성 필요 |

| 비용·확장 | 라이선스 비용 높음 | 라이선스 무료, 운영 역량 필요 |

어느 쪽이든 양보할 수 없는 요구사항은 같습니다.

- **영업일 캘린더**: 휴일, 임시 휴장, 월말·분기말 분기를 스케줄 정의에서 표현할 수 있어야 합니다.

- **체크포인트와 재기동**: 잡이 중간에 실패하면 처음부터가 아니라 실패 지점부터 재시작할 수 있어야 합니다.

- **선후행 강제**: 선행 잡 성공 없이 후행 잡이 돌지 않아야 하며, 강제 기동은 권한 통제와 기록 하에서만 가능해야 합니다.

대용량 처리 기법 — 파티셔닝, 병렬도, 청크

천만 건 이상을 처리하는 배치의 기본기는 세 가지입니다.

1. **파티셔닝**: 처리 대상을 겹치지 않는 구간(계좌번호 범위, 해시, 지점)으로 나눠 병렬 실행합니다.

2. **청크 처리**: 한 건씩 커밋하지 않고 N건 단위로 읽기-처리-쓰기 후 커밋해 트랜잭션 비용을 줄입니다.

3. **셋 기반 연산 우선**: 행 단위 루프보다 가능한 한 SQL 일괄 연산(INSERT SELECT, 일괄 UPDATE)을 사용합니다.

Spring Batch로 이자 계상 잡의 골격을 표현하면 다음과 같습니다.

@Configuration

public class InterestAccrualJobConfig {

@Bean

public Job interestAccrualJob(JobRepository jobRepository, Step partitionedStep) {

return new JobBuilder("interestAccrualJob", jobRepository)

.start(partitionedStep)

.build();

}

// 계좌번호 범위로 파티셔닝하여 그리드 사이즈만큼 병렬 실행

@Bean

public Step partitionedStep(JobRepository jobRepository,

Step accrualStep,

AccountRangePartitioner partitioner,

TaskExecutor taskExecutor) {

return new StepBuilder("partitionedAccrualStep", jobRepository)

.partitioner("accrualStep", partitioner)

.step(accrualStep)

.gridSize(8)

.taskExecutor(taskExecutor)

.build();

}

// 청크 단위 처리: 1000건 읽기-계산-쓰기 후 커밋

@Bean

public Step accrualStep(JobRepository jobRepository,

PlatformTransactionManager txManager,

JdbcPagingItemReader<Account> reader,

InterestCalculator processor,

JdbcBatchItemWriter<AccrualResult> writer) {

return new StepBuilder("accrualStep", jobRepository)

.<Account, AccrualResult>chunk(1000, txManager)

.reader(reader)

.processor(processor)

.writer(writer)

.faultTolerant()

.skipLimit(0) // 금융 배치: 건너뛰기 대신 실패 후 조사

.build();

}

}

public class AccountRangePartitioner implements Partitioner {

@Override

public Map<String, ExecutionContext> partition(int gridSize) {

Map<String, ExecutionContext> result = new HashMap<>();

long min = 1_0000_0000L, max = 9_9999_9999L;

long size = (max - min) / gridSize + 1;

for (int i = 0; i < gridSize; i++) {

ExecutionContext ctx = new ExecutionContext();

ctx.putLong("minAccountNo", min + size * i);

ctx.putLong("maxAccountNo", Math.min(min + size * (i + 1) - 1, max));

result.put("partition" + i, ctx);

}

return result;

}

}

설계 포인트입니다.

- **skipLimit(0)**: 일반 데이터 파이프라인에서는 불량 레코드를 건너뛰지만, 이자 계상에서 한 계좌를 건너뛰면 그 계좌의 이자가 사라집니다. 실패는 멈추고 조사하는 것이 원칙입니다.

- **JdbcPagingItemReader**: 커서 기반 리더는 재기동 시 위치 복원이 어려운 환경이 있어, 키 기반 페이징 리더가 재시작 안전성에 유리합니다.

- **파티션 경계는 데이터 분포 고려**: 계좌번호가 지점별로 몰려 있으면 균등 범위 분할이 불균형해집니다. 해시 분할 또는 사전 통계 기반 분할을 검토합니다.

일마감과 온라인의 공존 — 센터컷과 날짜 전환

24시간 뱅킹 시대의 핵심 난제는 "마감 중에도 이체는 들어온다"입니다. 이를 다루는 장치가 센터컷(center-cut)과 날짜 전환(cut-over) 시퀀스입니다.

센터컷은 대량 건을 온라인 트랜잭션 경로로 흘려보내되 배치가 주도하는 방식입니다. 예를 들어 급여 이체 10만 건을 배치 파일로 받아, 내부적으로는 온라인 이체 트랜잭션을 고속으로 연사하는 구조입니다. 온라인 경로를 재사용하므로 한도 검사·잔액 검사 로직이 일원화됩니다.

날짜 전환은 대략 다음 시퀀스로 진행됩니다.

[날짜 전환 cut-over 시퀀스 (단순화)]

23:50 선마감 공지 : 일부 채널 거래 제한 안내

23:55 신규 거래 큐잉 시작 : 이후 도착 거래는 익일 기산 큐로 적재

00:00 논리적 날짜 전환 : 시스템 영업일 D → D+1

├─ 큐잉된 거래: D+1 기산일로 온라인 처리 재개

│ (계좌 원장은 계속 살아 있음 — 무중단 전환)

00:05 D일자 거래 확정 스냅샷 → EOD 배치 기동

02:00 원장 검증·GL 전기 완료

04:00 보고서·정보계 적재 완료, EOD 종료 선언

설계상 중요한 결정들입니다.

- **무중단 전환 여부**: 과거에는 마감 중 온라인을 내렸지만, 현재는 대부분 "기산일만 전환하고 온라인은 유지"하는 무중단 마감이 표준입니다. 이를 위해 원장 조회·기재가 영업일 기준으로 분리되어야 합니다(앞 글의 business_date 설계가 여기서 효력을 발휘합니다).

- **마감 시점의 일관성 스냅샷**: 이자 계상은 D일 23:59:59 기준 잔액으로 계산해야 하는데, 온라인이 계속 돌고 있으므로 "D일자 포스팅까지만 합산"하는 논리적 스냅샷으로 해결합니다.

- **큐잉 거래의 SLA**: 날짜 전환 동안 큐에 쌓인 거래는 수 분 내 처리되어야 하며, 큐 적체 모니터링이 필요합니다.

배치 성능 최적화 — 인덱스와 벌크 연산

배치 성능 문제의 대부분은 "온라인용으로 설계된 스키마를 배치가 풀스캔"하는 데서 옵니다.

- **읽기**: 배치 전용 커버링 인덱스 또는 파티션 프루닝을 활용합니다. 일자 파티셔닝된 포스팅 테이블이라면 당일 파티션만 읽도록 합니다.

- **쓰기**: 건건 INSERT 대신 배치 INSERT(JDBC batch, COPY)를 사용합니다. 대량 UPDATE는 임시 테이블에 결과를 만들고 MERGE 하는 편이 빠른 경우가 많습니다.

- **인덱스 유지 비용**: 수백만 건을 적재하는 테이블의 보조 인덱스는 적재 속도를 크게 떨어뜨립니다. 야간 대량 적재 테이블은 인덱스를 최소화하거나, 적재 후 인덱스를 재구성하는 전략을 검토합니다.

-- 행 단위 루프 대신 셋 기반 일괄 이자 누적 (예시)

INSERT INTO interest_accruals (account_id, business_date, accrual_amount)

SELECT b.account_id,

DATE '2026-06-13',

ROUND(b.balance * r.daily_rate, 0)

FROM eod_balance_snapshot b

JOIN product_rates r ON r.product_code = b.product_code

WHERE b.snapshot_date = DATE '2026-06-13'

AND b.balance > 0;

다만 셋 기반으로 갈수록 "어느 계좌에서 왜 이 금액이 나왔는지"의 추적성이 떨어지므로, 산출 근거(적용 금리, 기준 잔액)를 결과 테이블에 함께 저장하는 것이 감사 대응에 유리합니다.

실패 처리 — 부분 재처리와 멱등 설계

새벽 2시에 잡이 죽었을 때, 운영자가 안심하고 누를 수 있는 "재기동 버튼"을 만드는 것이 배치 설계의 절반입니다.

원칙은 세 가지입니다.

1. **재실행 멱등성**: 같은 잡을 같은 파라미터로 두 번 돌려도 결과가 같아야 합니다. 이자 계상이라면 "당일 계상분 삭제 후 재계산" 또는 "계좌+일자 유니크 제약으로 중복 차단" 중 하나를 명시적으로 선택합니다.

2. **체크포인트 기반 부분 재처리**: 청크 커밋 지점이 체크포인트가 되므로, 재기동 시 완료된 청크는 건너뜁니다. Spring Batch의 JobRepository가 이 상태를 관리합니다.

3. **데이터 보정은 보정 잡으로**: 운영자가 SQL로 직접 데이터를 고치는 순간 멱등성과 감사 추적이 깨집니다. 보정도 기록이 남는 잡으로 수행합니다.

-- 멱등성 패턴: 계좌+일자 유니크 제약 + 재실행 시 기존분 정리

ALTER TABLE interest_accruals

ADD CONSTRAINT uq_accrual UNIQUE (account_id, business_date);

-- 재기동 전처리 스텝: 당일 미확정 계상분 삭제 (확정 플래그 보호)

DELETE FROM interest_accruals

WHERE business_date = DATE '2026-06-13'

AND finalized = false;

타기관 인터페이스 잡은 한 단계 더 까다롭습니다. 정산 파일을 이미 전송했는데 잡이 실패로 기록됐다면, 재실행 시 파일이 이중 전송될 수 있습니다. 전송 단계는 "생성-검증-전송-확인"으로 쪼개고, 전송 단계만의 멱등성 키(파일명+일자)를 둡니다.

모니터링 — 배치 SLA와 지연 알림

EOD는 "아침 영업 개시 전 완료"라는 절대 데드라인이 있습니다. 모니터링은 실패 감지보다 **지연 예측**이 중요합니다.

- **크리티컬 패스 관리**: DAG에서 가장 긴 의존 경로를 식별하고, 경로상 잡의 시작·종료 시각을 기준선과 비교합니다.

- **단계별 SLA**: "이자 계상은 01:30까지 시작, 02:30까지 종료" 같은 구간 SLA를 두고, 초과 시 페이저 알림을 보냅니다.

- **처리량 추세**: 같은 잡이 어제보다 2배 느리다면 데이터 증가, 통계 정보 노후, 실행 계획 변경을 의심합니다. 잡별 처리 건수와 소요 시간을 시계열로 적재해 추세를 봅니다.

- **선행 데이터 검증**: 외부 파일이 늦거나 0건으로 도착하는 경우가 흔한 장애 원인입니다. "파일 도착 + 건수 합리성" 체크를 잡 시작 조건으로 둡니다.

배치 현대화 — 준실시간과 클라우드

배치를 모두 실시간으로 바꾸는 것이 현대화가 아닙니다. 현실적인 현대화 방향은 다음과 같습니다.

1. **계산과 확정의 분리**: 이자 "계산"은 온라인 중에도 증분으로 미리 해두고(준실시간 집계), 마감 시점에는 "확정"만 수행해 EOD 윈도우를 줄입니다.

2. **이벤트 기반 전이**: 연체 전이처럼 트리거가 명확한 업무는 일 1회 배치 대신 이벤트(상환 기일 도과) 기반으로 옮길 수 있습니다. 다만 규제 보고 기준 시점과의 정합은 여전히 일 단위 확정이 필요합니다.

3. **클라우드의 배치**: Kubernetes Job/CronJob, AWS Batch, 매니지드 Airflow 등으로 실행 기반을 옮기면 탄력적 병렬도(평소 4노드, 월말 16노드)를 얻습니다. 대신 영업일 캘린더, 재기동 통제, 데이터 인접성(DB와의 네트워크 지연)은 직접 설계해야 합니다.

4. **마감 없는 회계는 없다**: 어떤 아키텍처든 "이 시점 기준으로 숫자를 확정한다"는 회계적 요구는 사라지지 않습니다. 현대화의 목표는 마감의 제거가 아니라 마감 윈도우의 단축과 안정화입니다.

테스트 — 대량 데이터 없이 배치를 믿을 수 없다

배치는 1만 건에서 멀쩡하다가 1천만 건에서 죽습니다. 테스트 전략의 핵심은 운영 규모 데이터입니다.

- **합성 데이터 생성기**: 운영 데이터 분포(계좌 수, 상품 비율, 거래 밀도)를 모사한 생성기를 만들어 성능 테스트 환경을 채웁니다. 개인정보를 복사하는 방식은 마스킹·비식별화 통제가 필요하므로, 처음부터 합성 생성이 깔끔합니다.

- **경계일 테스트**: 월말, 분기말, 연말, 윤년 2월 29일, 휴일 연속 구간(설 연휴 뒤 첫 영업일)은 별도 시나리오로 검증합니다. 휴일 다음 영업일의 이자 계상은 휴일 일수만큼 누적되므로 평일과 결과가 다릅니다.

- **재기동 리허설**: 일부러 중간에 잡을 죽이고 재기동했을 때 결과가 무결한지 — 이중 계상도 누락도 없는지 — 를 정기적으로 검증합니다.

운영 시나리오 — 마감 지연 장애 대응

가상의, 그러나 전형적인 장애 시나리오로 마무리하겠습니다.

[시나리오: 이자 계상 잡 지연]

01:40 이자 계상 잡, 평소 40분 소요 → 60분 경과해도 진행률 55%

01:45 지연 알림 발생. 당직자가 크리티컬 패스 영향 평가

→ 이대로면 GL 전기가 04:30, 영업 개시 전 완료 불가 판단

01:50 원인 분석: 전일 신규 상품 출시로 대상 계좌 30% 증가

+ 통계 정보 미갱신으로 실행 계획 변경(인덱스 → 풀스캔)

02:00 의사결정: 잡 중단 → 통계 갱신 → 체크포인트 재기동

(병렬도 8 → 12 상향, 사전 검증된 상한 내)

02:10 재기동. 완료된 파티션은 스킵되어 잔여분만 처리

03:05 이자 계상 완료, 후행 잡 자동 진행

04:10 EOD 정상 종료. 사후 조치: 상품 출시 시 배치 영향 평가를

출시 체크리스트에 추가, 통계 갱신 잡을 선행 단계로 편입

이 시나리오가 보여주는 것은, 장애 대응 능력이 결국 평소 설계 — 체크포인트, 멱등 재기동, 병렬도 조정 가능성, 크리티컬 패스 가시성 — 에서 나온다는 점입니다.

배치와 온라인의 자원 경합 — 격리 전략

무중단 마감에서는 배치와 온라인이 같은 데이터베이스를 두고 경쟁합니다. 격리 전략 없이 대량 배치를 돌리면 온라인 응답 시간이 튀고, 최악의 경우 락 대기로 채널 거래가 타임아웃됩니다.

실무에서 쓰는 격리 수단을 단계별로 정리하면 다음과 같습니다.

| 수단 | 내용 | 적용 포인트 |

| --- | --- | --- |

| 시간 격리 | 온라인 피크를 피한 윈도우 배정 | 가장 기본, 그러나 24시간 채널에선 한계 |

| 자원 격리 | 배치 전용 커넥션 풀·세션 수 상한 | DB 커넥션 고갈 방지 |

| 읽기 분리 | 읽기 전용 복제본에서 조회성 배치 수행 | 보고서·정보계 적재 |

| 락 최소화 | 짧은 트랜잭션, 청크 커밋, 낙관적 처리 | 원장 갱신 배치 |

| 우선순위 제어 | DB 리소스 매니저로 배치 세션 강등 | 피크 시간 침범 시 보호 |

특히 주의할 패턴이 두 가지 있습니다.

1. **배치의 장시간 트랜잭션**: 100만 건을 한 트랜잭션으로 처리하면 언두(undo) 부담과 락 보유 시간이 폭증합니다. 청크 커밋은 성능 기법이기 이전에 온라인 보호 장치입니다.

2. **온라인과 같은 행을 만지는 배치**: 이자 계상이 갱신하는 계좌 행을 온라인 이체도 갱신한다면, 행 락 순서와 대기 시간 상한(lock timeout)을 명시적으로 설계해야 합니다. 배치가 락을 오래 쥐는 쪽이 되지 않도록, 배치 측에 짧은 타임아웃과 재시도를 둡니다.

잡 설계 표준 — 운영 가능한 배치의 조건

수천 개의 잡을 운영하려면 개별 잡의 품질보다 **표준의 일관성**이 중요합니다. 조직에 하나쯤 있어야 할 잡 설계 표준의 골격입니다.

- **명명 규칙**: 시스템-업무-주기-순번 형태(예: DEP-INTACC-D-010)로 잡 이름만 보고 소속과 주기를 알 수 있게 합니다.

- **파라미터 표준**: 모든 잡은 기준일자(business date)를 명시적 파라미터로 받습니다. "오늘 날짜를 시스템 시계에서 읽는" 잡은 재처리가 불가능한 잡입니다.

- **종료 코드 규약**: 정상(0), 경고성 완료(4), 재기동 가능 실패(8), 개입 필요 실패(16)처럼 스케줄러가 자동 분기할 수 있는 코드 체계를 통일합니다.

- **로그 표준**: 시작·종료 시각, 입력 건수, 처리 건수, 스킵 건수, 기준일자를 구조화 로그로 남깁니다. "처리 건수 = 입력 건수"의 불일치는 그 자체로 알림 대상입니다.

[잡 실행 요약 로그 예시 (구조화)]

job=DEP-INTACC-D-010 business_date=2026-06-13

status=COMPLETED exit_code=0

read_count=10482917 write_count=10482917 skip_count=0

started=01:12:03 ended=01:54:41 duration=42m38s

partition_count=8 restart=false

이 다섯 줄이 매일 쌓이면, 처리량 추세 분석과 지연 예측의 원천 데이터가 됩니다. 반대로 이 표준이 없으면 장애 때마다 잡마다 다른 로그 포맷을 해독하는 데 시간을 씁니다.

일마감 너머 — 월마감, 분기마감, 연마감

EOD 위에는 더 큰 주기의 마감이 겹쳐 있습니다. 월마감(EOM)은 월 단위 이자 결산·수수료 청구·월 보고서를, 분기마감은 자산건전성 확정과 충당금 산정을, 연마감(EOY)은 연간 결산과 이월 처리를 수행합니다.

주기가 겹치는 날 — 예를 들어 12월 31일은 EOD, EOM, 분기마감, EOY가 모두 겹칩니다 — 의 설계가 까다롭습니다.

- **윈도우 산정**: 겹치는 날의 총 소요 시간은 평일의 2~3배가 될 수 있습니다. 최악 조합일 기준으로 윈도우를 산정하고, 평일 기준으로 SLA를 약속하면 안 됩니다.

- **주기 간 의존성**: 월마감은 해당 월 마지막 EOD의 정상 완료를 전제로 합니다. EOD 실패 시 월마감을 자동 보류하는 게이트가 필요합니다.

- **연말 동결 기간**: 많은 기관이 연마감 전후로 배포 동결(freeze)을 운영합니다. 연마감에서만 실행되는 잡은 1년에 한 번만 검증 기회가 있으므로, 연중에 리허설 환경에서 모의 연마감을 돌려보는 것이 사고를 막는 유일한 방법입니다.

[마감 주기의 중첩 (12월 31일의 예)]

EOD (일마감)

└─ EOM (월마감) : 12월분 이자 결산, 월 보고서

└─ EOQ (분기마감): 자산분류 확정, 충당금

└─ EOY (연마감): 연간 결산, 이월, 연 보고서

실행 순서: EOD → EOM → EOQ → EOY (각 단계가 다음의 선행 조건)

함정과 안티패턴

마지막으로, 금융권 배치에서 반복적으로 목격되는 안티패턴을 모았습니다.

1. **시스템 시계 의존**: 잡 내부에서 현재 시각으로 기준일을 정하는 패턴. 재처리 시 어제 날짜로 돌릴 수 없게 됩니다. 기준일은 항상 파라미터로.

2. **암묵적 의존성**: "A잡이 보통 1시에 끝나니까 B잡은 1시 30분에 시작" 같은 시간 기반 의존. A가 지연되는 날 B는 빈 데이터를 처리합니다. 의존성은 반드시 선후행 관계로 선언합니다.

3. **재기동 불가능한 중간 상태**: 임시 테이블을 TRUNCATE 후 적재하는 잡이 중간에 죽으면, 재기동 시 반쯤 빈 테이블에서 시작합니다. 스텝 경계마다 상태가 자기완결적인지 점검합니다.

4. **무한 재시도**: 외부 기관 응답 실패에 무한 재시도를 걸면, 상대 기관 장애 때 우리 쪽 큐와 스레드가 함께 고갈됩니다. 재시도 상한과 수동 개입 전환점을 둡니다.

5. **알림 폭주**: 모든 잡 실패를 같은 채널로 보내면 진짜 크리티컬 알림이 묻힙니다. 크리티컬 패스 잡과 일반 잡의 알림 등급을 분리합니다.

6. **"한 번만 돌리는" 보정 스크립트**: 기록 없는 일회성 SQL 보정은 다음 마감의 대사 불일치로 돌아옵니다. 보정도 잡으로, 기록과 함께.

7. **테스트 환경의 소형 데이터**: 1만 건으로 통과한 성능 테스트는 아무것도 보장하지 않습니다. 실행 계획은 데이터 규모에 따라 달라집니다.

설계 체크리스트

- [ ] EOD 전체 의존성이 DAG로 문서화·코드화되어 있는가

- [ ] 영업일 캘린더(휴일, 월말, 분기말)가 스케줄 정의에 반영되는가

- [ ] 모든 잡이 같은 파라미터로 재실행해도 안전(멱등)한가

- [ ] 체크포인트 재기동 시 완료분 스킵이 검증되어 있는가

- [ ] skip 정책이 업무 특성에 맞게 설정됐는가(금융 핵심 잡은 skip 금지)

- [ ] 파티셔닝 경계가 데이터 분포를 반영하는가

- [ ] 날짜 전환 중 거래 큐잉과 기산일 분리가 동작하는가

- [ ] 마감 검증(차대 평형, 건수 대사)이 후행 잡 진행의 게이트인가

- [ ] 외부 파일 도착·건수 합리성 체크가 잡 시작 조건인가

- [ ] 크리티컬 패스와 단계별 SLA, 지연 알림이 운영되는가

- [ ] 잡별 처리량·소요 시간이 시계열로 축적되는가

- [ ] 운영 규모 합성 데이터로 성능·재기동 리허설을 하는가

- [ ] 경계일(월말·연말·윤일·연휴) 시나리오가 테스트에 포함되는가

- [ ] 수동 데이터 보정 대신 기록이 남는 보정 잡을 쓰는가

마치며

금융권 배치는 낡은 기술이 아니라, "기준 시점에 숫자를 확정한다"는 회계적 요구를 가장 효율적으로 구현하는 형식입니다. 좋은 배치 아키텍처의 본질은 화려한 프레임워크가 아니라 — 의존성의 명시화, 실패를 전제로 한 멱등 재기동, 그리고 새벽 2시의 운영자가 자신 있게 누를 수 있는 재시작 버튼입니다. EOD 윈도우를 줄이고 싶다면 배치를 없애려 하지 말고, 계산을 앞당기고 확정만 마감에 남기는 방향을 먼저 검토하시기 바랍니다.

참고 자료

- Spring Batch 공식 문서: https://docs.spring.io/spring-batch/reference/

- Spring Batch 프로젝트: https://spring.io/projects/spring-batch

- Apache Airflow 공식 문서: https://airflow.apache.org/docs/

- Kubernetes Job 공식 문서: https://kubernetes.io/docs/concepts/workloads/controllers/job/

- Kubernetes CronJob 공식 문서: https://kubernetes.io/docs/concepts/workloads/controllers/cron-job/

- AWS Batch 공식 문서: https://docs.aws.amazon.com/batch/

- PostgreSQL 공식 문서 (파티셔닝): https://www.postgresql.org/docs/current/ddl-partitioning.html

- 금융결제원: https://www.kftc.or.kr/

- 금융감독원: https://www.fss.or.kr/

- BIS (국제결제은행): https://www.bis.org/

- JCP — Batch Applications for the Java Platform (JSR 352): https://jcp.org/en/jsr/detail?id=352

현재 단락 (1/261)

은행 영업점이 문을 닫고 모바일 앱 사용자가 잠든 새벽, 은행의 데이터센터는 하루 중 가장 바쁜 시간을 보냅니다. 수천 개의 배치 잡이 의존성 그래프를 따라 흘러가며 이자를 계산하...

작성 글자: 0원문 글자: 10,977작성 단락: 0/261