트랜잭션이란?
트랜잭션이란 ‘더이상 분할이 불가능한 업무처리의 단위’를 의미한다.
한꺼번에 수행되어야 할 일련의 연산모음을 의미한다.
만약 A가 B에게 송금을 하였는데 A는 송금에 성공하였지만, B는 입금에 실패했다하면 안된다.
그러므로 이러한 과정은 동시에 성공하던지, 동시에 실패해야 한다.
이러한 과정같이 데이터 거래에 있어서 안정성을 확보하기 위해 하나의 과정으로 묶는 것이 트랜잭션이다.
따라서 트랜잭션 과정을 통해 오류가 발생한다면 모든 작업을 원상태로 복구(RollBack)하고, 정상적으로 처리가 된다면 그 결과를 반영한다.
데이터베이스에서 CRUD 과정을 통해 값(상태)를 바꿔주는 것 또한 일종의 트랜잭션이다.
잘못된 Query를 작성하게 된다면 실제 반영이 안되기 때문이다.
git의 commit기능 시 오류가 발생하면 반영이 안되는 것과 같다.
이러한 트랜잭션 과정은 사용자가 원하는 기준에 따라 작업단위를 나눌 수 있다.
예를 들어 사용자가 여행 게시판 중 여행 후기 게시판에 글을 작성하고 싶다면
- 메인 페이지에서 게시판 접속(SELECT)
- 게시판에서 여행 후기 게시판 선택(SELECT)
- 여행 후기 게시판에 해당하는 내용이 출력(SELECT)
- 게시글 작성
- 해당 게시판에 게시글이 데이터베이스 등록(INSERT)
이러한 과정들을 통해 4개의 과정을 하나의 트랜잭션으로 분류 할 수도 있다.
트랜잭션 특징
트랜잭션은 크게 4가지로 분류된다.
- 원자성
- 원자성은 트랜잭션이 데이터베이스에 모두 반영되던가, 아니면 전혀 반영되지 않아야 한다.
- 일관성
- 트랜잭션이 진행되는 동안에 DB가 변경되더라도 업데이트된 DB가 아닌, 기존의 트랜잭션을 진행 하기 위해 참조항 DB로 진행되야 한다.
- 독립성
- 트랜잭션이 2개 이상 실행되고 있다면 서로 다른 트랜잭션끼리 접근할 수 없다는것을 말한다.
- 영구성
- 트랜잭션이 성공적으로 처리됬다면 결과는 영구적으로 반영되야한다.
✅ 트랜잭션이 2개 이상 필요한 특수한 경우
🔸 트랜잭션의 4대 특성(ACID) 중
특히 일관성(Consistency), 독립성(Isolation) 을 유지해야 하지만
로직이 복잡하여 트랜잭션을 동시에 2개 이상 사용해야 할 경우,
➡️ @Transactional(propagation = Propagation.REQUIRES_NEW)
어노테이션을 사용하여 트랜잭션을 분리해줄 수 있다.
❗ REQUIRES_NEW 동작 방식
- 기존 트랜잭션을 일시 중단
- 새로운 트랜잭션을 별도로 시작
- 기존 트랜잭션과는 독립적으로 커밋 / 롤백 처리
📌 예:
메인 로직은 실패하더라도 로그 저장은 반드시 수행해야 할 때
→ 로그 저장을 REQUIRES_NEW로 분리하여 개별 트랜잭션으로 처리
⚠️ 주의사항
❗ 성능 주의
- REQUIRES_NEW는 트랜잭션을 중단하고 새로 생성하는 구조라
빈번하게 사용되면 성능에 악영향을 줄 수 있음
❗ 내부 호출 불가
- 아래와 같은 자기 클래스 내부 메서드 호출은
스프링의 프록시 기반 AOP 구조상 트랜잭션 분리가 안됨
→ 반드시 다른 클래스의 메서드로 분리해야 효과가 있음
트랜잭션 예외
모든 명령어는 트랜잭션의 Rollback 처리가 되지 않는다.
DDL(CREATE, DROP, ALTER, RENAME, TRUNCATE)는 대상이 아니다.
Spring Boot에서 @Transaction어노테이션이 붙을 경우 해당 로직이 유효하지 않을 경우 Rollback 처리가 된다.
분산 트랜잭션
분산 트랜잭션이랑 2개 이상의 네트워크 상의 시스템 간의 트랜잭션을 말한다.
여러 테이블들이 실제로는 분리되어있지만 하나의 작업인것처럼 동작을 하는것을 말한다.
분산 트랜잭션은 다른 트랜잭션처럼 ACID를 갖춰야 하고 원자성의 단위를 위해 all-or-nothing결과를 보증해야한다.
단일 데이터베이스에서는 단일 트랜잭션 범위 내에서 원하는 작업 수행이 가능하지만, 데이터베이스에 서로 다른 테이블을 하나의 트랜잭션으로 묶어서 사용하려면 1) 2-Phase Commit과 2) Saga Pattern가 있다.
분산 트랜잭션의 주요 개념
- 트랜잭션 관리자
- 분산 트랜잭션을 조정하는 역할을 한다. 트랜잭션 관리자는 트랜잭션의 시작, commit, rollback을 관리하고 여러 분산된 자원 관리자들을 조정한다.
- 자원 관리자
- DB나 메시지 처리같은 시스템 자원을 관리하는 역할을 한다. 각 자원 관리자는 트랜잭션 관리자와 통신하여 트랜잭션의 상태를 보고한다.
분산 트랜잭션의 종류로는 1) 2-Phase Commit과 2) Saga Pattern가 있다.
Two Phase Commit(2PC)
- 분산 트랜잭션의 일관성을 보장하기 위해 사용되는 프로토콜이다. 2PC는 준비 단계와 커밋 단계로 구성된다.
- 준비 단계 : 트랜잭션 관리자가 각 자원 관리자에게 트랜잭션을 준비하도록 요청하고, 자원 관리자들은 준비가 완료되면 준비 상태를 보고한다.
- 커밋 단계 : 모든 자원 관리자가 준비 완료를 보고하면 트랜잭션 관리자가 각 자원 관리자에게 트랜잭션을 커밋하도록 지시한다. 여기서 하나라도 문제가 발생하면 rollback처리를 하게 된다.
- 적용 예시
- 트랜잭션 시작: 트랜잭션 관리자가 고유한 트랜잭션 ID를 생성하고, 각 자원 관리자(DB)에게 이를 전달하여 트랜잭션을 시작한다.
- 로컬 트랜잭션 작업: 각 자원 관리자(DB)에서 데이터를 작성하거나 수정하는 작업을 수행한다.
- 자원 잠금: 자원 관리자는 트랜잭션이 접근할 데이터에 대해 락을 설정한다.
- 락(Lock)이란 데이터베이스나 분산 시스템에서 데이터의 일관성과 무결성을 보장하기 위해 사용되는 메커니즘이다. 동시에 여러 트랜잭션이 동일한 데이터에 접근하여 변경하는 것을 방지하고, 데이터의 일관성을 유지합니다.
- 준비 요청(Prepare Request): 트랜잭션 관리자가 각 자원 관리자에게 트랜잭션 준비를 요청한다.
- 준비 응답(Prepare Response): 각 자원 관리자는 로컬 트랜잭션이 성공적으로 완료되었고 커밋할 준비가 되었음을 트랜잭션 관리자에게 알린다. 이 응답에는 커밋 가능 여부가 포함된다.
- 커밋 여부 결정(Decision): 트랜잭션 관리자가 모든 자원 관리자로부터 준비 완료 응답을 받으면, 트랜잭션을 커밋하도록 결정한다. 하나라도 실패 응답이 있으면 롤백을 결정한다.
- 커밋 요청(Commit Request): 모든 자원 관리자가 커밋 가능 상태를 보고하면, 트랜잭션 관리자가 각 자원 관리자에게 트랜잭션을 커밋하도록 지시한다.
- 커밋 실행(Commit Execution): 각 자원 관리자는 트랜잭션을 커밋한다.
- 락 해제(Lock Release): 트랜잭션 관리자는 커밋이 완료된 후, 자원 관리자에게 락을 해제하도록 지시한다.
- 롤백(Rollback): 만약 하나라도 실패하거나 타임아웃이 발생하면, 트랜잭션 관리자는 롤백을 한다. DB 중 하나가 다운되면, 다시 회복될 때까지 트랜잭션이 커밋되지 않도록 한다.
- 준비 단계
이러한 2PC가 사용되는 경우는
- 2개의 데이터베이스에 관련된 데이터를 쓰기 작업해야하는 경우
- 메시지큐와 해당 메시지를 처리하는 분산 노드에서 둘다 제대로 처리되었다는 확인이 필요한 경우
2PC의 취약점
만약 트랜잭션 관리자가 다운된다면 사용자가 혼자서 작업 수행을 할 수없다,
또한 테이블이나 데이터에 설정한 락들이 그대로 이어져서 장애로 이어지게 된다.
이러한 문제들이 발생하게 되면 트랜잭션 관리자가 회복할 때까지 기다려서 트랜잭션 로그를 읽어들여 복구하는 수밖에 없다
보완 방법 :
- 트랜잭션 관리자 이중화 :
- 트랜잭션 관리자를 이중화하여 하나의 트랜잭션 관리자가 다운되더라도 다른 관리자가 작업을 이어서 할 수 있도록 한다.
- 이러한 이중화를 통해 시스템의 신뢰성을 높일 수 있을 것이다.
- 타임아웃 설정을 통한 자동 회복 :
- 자원 관리자에 적절한 타임아웃 설정을 통해 일정 시간이 지나면 락을 해제하도록 설정한다.
- 해당 설정을 통해 트랜잭션 관리자가 다운되어도, 새로운 트랜잭션 관리자가 기존 트랜잭션이 수행하는 작업을 이어서 처리할 수 있도록 한다.
SAGA Pattern
Saga 패턴의 주요 개념
- Saga :
- Saga는 일련의 로컬 트랜잭션의 집합으로, 각 트랜잭션은 서로 다른 서비스에서 실행된다.
- 각 로컬 트랜잭션이 성공하여 다음 트랜잭션이 실행되며, 실패하면 보상 트랜잭션을 실행하여 이전 트랜잭션의 변경 사항을 원래 상태로 되돌린다.
- 이러한 보상 트랜잭션을 이벤트/메시지로 소싱하여, 서비스들이 소싱값을 주고 받아 처리하는 것을 SAGA패턴이라고 한다. 트랜잭션의 관리 주체가 DB가 아닌 Application에 있다.
- 로컬 트랜잭션 :
- 각 서비스는 자신의 DB에서 로컬 트랜잭션을 수행한다. 이는 일반적인 ACID기능이 있는 트랜잭션이다.
- 보상 트랜잭션 :
- 2개 이상의 트랜잭션이 처리될 때 여러 단계의 서비스 중 실패한 서비스가 존재한다면 정상적으로 수행된 서비스들의 트랜잭션을 취소 혹은 rollback을 해준다.
- 이러한 SAGA패턴에는 2가지 방식이 있다.
- Choreography(코레오그래피) pattern
- 분산 트랜잭션을 중계하는 중계자가 없는 패턴으로 다음과 같이 동작한다.
- 현재 서비스에서 로컬 트랜잭션을 처리한 후, 다음 서비스에게 처리할 이벤트를 전달
- 다음 서비스에서 처리 후, 각 서비스에서 성공 및 실패 응답을 트랜잭션 관리자에게 전달
- 실패 하는 경우에는 보상 트랜잭션을 실행하여 롤백처리
- 이벤트를 통해 처리하므로 서비스 간의 결합도가 낮다.
- 비교적 구현이 간단하고 확장성이 좋다.
- 서비스마다 구현로직이 다양하므로 흐름에 대한 이해가 필요하다.
- 잘못 구현하는 경우에 순환참조나 복잡한 의존성 문제가 발생할 수 있다.
- 다른 서비스에서 발생할 수 있는 모든 서비스에 대해 인지하고 있어야 한다.
- 전체 시스템이 실행되는 통합테스트가 어려울 수 있고 모든 서비스가 실행되는 시뮬레이션이 필요하다.
@Transactional를 통해 각 메소드를 로컬 트랜잭션으로 처리하고 rollback처리까지 가능하도록 한다.위의 2개의 어노테이션을 통해 로컬 트랜잭션에서 처리한 값이 오류일 경우 연관된 메소드들이 전부 rollback처리가 되도록 한다. - 분산 트랜잭션을 중계하는 중계자가 없는 패턴으로 다음과 같이 동작한다.
- @EventListener를 통해 해당 메소드에서 호출한 다른 메소드와 연관 관계가 설정되어
- Orchestration(오케스트레이션) pattern
- 코레오그래피 패턴과는 달리 분산 트랜잭션을 책임지는 별도의 중계자가 존재하는 패턴이다.
- 별도의 중계자를 오케스트레이터라고 한다.
- 해당 중계자는 모든 트랜잭션을 처리하고 이벤트에 따라 수행할 작업을 사용자에게 알려준다. Saga 요청을 실행하고, 각 작업의 상태를 저장 및 해석하여 보상 트랜잭션을 통해 오류 복구를 처리한다.
- Choreography(코레오그래피) pattern
장점 :
- 많은 서비스 및 추가될 예정인 복잡한 워크플로우에 적합하다.
- 모든 서비스를 제어하고 활동 흐름을 제어할 수 있다.
- 각 서비스에 의존하지 않기 때문에 순환 문제가 발생하지 않는다.
- 각 서비스는 다른 서비스의 명령에 대해 알 필요가 없기 때문에, 비즈니스 논리를 최소화 시킬 수 있다.
단점 :
- 과도한 중앙 집중으로 과부하가 생길 수 있다.
이러한 문제로 SAGA패턴을 적용할 때는 고려사항이 존재한다.
- SAGA 패턴은 트랜잭션을 조정하고, 여러 서비스에 걸친 비즈니스 프로세스에 대한 데이터 일관성을 유지하는 방법에 대해 새로운 사고 방식이 필요하여 러닝커브가 있다.
- 디버깅이 어렵고, 서비스가 증가함에 따라 복잡성이 증가한다.
- 격리에 대한 대책이 필요하다.
✅ 트랜잭션 처리 전략 요약
🔄 SAGA 패턴
📌 1. 코레오그래피(Choreography) 패턴
- 💡 특징: 서비스 간 이벤트 기반으로 느슨하게 연결됨
(예: 신용등급 조회 → 거주지 확인 → 가족 확인) - ✅ 장점
- 서비스 간 결합도 낮음
- 구현이 간단
- ❌ 단점
- 오류 발생 시 문제의 근원 추적 어려움
- 복잡한 비즈니스 흐름에는 부적합
📌 2. 오케스트레이션(Orchestration) 패턴
- 💡 특징: 중앙 컨트롤러(Orchestrator) 가 전체 흐름을 제어
(신용등급 조회, 거주지 확인, 가족 확인을 한 메서드에서 처리) - ✅ 장점
- 명확한 흐름 제어 가능
- 복잡한 워크플로우에 적합
- ❌ 단점
- 중앙 집중 구조로 인해
- CPU / 메모리 부하 발생 가능
- 컨트롤러가 단일 장애점(SPOF) 이 될 수 있음
- 중앙 집중 구조로 인해
🔄 트랜잭션 패턴 선택 기준
| ⚖️ 2PC (Two-Phase Commit) | 강한 일관성이 반드시 보장돼야 할 경우 | 트랜잭션을 양쪽 모두 커밋해야 완료됨 |
| 🔁 SAGA Pattern | 유연성, 확장성이 중요한 경우 | 각 단계별 롤백 처리 가능, 보상 트랜잭션 사용 |
'스터디 > Spring Boot' 카테고리의 다른 글
| BFF패턴과 MVC패턴의 차이점 (0) | 2026.02.25 |
|---|---|
| RDBMS, NoSQL이란 (0) | 2024.08.16 |
| 모놀리식 아키텍처 (0) | 2024.08.15 |
| [Spring Boot] JPA란 (0) | 2024.05.19 |
| [Spring Boot] 스프링 부트란? (0) | 2024.05.19 |