금융 시스템이 Exactly-Once 대신 보상 트랜잭션을 사용하는 이유

금융 시스템에서 왜 완벽한 일회성 처리가 아닌 보상 트랜잭션을 선택하는가
현대 금융 시스템은 겉보기에는 매우 매끄럽게 작동하는 것처럼 보입니다. 스마트폰 앱으로 버튼 하나만 누르면 해외 송금이 완료되고, 주식 거래는 순식간에 이루어집니다. 하지만 이 화려한 겉모습 뒤에는 ‘데이터의 무결성’을 지키기 위한 치열한 기술적 고민이 숨어 있습니다. 개발자들 사이에서 이상적인 상태로 꼽히는 ‘Exactly Once(정확히 한 번 처리)’가 왜 금융 시스템의 표준이 되지 못하고, 대신 ‘보상 트랜잭션’이라는 복잡한 방식을 사용하는지 그 이유를 파헤쳐 보겠습니다.
분산 시스템의 현실과 제약 사항
금융 시스템은 단일 서버에서 작동하지 않습니다. 고객의 잔액 데이터베이스, 송금 처리 엔진, 외부 은행망, 알림 서비스 등 수많은 서비스가 네트워크를 통해 연결된 ‘분산 시스템’입니다. 분산 시스템에서는 네트워크 지연, 서버 장애, 패킷 유실 등 예기치 못한 문제가 일상적으로 발생합니다.
이론적으로 모든 단계에서 ‘정확히 한 번’만 처리가 일어난다면 데이터 불일치는 발생하지 않을 것입니다. 하지만 이를 실현하려면 ‘2단계 커밋(2PC)’과 같은 강력한 동기식 제어 수단이 필요합니다. 2단계 커밋은 모든 서버가 응답할 때까지 다른 작업을 멈추고 대기해야 하는데, 이는 금융 시스템에서 치명적인 성능 저하를 일으킵니다. 만약 외부 은행 시스템이 응답하지 않으면, 우리 시스템 전체가 마비되는 상황이 올 수도 있습니다. 따라서 금융권은 성능과 가용성을 확보하기 위해 ‘결과적 일관성’을 지향하고, 이를 보완하기 위한 장치로 보상 트랜잭션을 선택합니다.
보상 트랜잭션의 개념과 작동 원리
보상 트랜잭션은 마치 ‘실수를 되돌리는 되감기 버튼’과 같습니다. 전체 과정을 하나의 거대한 단위로 묶는 대신, 각 단계를 독립적인 트랜잭션으로 처리합니다. 만약 중간 단계에서 오류가 발생하면, 앞서 성공했던 작업들을 반대 방향으로 실행하여 상태를 원복시킵니다.
- 단계 1: A 계좌에서 10만 원 인출 (성공)
- 단계 2: 송금 중계 서버로 데이터 전송 (성공)
- 단계 3: B 계좌로 10만 원 입금 (실패)
- 보상 작업: 단계 1에서 인출했던 10만 원을 다시 A 계좌로 입금 (취소 처리)
이 방식의 핵심은 ‘실패를 허용하되, 실패했을 때 어떻게 원래 상태로 되돌릴 것인가’에 집중하는 것입니다. 이를 통해 시스템은 전체를 멈추지 않고도 오류를 능동적으로 해결할 수 있습니다.
흔한 오해와 사실 관계
많은 이들이 보상 트랜잭션을 ‘실수를 사후에 수습하는 비효율적인 방법’이라고 오해합니다. 하지만 이는 실무적인 관점에서의 최선책입니다.
- 오해: 트랜잭션이 완벽하지 않으니 데이터가 꼬일 것이다.
- 사실: 보상 트랜잭션은 데이터가 꼬이지 않도록 ‘상태 관리’를 엄격하게 수행합니다. 작업이 진행 중인지, 완료되었는지, 아니면 취소(보상) 중인지 명확한 상태값을 유지합니다.
- 오해: 성능이 더 느려질 것이다.
- 사실: 동기식 락(Lock)을 걸지 않기 때문에 오히려 처리량(Throughput) 측면에서는 훨씬 빠릅니다.
금융 시스템에서 보상 트랜잭션을 구현할 때의 핵심 팁
보상 트랜잭션을 안정적으로 운영하기 위해서는 몇 가지 설계 원칙이 필요합니다.
멱등성 보장
보상 작업을 여러 번 실행해도 결과가 동일해야 합니다. 예를 들어, ’10만 원을 입금하라’는 명령이 네트워크 재시도로 인해 두 번 전달되어도, 계좌에는 딱 한 번만 입금되어야 합니다. 이를 위해 고유한 ‘트랜잭션 ID’를 생성하고, 이미 처리된 ID인지 확인하는 로직이 필수입니다.
상태 머신 활용
각 거래가 어떤 상태(요청 중, 완료, 보상 중, 보상 완료)에 있는지 추적하는 상태 머신을 구축해야 합니다. 시스템이 갑자기 재부팅되어도, 마지막 상태를 읽어와서 보상 작업을 이어갈 수 있어야 합니다.
오류 추적과 모니터링
보상 트랜잭션이 실패하는 경우도 존재합니다. 예를 들어, 보상 작업을 하려는데 통신 장애가 지속되는 경우입니다. 이때는 사람의 개입이 필요하거나, 강력한 재시도 정책이 담긴 ‘데드 레터 큐(Dead Letter Queue)’를 활용해야 합니다.
비용 효율적인 시스템 설계를 위한 조언
복잡한 보상 트랜잭션을 모든 서비스에 적용하는 것은 비용이 많이 듭니다. 따라서 비즈니스 중요도에 따라 전략을 나누어야 합니다.
| 구분 | 적용 전략 | 특징 |
|---|---|---|
| 핵심 금융 거래 | 보상 트랜잭션 필수 | 데이터 무결성 최우선 |
| 일반 알림/로그 | 비동기 이벤트 처리 | 실패해도 시스템에 영향 없음 |
| 단순 조회 서비스 | 최종 일관성 유지 | 실시간성보다 처리 속도 중요 |
비용 효율성을 높이려면, 데이터가 꼭 실시간으로 일치해야 하는 영역과, 몇 초 정도의 지연이 허용되는 영역을 분리하십시오. 보상 트랜잭션은 데이터 일관성이 필수적인 ‘돈’과 관련된 로직에 집중하고, 나머지는 메시지 큐를 활용한 비동기 방식으로 처리하는 것이 가장 경제적입니다.
전문가가 말하는 보상 트랜잭션의 미래
데이터베이스 전문가들은 앞으로 금융 시스템이 마이크로서비스 아키텍처(MSA)로 더욱 고도화됨에 따라 보상 트랜잭션의 중요성이 더 커질 것이라고 말합니다. 과거의 모놀리식 구조에서는 DB의 트랜잭션 기능에 의존했지만, 이제는 서비스 자체가 스스로 상태를 관리하고 복구하는 능력을 갖춰야 하기 때문입니다.
특히 ‘사가(Saga) 패턴’과 같은 보상 트랜잭션의 표준화된 설계 패턴이 널리 사용되고 있습니다. 사가 패턴은 긴 트랜잭션을 여러 개의 작은 트랜잭션으로 나누고, 각 단계마다 보상 로직을 연결하여 전체의 무결성을 보장합니다. 이는 개발자가 일일이 복구 로직을 짜야 했던 과거보다 훨씬 체계적이고 안정적인 방식입니다.
자주 묻는 질문과 답변
Q1. 보상 트랜잭션 중에 또 오류가 나면 어떻게 하나요?
A1. 보상 작업 자체를 재시도하는 로직을 포함합니다. 만약 보상 작업마저 반복적으로 실패한다면, 해당 거래를 ‘수동 처리 대기’ 상태로 전환하여 운영자가 직접 개입할 수 있도록 알람을 발생시킵니다.
Q2. Exactly Once를 구현하는 기술은 없나요?
A2. 카프카(Kafka)와 같은 메시지 브로커에서 제한적으로 제공하지만, 이는 단일 생태계 내에서의 일회성 보장일 뿐입니다. 서로 다른 은행 시스템이나 외부 연동 서비스까지 포함한 전체 금융 망에서는 여전히 보상 트랜잭션이 유일한 현실적 대안입니다.
Q3. 일반 개발자가 보상 트랜잭션을 시작하려면 무엇부터 공부해야 할까요?
A3. ‘분산 트랜잭션(Distributed Transaction)’과 ‘사가 패턴(Saga Pattern)’을 먼저 학습하세요. 또한, 데이터베이스의 격리 수준(Isolation Level)이 분산 환경에서 어떻게 무너지는지 이해하는 것이 중요합니다.
금융 시스템에서 완벽함이란 ‘오류가 없는 상태’가 아니라, ‘오류를 빠르게 감지하고 안전하게 원래 상태로 되돌릴 수 있는 상태’를 의미합니다. 보상 트랜잭션은 바로 그 유연함과 신뢰성을 동시에 확보하기 위한 금융권의 가장 지혜로운 선택지입니다. 시스템 설계 시 무조건적인 일관성을 좇기보다, 비즈니스 가치와 성능 사이의 균형을 찾기 위해 보상 트랜잭션을 적극적으로 고려해 보시기 바랍니다.




댓글 0
첫 댓글을 남겨보세요.