Skip to content
Published on

은행 수신 시스템 아키텍처 — 계정계의 심장을 해부하다

Authors

들어가며

은행 IT에서 "계정계"라는 단어는 무게가 다릅니다. 채널이 멈추면 고객이 불편하지만, 계정계가 멈추면 은행이 멈춥니다. 그 계정계의 중심에 있는 것이 바로 수신(예금) 시스템입니다. 고객이 ATM에서 출금 버튼을 누르는 순간부터 원장의 잔액이 갱신되고 거래 내역이 확정되기까지, 그 짧은 수백 밀리초 안에 수십 년간 다듬어진 설계 원칙들이 응축되어 있습니다.

이 글은 코어뱅킹 수신 도메인을 처음 접하는 개발자, 그리고 차세대 프로젝트나 채널 연계 개발에서 계정계를 상대해야 하는 엔지니어를 위해 썼습니다. 수신 업무 도메인의 구조, 원장 테이블 설계, 거래 처리 시퀀스, 동시성 제어, 일마감과 무중단 운영의 공존 문제까지 실무 관점에서 해부해 보겠습니다. 본 글은 일반적인 기술 해설이며 특정 금융기관의 내부 구현이나 투자·법률 자문이 아님을 미리 밝힙니다.

수신 업무 도메인 개관

수신이란 무엇인가

은행 업무는 크게 수신(돈을 받는 업무)과 여신(돈을 빌려주는 업무)으로 나뉩니다. 수신은 고객으로부터 예금을 받아 관리하는 업무 전반을 말하며, 은행 입장에서는 부채(고객에게 돌려줘야 할 돈)입니다. 대표적인 수신 상품은 다음과 같습니다.

상품 유형특징이자 구조핵심 설계 포인트
보통예금(요구불)입출금 자유낮은 변동금리, 결산기 지급고빈도 거래, 동시성 제어
정기예금(거치식)목돈을 일정 기간 예치약정금리, 만기 일시 지급만기 관리, 중도해지 이율
정기적금(적립식)매월 일정액 납입회차별 일할 계산회차 관리, 미납/선납 처리
자유적금자유 납입납입일별 일할 계산건별 이자 계산
MMDA시장금리 연동 수시입출잔액 구간별 차등금리일별 잔액 추적

같은 "예금"이라도 거래 패턴이 완전히 다릅니다. 보통예금은 초당 수천 건의 입출금이 몰리는 고빈도 트랜잭션 도메인이고, 정기예금은 거래 빈도는 낮지만 이자 계산과 만기 처리의 정합성이 생명입니다. 시스템 설계도 이 차이를 반영해야 합니다.

계좌의 수명주기

수신 계좌는 명확한 상태 기계(state machine)를 가집니다.

                  +----------+
   신규(개설)      |          |  거래정지 사유 발생
  ------------->  |  정상     | ----------------------+
                  | (ACTIVE) |                        |
                  +----------+                        v
                    |      ^                    +-----------+
            해지신청 |      | 정지해제            |  거래정지   |
                    |      +------------------- | (BLOCKED) |
                    v                           +-----------+
              +----------+                            |
              |  해지     |  <-------------------------+
              | (CLOSED) |        강제해지(법적사유 등)
              +----------+
                    |
                    v  일정기간 경과
              +----------+        +-----------+
              | 휴면전환  | -----> | 출연/소멸   |
              | (DORMANT)|        | (ESCHEAT) |
              +----------+        +-----------+

실무에서 중요한 것은 상태 전이의 부수 효과입니다. 예를 들어 해지 시점에는 미지급 이자를 정산해서 지급해야 하고, 휴면 전환 시점에는 휴면예금 관리 체계(서민금융진흥원 출연 등)로 넘기는 별도 프로세스가 발동합니다. 상태 전이마다 회계 분개가 따라붙는다는 점이 일반적인 CRUD 애플리케이션과 코어뱅킹의 가장 큰 차이입니다.

계정계, 정보계, 대외계 — 은행 시스템의 3계층

한국 은행 IT는 전통적으로 시스템을 업무 성격에 따라 구분해 왔습니다.

 +-----------------------------------------------------------------+
 |                          채널계 (Channel)                         |
 |   인터넷뱅킹  모바일앱  ATM  창구단말  텔레뱅킹  오픈뱅킹 API          |
 +------------------------------+----------------------------------+
                                |  전문(電文) / API
 +------------------------------v----------------------------------+
 |                          계정계 (Core)                            |
 |  +-----------+  +-----------+  +-----------+  +--------------+   |
 |  |   수신     |  |   여신     |  |   외환     |  |  공통(고객,    |   |
 |  | (예금원장)  |  | (대출원장)  |  | (외화원장)  |  |  상품, 회계)   |   |
 |  +-----------+  +-----------+  +-----------+  +--------------+   |
 +-------+----------------------------------------------+----------+
         | 거래 로그/원장 복제 (CDC, 배치)                   | 대외 전문
 +-------v------------------+  +------------------------v----------+
 |        정보계 (DW/Mart)    |  |           대외계 (External G/W)     |
 |  경영정보  리스크  마케팅    |  |  금융결제원  한국은행  카드망  SWIFT   |
 |  고객분석  규제보고(BIS 등)  |  |  공동망  CMS  오픈뱅킹센터           |
 +---------------------------+  +-----------------------------------+
  • 계정계는 원장(ledger)을 보유한 기록 시스템(System of Record)입니다. 잔액의 진실은 오직 계정계에만 있습니다.
  • 정보계는 계정계 데이터를 복제·가공한 분석 시스템입니다. 경영 보고서, 리스크 측정, 마케팅 캠페인이 여기서 돌고, 계정계의 온라인 성능을 보호하기 위해 조회성 부하를 흡수합니다.
  • 대외계는 금융결제원(KFTC) 공동망, 한국은행망, SWIFT 등 외부 기관과의 전문 송수신을 담당하는 게이트웨이입니다. 타행이체가 가능한 것은 대외계가 있기 때문입니다.

이 구분이 중요한 이유는 데이터 일관성 등급이 다르기 때문입니다. 계정계는 강한 일관성(트랜잭션 ACID)이 필수이고, 정보계는 수 분에서 하루 정도의 지연이 허용됩니다. 채널에서 "어제 기준 평균잔액"을 보여줄 때 계정계를 직접 때리면 안 되는 이유이기도 합니다.

수신 원장 설계 — 테이블로 보는 코어

수신 원장의 뼈대는 세 종류의 테이블입니다. 계좌 마스터, 거래 내역, 그리고 잔액(또는 잔액 이력)입니다. 아래는 개념을 설명하기 위한 단순화된 스키마 예제입니다(실제 차세대 시스템의 컬럼 수는 수백 개에 달합니다).

계좌 마스터

CREATE TABLE deposit_account_master (
    account_no        CHAR(14)      NOT NULL,  -- 계좌번호
    customer_id       VARCHAR(20)   NOT NULL,  -- 고객번호
    product_code      VARCHAR(10)   NOT NULL,  -- 상품코드
    currency_code     CHAR(3)       NOT NULL DEFAULT 'KRW',
    account_status    CHAR(2)       NOT NULL,  -- 01:정상 02:정지 03:해지 04:휴면
    open_date         DATE          NOT NULL,  -- 신규일
    maturity_date     DATE,                    -- 만기일(거치/적립식)
    contract_rate     NUMERIC(7,4),            -- 약정금리(연리, %)
    contract_amount   NUMERIC(17,0),           -- 계약금액(적금 월부금 등)
    last_txn_date     DATE,                    -- 최종거래일(휴면 판정용)
    branch_code       VARCHAR(6)    NOT NULL,  -- 관리점
    passbook_seq      INTEGER       DEFAULT 0, -- 통장 이월 횟수
    created_at        TIMESTAMP     NOT NULL,
    updated_at        TIMESTAMP     NOT NULL,
    CONSTRAINT pk_dam PRIMARY KEY (account_no)
);

CREATE INDEX ix_dam_customer ON deposit_account_master (customer_id);
CREATE INDEX ix_dam_maturity ON deposit_account_master (maturity_date, account_status);

만기일 인덱스는 만기 도래 계좌를 추출하는 일배치의 생명줄입니다. 휴면 판정을 위한 최종거래일 관리도 마스터의 몫입니다.

거래 내역 (저널)

CREATE TABLE deposit_transaction_history (
    account_no        CHAR(14)      NOT NULL,
    txn_date          DATE          NOT NULL,  -- 거래일(영업일 기준)
    txn_seq           INTEGER       NOT NULL,  -- 계좌별 거래일련번호
    txn_datetime      TIMESTAMP     NOT NULL,  -- 시스템 시각
    txn_type          CHAR(2)       NOT NULL,  -- 01:입금 02:출금 03:이자 04:정정
    txn_amount        NUMERIC(17,0) NOT NULL,  -- 거래금액
    balance_after     NUMERIC(17,0) NOT NULL,  -- 거래후잔액(통장인자용)
    counterparty      VARCHAR(60),             -- 적요/상대계좌 표시
    channel_code      CHAR(2)       NOT NULL,  -- 채널 구분(창구/ATM/모바일)
    teller_id         VARCHAR(10),             -- 취급자(창구거래)
    global_txn_id     VARCHAR(32)   NOT NULL,  -- 거래고유번호(전체 추적용)
    reversal_yn       CHAR(1)       NOT NULL DEFAULT 'N',  -- 취소거래 여부
    original_txn_ref  VARCHAR(32),             -- 원거래 참조(취소 시)
    CONSTRAINT pk_dth PRIMARY KEY (account_no, txn_date, txn_seq)
);

CREATE UNIQUE INDEX ux_dth_global ON deposit_transaction_history (global_txn_id);

설계 포인트가 세 가지 있습니다.

  1. 거래 내역은 불변(append-only)입니다. 잘못된 거래는 UPDATE로 고치지 않고 반대 방향의 취소(정정) 거래를 추가합니다. 원장의 감사 추적성은 여기서 나옵니다.
  2. 거래후잔액을 저널에 함께 기록합니다. 통장 인자와 분쟁 대응 때문이기도 하지만, 잔액 검증 배치가 "직전 거래후잔액 + 거래금액 = 당거래후잔액" 체인을 검사하는 데도 쓰입니다.
  3. 거래고유번호(global transaction id)는 채널부터 대외계까지 관통하는 추적 키입니다. 타임아웃 후 결과 조회(원거래 확인)와 중복 방지(idempotency)의 기준이 됩니다.

잔액 관리

CREATE TABLE deposit_balance (
    account_no        CHAR(14)      NOT NULL,
    current_balance   NUMERIC(17,0) NOT NULL,  -- 현재잔액
    available_balance NUMERIC(17,0) NOT NULL,  -- 출금가능잔액
    hold_amount       NUMERIC(17,0) NOT NULL DEFAULT 0,  -- 지급정지/압류금액
    uncleared_amount  NUMERIC(17,0) NOT NULL DEFAULT 0,  -- 미결제타점권(어음/수표)
    last_txn_seq      INTEGER       NOT NULL,  -- 최종 거래일련번호
    version_no        BIGINT        NOT NULL DEFAULT 0,  -- 낙관적 락 버전
    updated_at        TIMESTAMP     NOT NULL,
    CONSTRAINT pk_db PRIMARY KEY (account_no)
);

현재잔액과 출금가능잔액이 다르다는 점이 수신 도메인의 미묘함입니다. 압류·질권 설정 금액, 아직 결제가 끝나지 않은 타점권 입금액은 잔액에는 있어도 출금할 수 없습니다. 출금 가능 여부 판단식은 대략 다음과 같습니다.

출금가능잔액 = 현재잔액 - 지급정지금액 - 미결제타점권 + 마이너스한도(약정 시)
출금 승인 조건: 출금요청금액 <= 출금가능잔액

거래 처리 흐름 — 출금 한 건의 일생

입출금 시퀀스

모바일 앱에서 출금(이체 출금)이 일어날 때의 흐름을 단순화하면 다음과 같습니다.

 고객앱      채널서버        계정계(수신)              DB
   |            |               |                    |
   |--출금요청-->|               |                    |
   |            |--전문(출금)--->|                    |
   |            |               |--1. 계좌상태 검증---->|  (정상? 정지?)
   |            |               |--2. 잔액 행 잠금----->|  SELECT ... FOR UPDATE
   |            |               |--3. 출금가능액 검증-->|
   |            |               |--4. 잔액 차감-------->|  UPDATE balance
   |            |               |--5. 거래내역 INSERT-->|
   |            |               |--6. 회계분개 기록---->|
   |            |               |<------ COMMIT ------|
   |            |<--응답(승인)---|                    |
   |<--완료표시--|               |                    |

핵심은 2번에서 5번까지가 하나의 DB 트랜잭션이라는 점입니다. 잔액 검증과 차감 사이에 다른 거래가 끼어들면 이중 출금이 발생하므로, 검증과 갱신은 반드시 같은 잠금 구간 안에서 이뤄져야 합니다.

비관적 락 — 코어뱅킹의 기본기

전통적인 코어뱅킹은 비관적 락을 씁니다. 잔액 행을 먼저 잠그고 검증·갱신하는 방식입니다.

-- 트랜잭션 시작
BEGIN;

-- 1) 잔액 행을 배타 잠금으로 읽는다
SELECT current_balance, available_balance, last_txn_seq
  FROM deposit_balance
 WHERE account_no = '11012345678901'
   FOR UPDATE;

-- 2) 애플리케이션에서 출금가능액 검증 후 차감
UPDATE deposit_balance
   SET current_balance   = current_balance - 500000,
       available_balance = available_balance - 500000,
       last_txn_seq      = last_txn_seq + 1,
       updated_at        = CURRENT_TIMESTAMP
 WHERE account_no = '11012345678901';

-- 3) 거래내역 기록
INSERT INTO deposit_transaction_history
       (account_no, txn_date, txn_seq, txn_datetime, txn_type,
        txn_amount, balance_after, channel_code, global_txn_id, reversal_yn)
VALUES ('11012345678901', CURRENT_DATE, 124, CURRENT_TIMESTAMP, '02',
        500000, 1500000, '03', 'G20260613000000123456', 'N');

COMMIT;

비관적 락은 정합성이 확실한 대신 핫 어카운트(법인 모계좌, 가상계좌 모계좌처럼 거래가 집중되는 계좌)에서 잠금 대기가 길어집니다. 급여이체일에 특정 법인 계좌로 수만 건이 몰리면 그 계좌의 잔액 행이 직렬화 지점이 됩니다.

낙관적 락과 절충

조회 빈도가 압도적이고 충돌이 드문 영역에서는 버전 컬럼 기반 낙관적 락을 쓰기도 합니다.

UPDATE deposit_balance
   SET current_balance = current_balance - 500000,
       version_no      = version_no + 1
 WHERE account_no = '11012345678901'
   AND version_no  = 42;   -- 읽었던 버전과 같을 때만 성공
-- 갱신 건수가 0이면 충돌 → 재시도

실무 절충안은 다음과 같이 정리할 수 있습니다.

전략적합한 경우위험
비관적 락(FOR UPDATE)일반 입출금, 출금 계열 전반핫 어카운트 잠금 경합
낙관적 락(버전)충돌 드문 갱신, 한도 변경 등재시도 폭주 시 처리량 급락
잔액 차감 조건부 UPDATE단순 차감(가용액 검증 포함)복잡한 검증 로직 표현 한계
계좌 단위 직렬화 큐초고빈도 모계좌인프라 복잡도 증가

조건부 UPDATE는 검증을 SQL 안으로 밀어 넣는 기법입니다.

UPDATE deposit_balance
   SET available_balance = available_balance - 500000,
       current_balance   = current_balance - 500000
 WHERE account_no = '11012345678901'
   AND available_balance >= 500000;  -- 갱신 0건이면 잔액부족으로 거절

이체와 타행 거래 — 금융결제원 공동망

자행이체와 타행이체

같은 은행 내 이체(자행이체)는 출금 계좌와 입금 계좌를 하나의 트랜잭션으로 묶을 수 있습니다(이때도 데드락 방지를 위해 계좌번호 정렬 순서로 잠그는 것이 정석입니다). 문제는 타행이체입니다. 상대 은행의 원장은 우리가 건드릴 수 없으므로, 금융결제원(KFTC)이 운영하는 전자금융공동망을 통해 전문을 주고받습니다.

 A은행(출금측)            금융결제원(중계)            B은행(입금측)
     |                        |                        |
     |--1. 출금(자행 원장)      |                        |
     |--2. 타행입금 요청 전문--->|                        |
     |                        |--3. 입금 요청 전문------->|
     |                        |                        |--4. 입금(B행 원장)
     |                        |<--5. 입금 완료 응답------|
     |<--6. 완료 응답----------|                        |
     |--7. 거래 확정            |                        |
     |                        |                        |
     |          (은행 간 실제 자금은 한국은행 BOK-Wire+    |
     |           차액결제로 별도 시점에 정산된다)            |

중요한 개념 분리가 하나 있습니다. 고객 원장 반영(즉시)과 은행 간 자금 정산(이연 차액결제)은 시점이 다릅니다. 고객은 즉시 입금을 보지만, 은행 간 청산은 한국은행 결제망을 통한 차액결제로 처리됩니다. 그래서 은행은 상대 은행의 결제 불이행 리스크를 관리해야 하고, 이것이 담보·한도 관리 같은 규제 장치로 이어집니다.

타임아웃과 거래 보상

타행 거래의 악몽은 "모름" 상태입니다. 5번 응답이 오지 않으면 입금이 됐는지 안 됐는지 알 수 없습니다. 이때의 대응 패턴은 다음과 같습니다.

  1. 원거래 확인(결과 조회) 전문으로 상대 시스템에 결과를 묻습니다. 거래고유번호가 추적 키입니다.
  2. 그래도 불명이면 보류 처리 후 자동/수동 대사 프로세스로 넘깁니다. 출금은 이미 됐는데 입금 불명이면 고객 자산이 떠 있는 상태이므로 우선순위가 가장 높습니다.
  3. 최종 실패로 확정되면 보상 거래(출금 취소)를 자동 생성합니다. 원거래를 지우는 게 아니라 반대 거래를 추가하는 것이 원칙입니다.

분산 트랜잭션(2PC)을 은행 간에 걸 수는 없으므로, 코어뱅킹의 타행 거래는 본질적으로 보상 트랜잭션(Saga) 패턴의 원조 격이라고 볼 수 있습니다.

온라인과 배치의 이원 구조

수신 시스템은 두 개의 얼굴을 가집니다. 낮(과 밤)의 온라인 거래 처리, 그리고 일 단위의 배치 처리입니다.

구분온라인배치
단위거래 1건계좌 전체 또는 대상 추출분
시간 제약수십에서 수백 ms배치 윈도우(수십 분에서 수 시간)
대표 업무입출금, 이체, 조회이자 계산, 만기 처리, 휴면 전환, 잔액 검증
실패 처리즉시 거절/보상재기동(restart), 구간 재처리

대표적인 일배치(EOD, End of Day) 흐름은 다음과 같습니다.

 [영업일 D 마감 시작]
    1. 온라인 컷오버 준비 (신규 거래의 계리일자를 D+1로 전환)
    2. 미결 거래 정리 (대외 거래 대사, 보류 거래 확정)
    3. 이자 계산 배치 (일적수 적립, 결산 대상 이자 확정)
    4. 만기 도래 처리 (만기 안내, 자동 재예치, 자동 해지)
    5. 휴면/장기미거래 전환 판정
    6. 원장-회계(총계정원장) 대사
    7. 정보계 데이터 전송 (CDC 보정, 일 스냅샷)
    8. 일계표/시재 마감 확정
 [영업일 D+1 개시]

24x7 무중단과 일마감의 공존

과거에는 일마감 동안 온라인을 내렸지만, 지금은 새벽 3시에도 이체가 되는 시대입니다. 무중단과 일마감을 공존시키는 대표 기법은 다음과 같습니다.

  1. 계리일자 전환: 시스템은 멈추지 않고, 자정 또는 마감 시점 이후 거래에 D+1 계리일자를 부여합니다. "오늘"이라는 개념을 거래 시각이 아니라 계리일자로 분리하는 것입니다.
  2. 선일자 버퍼 영역: 마감 배치가 도는 동안 들어온 거래를 별도 버퍼(또는 D+1 파티션)에 기록하고, 마감 완료 후 본 원장 흐름에 합류시킵니다.
  3. 마감 배치의 온라인 친화화: 계좌 전체를 잠그는 대신 파티션 단위로 쪼개 처리하고, 각 파티션 처리 중에도 해당 외 계좌의 온라인 거래는 그대로 흘립니다.
  4. 무정지 원장 전환: 잔액 스냅샷을 D 기준으로 고정(논리적 마감)하고, 이후 거래는 D+1 잔액에만 반영합니다. 일계표 등 마감 산출물은 스냅샷 기준으로 만듭니다.

여기서 자주 터지는 실무 함정이 "마감 중 거래의 이중 반영"입니다. 이자 계산 배치가 잔액을 읽는 시점과 온라인 거래가 잔액을 바꾸는 시점이 겹치면, 일적수(일별 잔액 누계)가 흔들립니다. 그래서 일적수는 현재 잔액을 읽는 것이 아니라 거래 내역 기반으로 재구성 가능해야 하고, 마감 산출물은 반드시 "어느 시점 기준인지"가 명시된 스냅샷에서 나와야 합니다.

성능 요구사항 — 숫자로 보는 계정계

규모가 큰 시중은행 기준으로 흔히 거론되는 수준은 다음과 같습니다(기관·시기마다 차이가 크므로 어디까지나 자릿수 감각입니다).

항목일반적인 목표 수준
평시 계정계 거래량초당 수백에서 수천 건
피크(급여일, 명절 전)평시의 3배에서 10배
온라인 응답시간계정계 내부 처리 100ms 이내, 단순 조회는 더 짧게
가용성 목표연 99.9 퍼센트 이상(계획 정지 제외), 핵심 구간은 더 높게
일배치 윈도우수 시간 이내 완료, 지연 시 영업 개시 리스크

성능 설계에서 코어뱅킹 특유의 포인트는 다음과 같습니다.

  • 읽기 부하 분리: 잔액 조회, 거래내역 조회는 읽기 복제본 또는 정보계로 넘기고, 원장 DB에는 갱신 트랜잭션만 남깁니다. 단, 출금 직전의 잔액 검증은 반드시 원본에서 합니다.
  • 핫 어카운트 대책: 가상계좌 모계좌처럼 갱신이 집중되는 계좌는 잔액을 샤딩(서브 잔액 분할)하거나, 입금 계열은 비동기 집계로 흘리는 설계를 검토합니다.
  • 거래내역 파티셔닝: 거래일 기준 파티셔닝으로 인덱스 깊이를 통제하고, 과거 내역은 아카이브 계층으로 이관합니다.

장애 시나리오와 대응

이중화 구조

        [채널]                     [채널]
           \                         /
        +---v-------------------------v---+
        |        L4/전문 라우팅            |
        +---+-------------------------+---+
            |        (Active)         |        (Active or Standby)
     +------v------+           +------v------+
     |  AP 서버 #1  |           |  AP 서버 #2  |     <- 무상태, 수평 확장
     +------+------+           +------+------+
            |                         |
        +---v-------------------------v---+
        |       원장 DB (Primary)          |
        +---------------+------------------+
                        | 동기 복제
        +---------------v------------------+
        |       원장 DB (Standby)           |  <- 동일 센터 또는 근거리
        +---------------+------------------+
                        | 비동기 복제
        +---------------v------------------+
        |       재해복구(DR) 센터            |  <- 원거리, 정기 전환 훈련
        +-----------------------------------+

원장 DB의 동기 복제 구간은 데이터 무손실(RPO 0)을 노리는 구간이고, DR 센터는 지역 재해 대비입니다. 전자금융감독규정상 재해복구 체계와 목표 복구시간에 대한 요구가 있으므로, 핵심 업무의 RTO/RPO 목표를 정의하고 정기 전환 훈련을 수행하는 것이 일반적입니다.

대표 장애 시나리오

시나리오증상대응
원장 DB 페일오버수 초에서 수십 초 거래 실패자동 페일오버, 채널 재시도 정책, 미결 거래 대사
대외계 회선 단절타행이체 전 건 타임아웃회선 이중화 절체, 보류 처리 후 일괄 대사
핫 어카운트 잠금 폭주특정 계좌 거래 지연 전파큐잉/스로틀, 해당 상품 거래 분리
배치 지연영업 개시 전 마감 미완료배치 재기동 지점 관리, 개시 필수 선행만 우선
중복 전문 유입동일 거래 이중 처리 위험거래고유번호 기반 멱등 처리

멱등 처리는 한 줄로 요약하면 "같은 거래고유번호의 거래는 두 번 와도 한 번만 반영하고, 두 번째에는 첫 번째 결과를 돌려준다"입니다. 거래내역 테이블의 거래고유번호 유니크 인덱스가 마지막 방어선이 됩니다.

테스트 전략

계정계 테스트는 "코드가 도는가"가 아니라 "돈이 맞는가"를 검증해야 합니다.

  1. 정합성 자동 검증: 매 테스트 시나리오 후 (a) 거래내역 합계와 잔액 변동 일치, (b) 거래후잔액 체인 무결성, (c) 원장-회계 분개 대사를 자동 체크하는 어서션을 공통화합니다.
  2. 동시성 테스트: 같은 계좌에 입금과 출금을 동시에 수백 스레드로 퍼붓고 최종 잔액이 산술적으로 정확한지 검증합니다. 잔액 부족 거절 건수까지 합산해서 맞아야 합니다.
  3. 일자 경계 테스트: 마감 직전·마감 중·마감 직후 거래가 계리일자를 올바르게 받는지, 일적수가 흔들리지 않는지를 시나리오로 고정합니다. 시스템 날짜를 주입 가능하게 만드는 것이 선행 조건입니다.
  4. 장애 주입: 커밋 직전 AP 강제 종료, 대외 응답 지연, 중복 전문 재송 같은 케이스를 자동화해 보상·대사 로직을 검증합니다.
  5. 마이그레이션 대사: 차세대·이행 프로젝트라면 신구 시스템에 같은 거래를 흘리고 원장을 전수 비교하는 병행 테스트가 사실상 필수입니다.

용어집

용어영문/표기의미
수신Deposits예금을 받아 관리하는 업무. 은행의 부채 사이드
여신Lending대출 업무. 은행의 자산 사이드
계정계Core Banking System원장을 보유한 기록 시스템
정보계Information System / DW분석·보고용 데이터 시스템
대외계External Gateway외부 기관 전문 연동 시스템
원장Ledger계좌·잔액·거래의 공식 기록
전문Message / Telegram시스템 간 고정 포맷 거래 메시지
계리일자Posting Date회계상 거래가 귀속되는 영업일
일마감EOD Closing영업일 단위 결산·정리 배치
일적수Daily Accumulated Balance일별 잔액의 누계. 이자 계산의 기초
타점권Uncleared Items결제가 끝나지 않은 타행 어음·수표
대사Reconciliation두 기록 간 일치 여부 검증
보상 거래Compensating Transaction원거래를 상쇄하는 반대 거래
휴면예금Dormant Deposits장기 미거래로 휴면 처리된 예금

마치며

수신 시스템은 화려한 기술의 전시장이 아닙니다. 오히려 그 반대로, "잔액은 단 1원도 틀리면 안 된다"는 단순한 명제를 지키기 위해 동시성 제어, 불변 저널, 멱등 처리, 보상 거래, 마감 스냅샷 같은 장치들이 겹겹이 쌓인 구조물입니다. 새로운 아키텍처(MSA, 이벤트 소싱, 클라우드)를 코어뱅킹에 들일 때도 이 본질은 변하지 않습니다. 기술이 바뀌어도 질문은 같습니다. "이 설계에서 돈이 틀릴 수 있는 경로는 어디인가?"

다음 글에서는 수신의 꽃이라 할 수 있는 이자 계산 엔진을 일할 계산, 우대금리, 세금 처리까지 파고들어 보겠습니다.

참고 자료