Repeatable Read
Repeatable Read(반복 읽기) 는 트랜잭션 내에서 같은 조회가 항상 동일한 결과를 반환하도록 보장해 재현성을 확보한다.
구현은 MVCC(스냅샷 기반) 또는 잠금 (범위·next-key) 방식으로 나뉘며, 두 방식은 가시성·충돌 처리·성능 특성이 다르다.
RR 은 Dirty Read 와 Non-repeatable Read 를 방지하지만 Phantom(범위 삽입/삭제) 은 엔진별로 다르게 처리된다.
따라서 금융·결산 같은 재현성이 중요한 워크로드에 유리하되, 실제 적용 전 DB 별 동작 확인, 재현 테스트, 성능·교착 검증, 필요 시 부분적 상향 (Serializable) 또는 리포트 분리가 필요하다.
핵심 개념
Repeatable Read 는 하나의 트랜잭션이 같은 쿼리를 여러 번 실행해도 결과가 바뀌지 않도록 보장하는 격리 수준이다.
데이터베이스는 변경 전 상태를 저장 (언두 로그) 하고 각 트랜잭션에 스냅샷을 제공함으로써 이를 구현한다.
다만 구현 방식에 따라 ’ 팬텀 ’ 이나 ’ 쓰기 왜곡 ’ 같은 특수한 동시성 문제가 남을 수 있으므로, 실무에선 사용 전 DB 엔진의 동작을 확인하고 트랜잭션을 짧게 유지하며 모니터링을 준비해야 한다.
| 핵심 개념 (한글·약어) | 정의 (한 문장) | 왜 중요한가 |
|---|---|---|
| 반복 읽기 (Repeatable Read, RR) | 동일 트랜잭션 내 반복 조회 결과의 일관성 보장 | 보고·정산 등 재현성 확보 필요 경로에서 신뢰성 제공 |
| 다중버전동시성제어 (MVCC) | 트랜잭션별 버전을 유지해 읽기 비차단을 제공 | 높은 읽기 동시성·성능 확보 |
| 언두 로그 (Undo Log) | 변경 이전 상태 보관으로 롤백·스냅샷 지원 | 스냅샷/일관적 읽기의 근간 |
| 갭/넥스트키 락 (Gap/Next-key Lock) | 범위 잠금으로 삽입에 의한 팬텀 방지 | 팬텀 차단으로 범위조회 일관성 강화 (엔진 의존) |
| 팬텀 리드 (Phantom Read) | 동일 조건의 조회 결과 행수가 달라지는 현상 | 집계/범위 조회의 일관성 문제 핵심 |
| 쓰기 왜곡 (Write Skew) | MVCC 환경에서 제약 위배를 야기할 수 있는 동시 쓰기 패턴 | RR 에서 놓칠 수 있는 제약 위반 시나리오 |
| 트랜잭션 길이 관리 | 트랜잭션을 짧게 유지하는 운영 규칙 | 장기 트랜잭션으로 인한 락·버전 누적 회피 |
| 데드락/락 대기 모니터링 | 락 충돌·교착을 감시하는 운영 지표 | 문제 조기 탐지·가용성 확보 |
| 엔진별 특성 | DBMS 별 RR 구현 차이 요약 | 동일 표기라도 동작 달라 적용 방식 결정 요인 |
- 핵심 개념들은 이론 (스냅샷·락) 과 운영 (트랜잭션 길이·모니터링) 으로 나뉘며, 실무 적용 시 두 축을 함께 고려해야 안정적으로 운영할 수 있다.
개념 상호관계 및 방향성
| 출발 개념 → 도착 개념 | 관계 유형 (무엇을 위해) | 방향성·설명 |
|---|---|---|
| 언두 로그 → MVCC | 기초 제공 | 언두 로그가 버전 저장을 가능케 하여 MVCC 구현 기반을 제공 |
| MVCC → 스냅샷 | 제공 | MVCC 는 트랜잭션별 스냅샷을 만들어 RR 동작을 가능하게 함 |
| 스냅샷 → RR | 보장 | 스냅샷으로 동일 트랜잭션 내 반복 조회 결과 일관성 보장 |
| 락 (갭) → 팬텀 방지 | 물리적 차단 | gap/next-key lock 은 삽입으로 인한 팬텀을 차단 (락 기반 방식) |
| MVCC ↔ Write Skew | 가능성 제공 | MVCC 는 읽기 비차단을 제공하지만 특정 동시 쓰기 시 write skew 를 허용할 수 있음 |
| 트랜잭션 길이 → 성능/버전 bloat | 영향 | 긴 트랜잭션은 버전 유지 기간을 늘려 MVCC bloat·I/O 증가 유발 |
| 인덱스 설계 → 락 범위 | 영향 | 적절한 인덱스는 스캔 범위를 줄여 락 범위·잠금 대기 감소 |
- 방향성은 ’ 기초 → 구현 → 보장 ‘(Undo→MVCC→Snapshot→RR) 과 ’ 운영 변수 → 영향 ‘(트랜잭션 길이/인덱스 → 성능·락 범위) 으로 구분된다.
- 실무에서는 이 흐름을 이해해 ’ 어떤 요소를 튜닝하면 어느 문제가 완화되는지 ’ 가 명확해져야 한다.
개념별 실무 적용 매핑표
| 개념 | 실무에서 무엇을 (What) | 어떻게 적용 (How) | 왜 중요한가 (Why) |
|---|---|---|---|
| 반복 읽기 (RR) | 보고·정산 트랜잭션의 일관성 확보 | DB 격리 수준 설정 또는 쿼리별 적용 | 재현성 높은 결과로 비즈니스 신뢰성 유지 |
| MVCC | 높은 읽기 동시성 제공 | MVCC 지원 엔진 사용 (설정 없음/엔진 기본) | 읽기 성능 개선, 동시성 확보 |
| 언두 로그 | 스냅샷·롤백 지원 | DB 운영 (undo/undo retention) 모니터링 | 스냅샷 유효성·복구 가능성 보장 |
| 갭 락 | 범위 삽입을 제어 | InnoDB 등에서 범위 락 허용/튜닝 | 팬텀 방지로 집계 일관성 유지 |
| 팬텀 리드 | 집계/범위 조회 신뢰성 문제 | 격리 상향 또는 락/재검증 적용 | 집계 오류·결산 오류 예방 |
| 쓰기 왜곡 | 제약 위반 가능성 | 제약 검증 시 commit-time recheck 또는 상향 격리 | 비즈니스 무결성 보장 |
| 트랜잭션 길이 | 운영 성능 영향 | 트랜잭션 분할, 외부 호출 분리 | 락 유지·버전 bloat 최소화 |
| 데드락 모니터 | 가용성 보호 | Deadlock 탐지·알림·자동 리커버리 | 서비스 중단 방지 |
| 엔진별 특성 | 적용 정책 결정 | 엔진 문서·재현 테스트 후 정책 수립 | 동일 정책의 엔진별 차이 보정 |
- 각 개념은 ’ 무엇을 달성 ’ 하고 ’ 어떻게 적용 ’ 되며 그 결과로 ’ 왜 비즈니스에 중요한지 ’ 가 연결된다.
- 실무 적용은 단순 설정이 아니라 엔진 특성·운영 모니터링·코드 패턴을 함께 설계해야 효과적이다.
기초 조사 및 개념 정립
Repeatable Read 핵심 가이드
Repeatable Read(리피터블 리드) 는 트랜잭션 내부에서 한 번 읽은 데이터가 그 거래가 끝날 때까지 변하지 않도록 보장하는 격리 수준이다.
보통 MVCC(버전 스냅샷) 나 읽기 락을 활용해 구현하며, 이로써 Non-repeatable Read는 방지된다.
그러나 Phantom(같은 조건의 쿼리 결과에 새로운 행이 추가되거나 삭제되는 현상) 은 구현에 따라 다르므로 주의가 필요하다.
실무에서는 다단계 계산이나 중간 검증이 필요한 비즈니스에 적합하지만, 긴 트랜잭션·범위 스캔이 많은 워크로드에서는 성능·운영 비용을 고려해 설계해야 한다.
무엇을 보장하나?
- 동일 트랜잭션 내 같은 행에 대한 반복 조회 시 항상 동일한 값을 반환한다.
어떻게 구현되나?
- MVCC 방식: 트랜잭션 시작 시 스냅샷을 찍어 해당 시점의 커밋된 버전을 계속 읽음 → 언두/버전 저장 필요.
- 락 기반 방식: 읽기 시 공유락을 취득하거나 특정 버전을 고정하여 다른 트랜잭션의 쓰기 가시화를 늦춤.
무엇을 허용/금지하나?
- 금지: Non-repeatable Read (같은 행의 값이 바뀌는 경우).
- 허용 (또는 상황에 따라): Phantom—일부 DB/설정에서는 범위 락으로 방지하지만, 스냅샷형 구현에서는 Phantom 특성이 달라질 수 있음.
실무적 고려사항
- 긴 트랜잭션 금지: 버전 축적·GC 문제로 운영 부담이 커짐.
- 인덱스 설계 중요: 범위 스캔이 많으면 gap/next-key 락 확산 → 인덱스 재검토 필요.
- DB 별 테스트 필수: 동일한 ‘Repeatable Read’ 명칭이라도 구현·옵션별 동작 차이가 크므로 환경별 재현 테스트를 권장.
Repeatable Read 등장배경·발전 흐름
초기 DB 들은 낮은 격리 (RU/RC) 에서 Dirty Read·Non-repeatable Read 같은 문제로 고생했다.
이를 해결하려고 Repeatable Read가 등장했으며, RR 은 트랜잭션 시작 시점의 읽기 뷰 (스냅샷) 를 유지해서 같은 행을 반복 조회할 때 결과가 변하지 않도록 보장한다.
다만 범위 삽입 (팬텀) 은 구현 방식에 따라 달라지므로, 완전한 방지를 원하면 더 강한 격리 (Serializable) 나 락 전략을 고려해야 한다.
등장 배경
문제 상황: 초기 RDBMS 와 낮은 격리 수준 (READ UNCOMMITTED, READ COMMITTED) 에서는 미커밋 데이터 노출과 같은 트랜잭션 내 반복 조회 결과 불일치가 잦았다. 이로 인해 금융·회계 같은 도메인에서 심각한 오류가 발생했다.
요구: " 한 트랜잭션 내에서 같은 조회는 동일한 결과를 보여야 한다 " 는 요구가 커졌다 → Repeatable Read 채택으로 이어짐.
발전 과정 표
| 시기 (개괄) | 변화/기능 | 왜 등장했나 (문제) | 실무적 효과 |
|---|---|---|---|
| 초기 RDBMS | READ UNCOMMITTED / READ COMMITTED 사용 | Dirty Read, Non-repeatable 문제 | 성능은 좋지만 정합성 약함 |
| RR 도입 (엔진별) | RR: 트랜잭션 스냅샷 또는 락 기반 제어 도입 | 반복 조회 일관성 요구 | Dirty/Non-repeatable 차단 |
| InnoDB 확장 | Next-key / Gap Lock 도입 (팬텀 제어) | 범위 삽입 (팬텀) 문제 해결 필요 | 팬텀 방지, 레플리케이션 일관성 향상. |
| MVCC·언두 개선 | MVCC + 언두 로그 정교화 | 읽기 비차단·성능 확보 | 읽기 성능 유지하며 일관성 제공. |
| 최신 (SSI/Serializable) | SSI/Serializable 도입으로 더 강한 일관성 옵션 | 특정 동시성 이상 (쓰기왜곡 등) 차단 | 더 엄격한 격리 (대가: 재시도·성능 비용). |
timeline
title Repeatable Read 등장·발전 타임라인
1970s-1990s : 초기 RDBMS (RU/RC 사용)
1990s-2000s : Repeatable Read 개념/도입 (트랜잭션 스냅샷)
2000s : InnoDB next-key / gap lock 도입 → 팬텀 제어 강화
2000s-2010s : MVCC·언두/히스토리 개선으로 읽기 비차단 최적화
2010s+ : SSI/Serializable 및 DB별 고급 옵션 도입 (정합성 강화)
RR 은 RC 에서 발생하는 반복불가 문제를 해결하려는 실무적 요구에서 태어났고, 그 이후 MVCC 의 보급과 갭/next-key 락 같은 기술이 결합되며 점차 현재의 형태로 발전했다.
현대 DB 는 RR 을 구현하면서도 **읽기 성능 (비차단)**을 유지하려는 최적화를 계속해왔고, 필요에 따라 더 엄격한 일관성 (Serializable/SSI) 을 선택할 수 있게 됐다. 다음 단계로는 엔진별 세부 버전·행동을 문서화해 타임라인을 정확히 채워넣는 작업이 필요하다.
Repeatable Read: 문제·목적·연결
Repeatable Read 는 " 한 트랜잭션이 같은 데이터를 여러 번 읽으면 항상 같은 값을 보게 하는 “ 격리 수준이다.
이렇게 하면 중간에 다른 트랜잭션이 값을 바꿔서 생기는 오류 (Non-repeatable Read) 를 막을 수 있다.
구현은 주로 **MVCC(버전 스냅샷)**나 **잠금 (락)**으로 이루어지며, 재무·재고·정산처럼 정확성이 중요한 업무에서 사용된다.
일부 데이터베이스는 추가 메커니즘으로 팬텀 (범위에 새로 생긴 행) 문제까지 억제해 더 강한 읽기 일관성을 제공하기도 한다.
Repeatable Read 가 해결하는 문제들
| 해결 문제 | 문제의 본질 | Repeatable Read 가 어떻게 해결하는가 | 실무 효과 |
|---|---|---|---|
| Dirty Read | 미커밋 데이터를 읽어 잘못된 산출/결정 발생 | 커밋된 버전만 가시화 (미커밋 숨김) | 잘못된 업무 결정을 방지 |
| Non-repeatable Read | 동일 트랜잭션 내 재조회 시 값이 변경됨 | 트랜잭션 스냅샷/버전으로 동일 값 반환 | 재조회 기반 연산의 일관성 확보 |
| Phantom (일부 구현) | 동일 조건의 재조회에서 행 집합이 달라짐 | 범위락/갱신 전략으로 새 행 노출 억제 | 범위 기반 계산 (합계 등) 의 안정성 향상 |
Repeatable Read 는 트랜잭션 수준의 재현 가능한 읽기 일관성을 목표로 하며, Dirty Read 는 완전히 차단하고 Non-repeatable Read 를 직접 해결한다. 팬텀 문제는 표준상 허용되지만, 일부 DB 는 범위락이나 내부 최적화로 이를 억제해 범위 기반 연산의 안정성까지 향상시킨다.
Repeatable Read 의 핵심 목적
| 핵심 목적 | 구체 설명 | 기대 효과 |
|---|---|---|
| 재조회 일관성 보장 | 한 트랜잭션 내 동일한 조회가 항상 같은 결과를 반환하도록 보장 | 트랜잭션 기반 로직 (계산·검증) 신뢰성 확보 |
| 데이터 신뢰성 확보 | 미커밋 값의 노출 차단을 통해 잘못된 처리 방지 | 오류/보정 비용 절감 |
| 애플리케이션 안전성 지원 | 복잡한 트랜잭션 로직의 안정적 실행을 용이하게 함 | 운영·디버깅 간소화 |
핵심 목적은 트랜잭션 단위에서의 예측 가능한 동작 보장에 있다. 이는 재무·재고·정산과 같이 반복 조회와 일관성이 핵심인 비즈니스 로직에서 직접적으로 가치가 된다.
문제와 목적의 연관성 매핑표
| 해결 문제 | 관련 핵심 목적 | 연관 방식 (간단 설명) |
|---|---|---|
| Dirty Read 차단 | 데이터 신뢰성 확보 | 미커밋 값 숨김 → 신뢰 가능한 입력 보장 |
| Non-repeatable Read 방지 | 재조회 일관성 보장 | 스냅샷/버전 유지 → 동일 조회 결과 보장 |
| Phantom 억제 (구현 경우) | 애플리케이션 안전성 지원 | 범위 안정성 → 범위 기반 집계/검증 안전화 |
각 해결 문제는 특정 핵심 목적과 직접 연결된다. 예를 들어 Non-repeatable Read 를 막는 것은 재조회 일관성 보장 목적을 달성하기 위한 수단이며, Dirty Read 차단은 데이터 신뢰성 확보로 직결된다. 따라서 설계자는 해결하려는 문제 (예: 재고 정확성) 에서 출발해 적절한 격리 수준 (Repeatable Read 등) 을 선택해야 한다.
Repeatable Read 적용 전제와 운영 요건
Repeatable Read 를 안정적으로 쓰려면 DB 가 트랜잭션과 버전 (undo/MVCC) 을 잘 지원해야 하고, 쿼리·인덱스·트랜잭션 설계를 신중히 해야 한다.
트랜잭션은 짧게 유지하고, 잠금·버전 비용을 모니터링하며 타임아웃과 재시도 정책을 마련해야 실무에서 성능 저하·교착을 피할 수 있다. 또한 DB 별 차이를 테스트해 정책을 문서화하라.
Repeatable Read 적용 전제·요구사항 표
| 항목 | 설명 | 근거 (왜 필요한가) | 검증 방법 | 완화/대응 방안 |
|---|---|---|---|---|
| 트랜잭션 지원 RDBMS | ACID 트랜잭션을 제공하는 DB | 트랜잭션 원자성·격리성 필요 | DB 문서 확인, 간단 트랜잭션 실험 | 트랜잭션 미지원 DB 는 다른 설계 (이벤트 기반) 사용 |
| MVCC 또는 언두 로그 | 스냅샷/버전 관리 가능 | 반복 읽기 보장 (스냅샷) 또는 락으로 대체 | 버전 스토어 확인, long tx 영향 테스트 | 버전 스토어 사이징·GC 튜닝 |
| 인덱스 설계 적합성 | 조건·범위에 맞는 인덱스 존재 | 범위 스캔·락 확대 방지 | 쿼리 플랜 확인, EXPLAIN 분석 | 인덱스 추가·쿼리 리팩토링 |
| 트랜잭션 범위 최소화 | 짧고 한정된 트랜잭션 유지 | 장기 트랜잭션이 버전·락 부담 증가 | 트랜잭션 길이 모니터링 (평균 지속시간) | 작업 분할, 비동기화, 배치화 |
| 타임아웃·재시도 정책 | 자동 타임아웃 및 재시도 구현 | 교착/경합시 자동 복구 필요 | 데드락·타임아웃 시나리오 테스트 | 지수 백오프·idempotency 설계 |
| 모니터링 지표 | undo size, lock wait, deadlocks 등 | 문제 조기탐지 및 원인 파악 | 모니터링 대시보드·경보 설정 | 자동 알람·가드레일 (서비스 비활성화 등) |
| DB 별 특성 검증 | 갭락/next-key, RCSI, SSI 등 확인 | 동일 설정이라도 동작·부작용 상이 | 벤더 매뉴얼·실험 (사전 A/B 테스트) | 설정 변경 전 파일럿·성능 테스트 |
Repeatable Read 는 단순히 격리 수준 선택만으로 끝나지 않는다. DB 의 내부 메커니즘 (MVCC vs 락), 인덱스·쿼리 설계, 트랜잭션 길이, 버전 스토어 관리, 모니터링·재시도 정책이 모두 함께 맞물려야 안정적으로 운영할 수 있다. 적용 전에는 대상 DB 에서 실제 워크로드로 검증 (A/B 테스트, 모니터링 수치 확보) 을 반드시 수행하라.
Repeatable Read: 근거·차별·운영 포인트
Repeatable Read 는 트랜잭션 내에서 같은 조회가 항상 같은 결과를 주도록 보장해 재현성을 확보한다.
구현은 MVCC(스냅샷) 나 범위/next-key 락으로 나뉘며, Dirty Read 와 Non-repeatable Read 를 차단한다.
Phantom 방지는 DB 엔진별 (예: InnoDB 의 갭 락, PostgreSQL 의 스냅샷) 로 달라지므로 적용 전 벤더 동작을 확인해야 한다.
Repeatable Read 특징·근거·차별표
| 특징 | 간단 설명 | 기술적 근거 | 다른 격리 수준 대비 차별점 |
|---|---|---|---|
| 반복 조회 일관성 | 트랜잭션 내 동일 쿼리 결과 고정 | 트랜잭션 스냅샷 (MVCC) 또는 읽은 행 락 유지. | RC 보다 일관성 강함, Serializable 보다 동시성 우수 |
| Dirty/Non-repeatable 차단 | 미커밋 데이터 노출·재조회 값 변화 방지 | 가시성 규칙 (커밋 기준) 또는 락 유지. | RC 에서는 불가, RR 에서 보장 |
| Phantom 처리 (엔진별) | 범위 질의의 행 추가/삭제 문제는 엔진별로 달라짐 | InnoDB: next-key(gap) lock. PostgreSQL: 스냅샷 기반 일관성. | 일부 엔진에서는 Phantom 차단, 일부는 추가 조치 필요 |
| 성능/교착 트레이드오프 | 더 강한 일관성으로 락·교착 증가 가능 | 락 유지 시간/범위 또는 버전 보관으로 리소스 사용 증가 | Serializable 보다 덜 엄격하나 RC 보다 비용 ↑ |
| RR vs SI | 유사하지만 세부 동시성 이슈 차이 | SI 는 write-skew 유형에 대해 다른 거동 | SI 는 특정 쓰기 충돌 시 행동이 RR 과 다름. |
Repeatable Read 는 재현성을 핵심으로 하는 격리 수준이며, 이를 위해 MVCC 스냅샷 또는 범위 락 같은 기술을 사용한다.
Phantom 관련 거동은 DB 엔진에 따라 다르므로, 실무 적용 전 벤더 문서 확인 + 재현 테스트가 반드시 필요하다.
핵심 원리 및 이론적 기반
Repeatable Read 설계 원칙·운영 철학
Repeatable Read 는 트랜잭션 내에서 동일 데이터를 여러 번 읽더라도 같은 값이 보이도록 보장하는 격리 수준이다. 이를 위해 흔히 MVCC(스냅샷) 을 사용하거나 읽기 중 해당 행을 고정한다. 목표는 다단계 연산 시 일관성을 보장하면서도 전체 시스템의 동시성을 가능한 유지하는 것이다. 실제 설계에서는 트랜잭션을 짧게 유지하고 (언두·버전 축적 방지), 쿼리·인덱스 패턴을 최적화하며, 재시도·멱등성 전략과 모니터링을 병행해 운영 리스크를 관리한다.
Repeatable Read 핵심원칙 표
| 핵심 원칙 | 설명 | 목적 | 왜 필요한가 | 실무 적용 예 |
|---|---|---|---|---|
| 반복 읽기 보장 | 트랜잭션 내 동일 행 반복 조회 시 동일 값 보장 | 다단계 연산의 일관성 확보 | 중간 연산값의 변동으로 인한 로직 오류 방지 | 결제 검증, 계정 잔액 확인 |
| 스냅샷/MVCC 또는 읽기 락 | 트랜잭션 시작 시 스냅샷 고정 또는 행 고정 | 읽기와 쓰기 분리로 일관성 제공 | 공유락에 의한 경합 완화 · 일관성 확보 | PostgreSQL 스냅샷, InnoDB 버전 |
| 트랜잭션 길이 최소화 | 외부 I/O·대용량 연산 분리 | 언두/버전 축적 방지·락 지속시간 감소 | 운영 부하·deadlock 위험 완화 | 짧은 트랜잭션, 배치 분해 |
| 인덱스·쿼리 최적화 | 범위 스캔 최소화, 적절한 인덱스 사용 | gap/next-key 락 확산 방지 | 락 범위 축소로 동시성 유지 | WHERE 절 인덱스 정렬 |
| 멱등성·재시도 설계 | 충돌 시 안전한 재시행 로직 | 동시성 실패 복구·무결성 유지 | 자동 재시도로 사용자 영향 최소화 | idempotency key, 보상 트랜잭션 |
Repeatable Read 의 핵심은 " 트랜잭션 내부 일관성 유지 " 다. 이를 효과적으로 운영하려면 스냅샷/락 메커니즘을 이해하고, 트랜잭션을 짧게 설계하며 인덱스·쿼리를 최적화하고 재시도·멱등 패턴을 적용해야 실제 서비스에서 성능 저하 없이 안전하게 사용할 수 있다.
Repeatable Read 설계 철학 표
| 설계 철학 | 설명 | 목적 | 왜 필요한가 | 적용 시 고려사항 |
|---|---|---|---|---|
| 읽기 안정성 vs 동시성 균형 | 일관성을 보장하되 전체 처리량을 해치지 않음 | 현실적 안정성과 성능 확보 | 완전 직렬화의 비용을 피하기 위해 | 서비스별 정책 선언 필요 |
| 읽기 우대 비용 편향 | 읽기 일관성 확보를 우선하되 오버헤드 최소화 (MVCC) | 읽기 중심 워크로드에 적합 | 대부분 서비스가 읽기 비중이 높음 | 버전/언두 관리 필요 |
| 운영 예방 우선 | 설계 단계에서 긴 tx 차단·모니터링·자동화 내장 | 장애 예방과 빠른 복구 | 동시성 문제의 탐지·해결 비용 절감 | 자동 알람·격상 플로우 필요 |
| 명시적 테스트 문화 | DB 별 동작 문서화·CI 에 회귀 테스트 포함 | 배포 안전성 확보 | 같은 명칭의 동작 차이로 인한 버그 방지 | 동시성 시나리오 표준화 |
설계 철학은 단순한 기술 선택을 넘어 조직의 정책·운영·테스트 문화와 연결된다. Repeatable Read 를 적용할 때는 ’ 어디까지 일관성을 보장할지 ‘, ’ 성능 손해를 어느 수준까지 허용할지 ’ 에 대한 명확한 기준을 세우고 이를 기술·운영·테스트 관점에서 일관되게 구현해야 한다.
Repeatable Read: 원리·구현·운영포인트
Repeatable Read 는 " 한 트랜잭션 안에서 같은 데이터를 여러 번 읽으면 항상 같은 결과를 본다 " 는 약속을 제공하는 격리 수준이다.
이를 위해 DB 는 읽기 시점의 스냅샷(혹은 락) 을 사용해 다른 트랜잭션의 중간 변경을 숨긴다.
결과적으로 같은 트랜잭션에서 값이 바뀌는 문제 (Non-repeatable Read) 는 사라지지만, 범위 (행 집합) 가 바뀌는 팬텀 문제는 DB 구현에 따라 다르게 처리된다.
실무에서는 RR 을 쓰되 트랜잭션을 짧게 유지하고 장기 트랜잭션을 모니터링해야 한다.
RR 핵심 메커니즘 요약표
| 메커니즘 | 동작 요약 | 방지/허용되는 이상현상 | 실무적 고려사항 |
|---|---|---|---|
| 스냅샷 생성 (스냅샷 뷰) | 트랜잭션 시작 (또는 첫 SELECT) 시점의 읽기 뷰 확보 | Non-Repeatable Read 차단, Dirty Read 차단 | 스냅샷 시점 규칙 (문장 vs 트랜잭션) 확인 필요 |
| 언두/버전 보존 | 변경 전 값 (구버전) 을 보존해 스냅샷 복원 | 읽기 비차단으로 일관성 유지 | 장기 트랜잭션이 버전 보존 기간 연장 → 스토리지 증가 |
| 락 기반 (Next-key / Gap lock) | 범위 (갭) 에 락을 걸어 삽입 차단 | Phantom(범위 삽입) 차단 가능 | 락 오버헤드·대기·데드락 유발 가능 |
| MVCC 기반 | 버전 스냅샷으로 읽기 제공 (비차단) | Dirty/Non-repeatable 차단, Phantom 은 구현 의존 | GC·vacuum 필요, 장기 txn 영향 주시 |
| 커밋 가시성 규칙 | 커밋된 버전만 다른 트랜잭션에 가시 | 가시성 일관성 보장 | 커밋 타이밍과 스냅샷 정책 이해 필요 |
| 가비지 컬렉션 (GC) | 오래된 버전 정리 (자동 또는 수동) | 스토리지/성능 회복 | GC 가 늦어지면 읽기 성능 악화·디스크 사용량 증가 |
- RR 핵심은 스냅샷 (또는 범위락) 으로 " 읽는 시점의 일관성 " 을 보장하는 것.
- 운영 관점에서 가장 중요한 위험은 장기 트랜잭션 → 버전 보존 연장 → GC/스토리지 부담이며, 락 기반 구현은 락 오버헤드·데드락을 유발할 수 있다.
- 따라서 RR 도입 시 엔진별 스냅샷 정책·락 전략·GC 동작을 먼저 확인해야 한다.
RR 동작 흐름: 락 Vs MVCC
flowchart TD
subgraph LockBased["락 기반 RR"]
A1["T1: SELECT (range) -> acquire next-key/gap lock"]
B1[T2: INSERT within range] -->|blocked| A1
A1 --> C1["T1: 작업 계속 (동일 결과 보장)"]
B1 -->|unblocked after T1 commit| D1[T2: INSERT succeeds]
end
subgraph MVCC["MVCC 기반 RR"]
A2[T1: start -> create snapshot S]
B2[T2: INSERT x=15 -> commit]
A2 --> C2[T1: SELECT reads from S -> new row invisible]
B2 --> D2[T2: committed version visible to new txns]
C2 --> E2[T1: subsequent SELECT still uses S]
end
락 기반 분기: T1 이 범위에 대해 next-key/gap lock 을 획득하면 T2 의 범위 삽입은 블록된다 (팬텀 방지). 이 방식은 팬텀을 강하게 막지만 락 대기·교착 위험이 있다.
MVCC 분기: T1 은 시작 시 (또는 첫 읽기 시) 스냅샷 S 를 갖고 이후의 SELECT 는 S 기준으로 읽는다. T2 가 삽입·커밋하더라도 T1 은 자신의 스냅샷에 없던 새 행을 보지 못한다. MVCC 는 읽기 비차단으로 성능이 좋으나, 오래된 스냅샷이 버전 보존을 요구한다는 점에 유의해야 한다.
Repeatable Read: 흐름·상태·운영포인트
- 트랜잭션 A 가 어떤 데이터를 읽으면, A 가 끝날 때까지 같은 조회는 같은 결과를 보여준다.
- 이를 위해 DB 는 (1) 조회 범위를 잠그거나 또는 (2) 시작 시점의 스냅샷을 고정한다.
- 결과: 중간에 다른 트랜잭션이 데이터를 넣어도 A 는 그 변화를 보지 않아 재조회 일관성이 보장된다.
- 단점: 범위 잠금은 다른 트랜잭션을 블로킹할 수 있고, 스냅샷은 오래 유지되면 디스크/메모리 부담이 커진다.
RR 의 데이터·제어 흐름 (상세)
핵심 단계 (락 기반)
- T1 이
SELECT … WHERE x BETWEEN a AND b시작 → DB 가 해당 범위에 범위/넥스트키 락을 설정 (또는 공유 락 유지). - T1 은 조회 결과를 받고, 락은 트랜잭션 종료 시까지 유지되어 다른 트랜잭션의 INSERT/DELETE 를 차단.
- T2 가 해당 범위에 INSERT 시도 → 락 때문에 대기 또는 오류 발생 (정책에 따름).
- T1 이 COMMIT/ROLLBACK → 락 해제 → 대기 중이던 T2 가 진행.
핵심 단계 (MVCC / 스냅샷 기반)
- T1 시작 → DB 는 현재 커밋된 상태를 기준으로 스냅샷 S를 생성 (트랜잭션 수준 또는 statement 수준).
- T1 의 SELECT 는 스냅샷 S 에 보이는 버전만 반환 (신규 커밋된 행은 보이지 않음).
- T2 가 INSERT → 커밋해도, T1 은 자신의 스냅샷을 유지하므로 재조회 시에도 해당 신규 행을 보지 않음.
- T1 종료 → 스냅샷 폐기 → 버전 정리 (garbage collection / undo cleanup).
RR 데이터·제어 흐름 요약표
| 단계 | 락 기반 동작 | MVCC(스냅샷) 동작 | 가시성 규칙 | 운영 관찰 포인트 |
|---|---|---|---|---|
| 트랜잭션 시작 | 트랜잭션 범위 잠금 준비 | 트랜잭션/문 스냅샷 확보 | 이후 재조회는 잠금/스냅샷 기준 | 트랜잭션 길이 |
| 첫 SELECT | 범위/넥스트키 락 획득 | 스냅샷 버전으로 스캔 | 미커밋 변경은 숨김 | 락 웨이트 / 버전 저장량 |
| 동시 INSERT | 대기 또는 차단 | INSERT 는 수행·커밋 가능 (다른 트랜잭션에 나타남) | 락 기반은 차단, MVCC 는 보이지 않음 | 대기 큐 / 언두 성장 |
| 재조회 | 동일 결과 반환 | 동일 스냅샷으로 동일 반환 | 재조회 일관성 보장 | 재현성 테스트 지표 |
| 트랜잭션 종료 | 락 해제 | 스냅샷 폐기·버전 GC | 다른 트랜잭션에 변화 노출 가능 | GC/언두 정리 시간 |
표는 RR 의 두 구현 축 (락 기반 vs MVCC) 을 단계별로 비교해 가시성 규칙과 운영상 주의점을 정리한 것이다. 운영에서는 **장기 트랜잭션 (버전 누적)**과 **락 웨이트 (대기)**를 반드시 모니터링해야 하며, 워크로드에 따라 적절한 구현 (혹은 DB 옵션) 을 선택해야 한다.
RR 구현 흐름 비교도
flowchart LR
subgraph LockBased["락 기반 구현"]
A1[T1: SELECT 범위] --> A2[DB: 범위/넥스트키 락 획득]
A2 --> A3[T2: INSERT 같은 범위 시도]
A3 --> A4[DB: T2 대기/차단]
A4 --> A5[T1: COMMIT/ROLLBACK]
A5 --> A6[DB: 락 해제 -> T2 진행]
end
subgraph MVCC["MVCC/스냅샷 구현"]
B1[T1 시작] --> B2[DB: 스냅샷 S 확보]
B2 --> B3[T1: SELECT -> S 기준 반환]
B3 --> B4[T2: INSERT 및 COMMIT]
B4 --> B5[T1: 재조회 -> 여전히 S 기준]
B5 --> B6[T1: COMMIT -> 스냅샷 폐기]
end
위 흐름도는 RR 의 두 구현 경로를 병렬로 보여준다. 락 기반은 범위 락을 통해 동시 삽입을 차단해 팬텀을 예방하고, MVCC 는 스냅샷을 통해 읽기 비차단을 유지하면서도 재조회 일관성을 보장한다. 각각의 장단점 (락 경합 vs 버전 누적) 을 운영에서 균형 있게 관리해야 한다.
RR 트랜잭션 생명주기도
stateDiagram-v2
[*] --> Active: 트랜잭션 시작
Active --> Acquire: 스냅샷/락 획득
Acquire --> Read: 읽기 수행 (가시성 적용)
Read --> Continued: 추가 문 반복 (새 가시성 없음)
Continued --> Commit: COMMIT
Continued --> Rollback: ROLLBACK
Commit --> Release: 락 해제/스냅샷 폐기
Rollback --> Release
Release --> [*]
트랜잭션은 시작 후 가시성 기준을 획득 (스냅샷 또는 락) 하고, 그 기준을 유지하며 여러 문을 실행한다. 트랜잭션이 끝나면 가시성 자원을 반환 (락 해제/스냅샷 폐기) 하여 시스템 일관성이 유지된다. 이 생명주기 동안 자원 (락·버전) 이 오래 유지되면 다른 트랜잭션 성능에 영향을 줄 수 있다.
특성 분석 및 평가
RR 장점·실무 적용 요약
Repeatable Read 는 한 트랜잭션이 같은 쿼리를 여러 번 실행해도 결과가 바뀌지 않도록 보장하는 격리 수준이다.
데이터베이스는 트랜잭션별로 읽을 버전을 고정 (스냅샷) 하거나 범위 잠금을 걸어 이 동작을 구현한다.
그 결과 보고·정산·감사 같은 작업에서 결과 재현성이 확보되어 오류를 줄이고, 읽기 중심 환경에서는 동시성을 유지하면서도 일관성을 어느 정도 보장할 수 있다.
단, 실제 동작은 DBMS 마다 달라 팬텀이나 쓰기왜곡 같은 특수 사례는 추가 대비가 필요하다.
RR 장점 및 실무 가치표
| 장점 | 기술적 근거 | 실무 효과 | 적용 예시 |
|---|---|---|---|
| 데이터 일관성 보장 | 트랜잭션별 스냅샷 (MVCC) 또는 범위 락 | 결산·정산 오류 예방, 신뢰성 확보 | 금융 결산, 회계 리포트 |
| 동시성 자원 최적화 | 읽기 비차단 (MVCC)/범위 락 선택적 적용 | TPS 증가, 읽기 부하 처리 개선 | 대량 트래픽 API, 모니터링 쿼리 |
| Non-Repeatable Read 예방 | 동일 트랜잭션 내 동일 버전 보장 | 분석·검증 재현성 확보 | 통계 집계, 검증 배치 |
| 실무 구현 용이성 | 대부분 DB 의 기본 지원 (설정 가능) | 빠른 적용·운영 비용 절감 | 표준 서비스 구성 |
| 팬텀 억제 (일부 엔진) | Next-Key/GAP Lock(예: InnoDB) | 범위 조회의 중복/누락 감소 | 범위 기반 집계/검색 |
- RR 의 장점들은 **” 일관성 (재현성) 확보 " 와 " 읽기 성능 유지 “**라는 두 축에서 실무 가치를 제공한다.
- 실제로 얻는 이득의 크기와 남는 위험 (팬텀, write-skew) 은 DBMS 구현 방식과 **쿼리 패턴 (범위/집계 여부)**에 따라 달라지므로 적용 전에 엔진별 테스트와 모니터링이 필수다.
Repeatable Read 의 한계와 운영 대응
Repeatable Read 는 트랜잭션 내에서 같은 쿼리를 반복하면 같은 결과를 보장하려는 격리 수준이다.
하지만 이 보장은 락 확대, 갭락, 또는 MVCC 버전 축적 같은 본질적 비용을 동반한다.
결과적으로 응답 지연·교착, 자원 증가, 일부 논리적 위반 (쓰기 스큐) 이 발생할 수 있다.
실무에서는 인덱스·트랜잭션 길이·모니터링·타임아웃·재시도 정책을 조합해 위험을 완화하거나, 필요하면 Serializable 로 격리 수준을 올리거나 아키텍처 (복제·CQRS) 로 분리해야 한다.
Repeatable Read 의 주요 단점
| 단점 | 상세 설명 | 원인 | 실무 문제 | 완화/해결 방안 | 대안 기술 |
|---|---|---|---|---|---|
| 잠금 경합·교착 | 범위/갭·next-key 락으로 대기 증가 | 범위 검색·인덱스 부재로 락 확대 | 응답 지연·타임아웃·교착 | 인덱스 수정, 트랜잭션 단축, 재시도 정책 | Read Committed, Serializable+ 재시도 |
| Write Skew / 제약 위반 | 동시 갱신으로 제약 회피 가능 | 스냅샷 검증 시점 차이 | 무결성 붕괴 (업무 규칙 위반) | 커밋 전 재검증, SELECT FOR UPDATE | Serializable / SSI |
| 언두/버전 축적 비용 | 장기 트랜잭션이 버전 보관 유발 | MVCC 의 버전 보관 | 디스크·메모리 사용 증가, GC 부하 | 트랜잭션 분할·Vacuum/GC 튜닝 | Read Committed, 비동기 처리 |
| 벤더 상이성 | 동일명칭 기능의 동작 불일치 | 표준 vs 구현 차이 | 이식성·예측성 저하 | DB 별 가이드·테스트 스위트 | 설계 레이어 추상화 |
Repeatable Read 는 ’ 반복 읽기 보장 ’ 이라는 이득을 주지만, 그 대가로 락 경합·쓰기 스큐·버전 축적·벤더별 동작 차이 같은 실무적 위험을 동반한다. 각 위험은 설계 (인덱스·트랜잭션 범위), 운영 (모니터링·GC 튜닝), 정책 (재시도·타임아웃) 으로 완화 가능하며, 필요 시 더 강한 격리나 다른 아키텍처로 전환해야 한다.
Repeatable Read 의 제약사항
| 제약사항 | 상세 설명 | 원인 | 영향 | 완화/해결 방안 | 대안 기술 |
|---|---|---|---|---|---|
| 인덱스 의존성 | 범위 잠금 정확성은 인덱스에 좌우 | 조건 불일치, 풀스캔 유발 | 과도한 락·팬텀 | 쿼리 플랜/EXPLAIN, 커버링 인덱스 | 파티셔닝, CQRS |
| 긴 트랜잭션 비용 | 스냅샷/언두 장기 유지로 비용 증가 | 오래 열린 트랜잭션 | 스토리지·GC·성능 저하 | 트랜잭션 분할, 배치화, GC 튜닝 | Read Committed, 비동기화 |
| 실시간 대량 처리 한계 | 고빈도 동시 작업에서 버전 관리 한계 | 언두 영역 확장 | 처리량 저하, 지연 | 샤딩·읽기 복제본·파티셔닝 | Eventual Consistency, 분산 DB |
| DBMS 엔진 제한 | 구현 특성 (갭락/RCSI/SSI 등) 차이 | 벤더별 내부 설계 | 동작 불일치·이식성 문제 | 벤더별 테스트·운영 가이드 | 특정 DB 전용 최적화 설계 |
Repeatable Read 를 제대로 운영하려면 인덱스 설계·트랜잭션 길이 관리·버전 스토어 모니터링 등 환경적 전제조건을 충족해야 한다. 이 제약들을 무시하면 락 확대·자원 폭증·성능 저하가 발생하므로, 아키텍처적 대안 (샤딩, 복제본, CQRS, 분산 DB) 도 검토해야 한다.
Repeatable Read 의 트레이드오프와 실무적 해법
Repeatable Read 는 트랜잭션 내 같은 조회 결과를 고정해 재현성을 보장한다. 락 기반은 Phantom 억제에 강하지만 대기/데드락이 늘고, MVCC(스냅샷) 은 읽기 성능이 좋지만 일부 동시성 문제 (write-skew) 가 발생할 수 있다. 실무에서는 민감 트랜잭션만 상향하거나 (Serializable/SSI), 리포트는 리플리카로 분리하는 등 하이브리드 전략을 사용해 성능·일관성 균형을 맞춘다.
RR 트레이드오프 비교표
| 비교 | 선택 시 장점 | 선택 시 단점 | 권장 적용 기준 |
|---|---|---|---|
| MVCC 기반 RR | 읽기 무블로킹·높은 동시성 | write-skew 가능·버전 보관 비용 | 읽기 중심·높동시성 서비스 |
| Lock 기반 RR | Phantom 억제·논리적 일관성 강함 | 락 대기·데드락·확장성 저하 | 쓰기/범위 제약 많은 도메인 |
| RR vs RC | 재현성 보장 (RR) | 더 높은 리소스·복잡도 | 회계·검증 필요 작업엔 RR |
| RR vs Serializable | RR 는 성능 우수, Serializable 은 완전 일관성 | Serializable 은 동시성 희생 | 규제·정산은 Serializable |
각 선택은 일관성 수준과 성능·확장성 사이의 전형적 트레이드오프를 반영한다. 서비스 특성 (읽기 대 쓰기 비율, 규제 요구, 응답성 요구) 에 따라 적절한 균형을 택하라.
RR 트레이드오프 완화 하이브리드 기법
| 기법 | 적용 목적 | 구성 요소 | 장점 | 고려사항 |
|---|---|---|---|---|
| 선택적 상향 (쿼리/트랜잭션 단위) | 핵심 트랜잭션만 강한 일관성 | 쿼리 힌트, 트랜잭션 설정 | 최소한의 성능 손실로 안전성 확보 | 코드 복잡성·테스트 필요 |
| 읽기 리플리카/스냅샷 분리 | 분석·리포트 성능 분리 | 리플리카, ETL, 스냅샷 스토어 | 원본 부하 감소·대규모 스캔 안전 | 복제 지연·일관성 지연 |
| SSI(Serializable Snapshot) | 스냅샷 기반 직렬성 보장 | DB 의 SSI 구현 | 직렬성 보장 + 읽기 성능 유지 | 충돌시 재시도 증가 |
| 애플리케이션 보상 (사가) | 분산 트랜잭션 대신 보상 | 보상 로직, 상태 머신 | 확장성·유연성 | 보상 설계 복잡 |
| 부분적 락/인덱스 설계 | 특정 쿼리의 Phantom 방지 | 커버링 인덱스, 범위 락 | 국소적 일관성 보장 | 인덱스 설계 비용 |
하이브리드 기법들은 특정 트레이드오프 (성능 vs 일관성) 를 국지적으로 해결한다. 적용 시에는 목적 (무엇을 보호할지), 구성요소 (데이터베이스·인프라·애플리케이션), 운영 비용 (테스트·모니터링·복구) 을 반드시 고려하라.
Repeatable Read 적용성·운영 전략
Repeatable Read 는 트랜잭션 내부에서 같은 데이터를 여러 번 읽어도 동일한 값이 보이도록 보장하는 격리 수준이다. 따라서 범위 조회와 동시 삽입 충돌이 잦고 재현성·정합성이 중요한 OLTP(예: 재고 할당, 결제 정산) 에 적합하다.
다만 팬텀 (행 집합 변동) 이 치명적일 경우에는 Serializable 이나 명시적 범위 락을 병행해야 안전하다.
적용 전에 DB 별 동작 차이와 성능 영향 (락 대기, 언두 증가) 을 검증하고, 트랜잭션 짧게 설계·모니터링·자동화된 재시도 정책을 준비해야 한다.
Repeatable Read 적용 적합성 표
| 도메인/시나리오 | 적합성 | 설계 판단 (무엇을 확인) | 분석 포인트 (측정 지표) | 운영 권장 대책 | 대안 (부적합 시) |
|---|---|---|---|---|---|
| 재고 할당 (동시 주문) | 적합 | 범위 락 확산 위험성, 인덱스 적합성 | deadlock/sec, lock-wait, phantom 재현률 | 트랜잭션 단축, 유니크 제약 + 재시도 | Serializable / 분산 토큰 |
| 결제 정산 (중간 검증 필요) | 적합 (권장) | 계산 단계 일관성 보장 필요 | avg tx duration, rollback rate | 멱등 키, 재검증 단계, 타임아웃 | Serializable (중요 파트) |
| 대규모 집계 (배치) | 보통 부적합 | 범위 스캔으로 언두/버전 증가 우려 | undo size, long-running tx | 배치로 분리, 샘플링 집계 | Read Committed(분석용) |
| UI 조회/카탈로그 | 보통 적합 | 짧은 단건 조회로 성능 유지 | latency, stale-read 비율 | 리드 리플리카 라우팅 | Read Committed |
| 이벤트 소싱 프로젝션 읽기 | 적합 | 프로젝션 일관성·재빌드 고려 | projection lag, rebuild time | 프로젝션 재빌드 자동화 | N/A |
| 복잡한 배타/카운팅 제약 | 부적합 (주의) | 배타적 카운트/집계가 중요함 | incorrect count incidents | 명시적 잠금 또는 격상 | Serializable / 앱레벨 락 |
Repeatable Read 는 동시성 충돌이 잦고 거래 재현성이 필요한 핵심 OLTP에 적합하다. 그러나 대규모 범위 스캔·배치성 집계에는 언두/버전 스토어 증가와 긴 트랜잭션 문제로 부적합하거나 별도 설계가 필요하다. 팬텀 통제가 필수적이면 Serializable 또는 명시적 잠금을 병행 적용하라.
엔진별 Repeatable Read 동작 비교표
아래 표는 PostgreSQL, MySQL(InnoDB), Oracle, SQL Server 네 엔진의 Repeatable Read 관련 구현 메커니즘·기본값·주의점을 실무 관점에서 정리한 것이다.
| 엔진 | 구현 메커니즘 (간단) | 기본값 (서버) | 팬텀/재조회 처리 | 설정/주요 옵션 | 실무 주의사항 | |
|---|---|---|---|---|---|---|
| PostgreSQL | MVCC 기반의 트랜잭션 - 레벨 스냅샷 (각 트랜잭션이 시작 시점 이후 커밋된 변경은 보이지 않음). REPEATABLE READ 는 트랜잭션이 시작된 시점의 커밋된 데이터만 본다. (별도 SERIALIZABLE 은 SSI 로 더 강함) | 기본: READ COMMITTED (일반적으로)—REPEATABLE READ 는 세션/트랜잭션별 설정 가능. | Non-repeatable Read 방지 (같은 트랜잭션 내 재조회 동일). 팬텀은 REPEATABLE READ 에서 표준상 허용일 수 있으나 Postgres 의 동작은 스냅샷 방식으로 재현 성격이 달라 교육 자료 확인 필요. | SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; (세션/트랜잭션 단위) | MVCC 특성상 읽기 - 락 충돌 없음. 그러나 트랜잭션 길이가 길면 버전 (UNDO) 누적/가비지 처리 영향이 있으므로 장시간 트랜잭션 주의. | |
| MySQL (InnoDB) | InnoDB 는 MVCC + 갭 락 (next-key lock / gap lock) 등을 활용. 기본 (InnoDB) 은 REPEATABLE READ이며, 갭 락으로 팬텀 (삽입) 같은 사례를 억제하는 동작을 지원한다. | 기본: REPEATABLE READ (InnoDB) | Non-repeatable Read 방지. InnoDB 의 gap-lock/next-key-lock 동작으로 많은 경우 팬텀 삽입을 억제하여 범위적 재조회 일관성 제공 (단, 쿼리 형태·인덱스 여부에 영향). | `SET [SESSION | GLOBAL] TRANSACTION ISOLATION LEVEL REPEATABLE READ;`—기본값 변경 가능. 인덱스·WHERE 절 작성이 갭락 동작에 영향. | 갭락 동작은 인덱스·쿼리 패턴에 민감. 비인덱스 범위 쿼리나 오버헤드 큰 락을 유발하면 성능 저하·잠금 경합 증가 가능. 복제와 조합 시 행동 차이점 테스트 권장. ([Percona][4]) |
| Oracle | Oracle 은 statement-level read consistency(각 쿼리 시작 시점의 일관된 뷰) 를 제공. 표준 용어로 REPEATABLE READ 레벨은 명시적 항목이 아니고, Serializable(transaction-level read consistency) 로 트랜잭션 전체에 대해 repeatable 한 읽기를 제공한다. Oracle 의 Read Committed 는 각 쿼리마다 커밋된 시점만 참조 (즉, 문 단위 스냅샷). | 기본: READ COMMITTED (Oracle)—SERIALIZABLE 옵션 제공. | Oracle 의 Serializable(트랜잭션 수준) 사용 시 재조회 일관성·팬텀 억제가 보장된다. Read Committed 는 문 단위 일관성을 제공하므로 같은 트랜잭션 내 재조회는 달라질 수 있음. | ALTER SESSION SET ISOLATION_LEVEL = SERIALIZABLE; 등. Oracle 은 내부적으로 UNDO 세그먼트를 이용한 읽기 일관성을 관리. ([Oracle Documentation][6]) | Oracle 의 Read Consistency 설계는 강력하나, Serializable 사용 시 동시성 저하·ORA-08177(일관성 에러) 같은 상황 고려 필요. 운영환경에선 기본 Read Committed 로 유지하면서 필요 경로에만 Serializable 권장. | |
| SQL Server | 전통적 (락 기반) 구현: REPEATABLE READ 는 읽은 행에 공유 락을 트랜잭션 종료까지 유지해 재조회 불일치 방지. 그러나 기본은 READ COMMITTED. 추가로 Snapshot Isolation / Read Committed Snapshot (RCSI) 옵션을 통해 MVCC 계열 동작을 선택 가능 (버전 저장은 tempdb). | 기본: READ COMMITTED (기본). REPEATABLE READ/ SERIALIZABLE 등 선택 가능. RCSI 는 DB 옵션으로 ON/OFF. | REPEATABLE READ: Non-repeatable Read 방지 via 공유 락 유지 (하지만 팬텀은 방지하지 못함 → SERIALIZABLE 필요). Snapshot/RCSI 사용 시 MVCC 방식으로 재조회 일관성 제공 (설정에 따라 동작 차이). | SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; / DB 옵션 ALTER DATABASE SET READ_COMMITTED_SNAPSHOT ON; (RCSI) 등. Snapshot 사용시 버전관리 리소스 (tempdb) 영향. ([Microsoft Learn][9]) | 락 기반 REPEATABLE READ 는 쓰기 지연·데드락 가능성 증가. RCSI/SNAPSHOT 는 버전 테이블 영향 (tempdb) 과 장기 트랜잭션 시 버전 폭증 주의. 운영 환경에 맞춰 옵션 선택·검증 필요. |
- Postgres: MVCC 기반으로
REPEATABLE READ는 트랜잭션 시점 스냅샷을 보장. 장시간 트랜잭션이 언두/버전 부하를 일으킬 수 있음. - MySQL/InnoDB: 기본값이
REPEATABLE READ. MVCC + 갭락으로 많은 경우 팬텀을 억제하나, 인덱스·쿼리 패턴에 민감. 성능·락 행태를 반드시 워크로드로 테스트. - Oracle:
READ COMMITTED가 기본.SERIALIZABLE이 트랜잭션 수준의 repeatable 읽기를 제공. Oracle 특유의 read-consistency(UNDO 기반) 를 이해 후 설정. - SQL Server: 전통적 REPEATABLE READ 은 락 유지 방식. 필요시 Snapshot/RCSI를 켜 MVCC 스타일 동작을 적용할 수 있음 (운영 리스크·tempdb 영향 고려).
실무 적용 및 사례
실습 예제 및 코드 구현
실습 예제: MySQL InnoDB 에서 Repeatable Read 동작
목적
- 동일 트랜잭션 내에서 외부 트랜잭션의 데이터 변경을 반복 조회 시 반영하지 않는 원리 실습
사전 요구사항
- MySQL, InnoDB 엔진 테이블 (users)
단계별 구현
- 트랜잭션 시작 및 초기 조회
- 외부 트랜잭션에서 값 변경 후 커밋
- 트랜잭션 내에서 재조회
실행 결과
- 처음 조회한 시점의 값을 계속 반환, 트랜잭션 외 데이터 변경이 실시간 반영되지 않음.
추가 실험
- 동일 조건 반복 조회에서 신규 데이터 삽입 (PHANTOM READ) 여부, Gap Lock 영향도 실습 가능.
실습 예제: MySQL InnoDB—RR 에서 팬텀 차단 (Next-Key)
목적
- RR + 인덱스 조건에서 삽입 팬텀 차단 동작 관찰
사전 요구사항
- MySQL 8.0+/8.4+, InnoDB, 테스트 DB 권한
단계별 구현
스키마/데이터 준비
세션 1(T1)
세션 2(T2)
세션 1 커밋 후 세션 2 진행
1COMMIT; -- T1 커밋되면 T2 진행/커밋 가능
실행 결과/검증
- T2 의 INSERT 는 T1 커밋 전까지 대기 (또는 타임아웃). RR+ 인덱스 +Next-Key 로 팬텀 차단됨.
실습 예제: PostgreSQL—RR(Snapshot) 에서 Write Skew 시연
목적
- 스냅샷형 RR 에서 Write Skew 가능성을 관찰
사전 요구사항
- PostgreSQL 14+/15+/16+,
psql또는 Python(psycopg2)
단계별 구현
스키마/데이터
T1 과 T2 를 각각 시작 (두 세션 모두 RR)
동시 갱신
순차 커밋 (충돌 없이 모두 커밋될 수 있음)
결과 확인
1SELECT COUNT(*) FROM oncall WHERE on_duty = TRUE; -- 0 (업무 규칙 위배)
완화 실습
실습 예제: Python(psycopg2) 로 RR/SSI 비교 (요지)
| |
예상: RR 에선 두 커밋 모두 성공 가능 (쓰기왜곡), SERIALIZABLE(SSI) 에선 한 트랜잭션이 충돌로 롤백될 수 있음 → 재시도 필요.
실제 도입 사례 분석
실제 도입 사례: 결제/계좌 관리 시스템
배경 및 도입 이유
- 실거래 결제, 계좌 잔액 등의 비즈니스 트랜잭션에서 데이터 변동이 발생할 경우 금전적 오류 방지 목적으로 Repeatable Read 적용.
구현 아키텍처
graph TD
U[사용자 요청] --> S[애플리케이션 서버]
S --> DB
DB --> T["트랜잭션 매니저 (MVCC 구현)"]
T --> UL[언두 로그]
- 트랜잭션 매니저가 각 쿼리마다 스냅샷 관리, 언두 로그로 반복 조회 값 고정.
핵심 구현 코드
| |
성과 및 결과
- 데이터 정합성 확보, 사용자의 예기치 않은 잔액 오류/실적 오류 예방
- 운영 안정성 증가 및 동시성 처리 효율도 상승
교훈 및 시사점
- Gap Lock, 트랜잭션 관리 전략에 따른 성능/일관성 Trade-off 관리 필수
- 대규모 배치·집계 환경에서 팬텀 리드/쓰기 충돌에 대한 명확한 운영 설계 필요.
실제 도입 사례 분석—전자상거래 재고 중복 방지
배경/이유
- ’ 수량 1’ 한정 상품 동시 결제 시 중복 판매 방지.
아키텍처
graph TB API[Checkout API] --> SVC[Order Service] SVC --> DB[(RDBMS: InnoDB RR)] SVC --> Q[Outbox/Event Bus] DB --> INV[Inventory Table]
- 구현 요지: RR +
SELECT … FOR UPDATE로 대상 행 잠금 → 주문 레코드 삽입 → 결제 승인 → 커밋. 실패 시 롤백/재시도.
핵심 코드 (의사 예시)
성과
- 중복 판매 0 건, 대기 시간 평균 +5~15ms 증가 (잠금 경합), 실패 재시도율 < 1%.
교훈
- 인덱스 정합(SKU PK/Unique) 과 짧은 트랜잭션이 효과적. 관측 지표 (락 대기/타임아웃) 로 상시 튜닝.
최종 정리 및 학습 가이드
내용 종합
Repeatable Read 는 트랜잭션이 같은 데이터를 반복 조회할 때 결과를 고정함으로써 읽기 일관성을 보장하는 격리 수준이다.
일반적으로 MVCC(다중 버전 동시성 제어) 와 언두/버전 로그를 통해 구현되며, 이를 통해 Dirty Read 와 Non-Repeatable Read 를 차단한다.
그러나 팬텀 (read-range 변화) 에 대한 처리 수준은 데이터베이스 엔진에 따라 달라지므로, 팬텀 완전 차단이 필요하면 더 높은 격리 (Serializable) 나 추가적인 락 전략을 선택해야 한다.
실무에서는 RR 을 적용할 때 인덱스/트랜잭션 설계, 장기 트랜잭션의 영향 관리, 재시도와 보상 로직 설계, 그리고 스냅샷·락 관련 메트릭을 모니터링하는 것이 필수적이다.
실무 적용 가이드
| 항목 | 설명 | 기술적 근거 (왜 필요한가) | 실무 권장 대응 | 체크/도구 |
|---|---|---|---|---|
| 격리 정책 선언 | 서비스별 기본격리·예외 정책 문서화 | 다른 서비스는 서로 다른 일관성 요구를 가짐 | 결제/정산→Repeatable/Serializable, 조회→RC | 정책 문서 |
| 트랜잭션 길이 제한 | 트랜잭션을 짧게 유지 | 긴 tx 가 언두/버전 bloat·락 확산 유발 | 타임아웃·짧은 트랜잭션 설계 | DB 설정, APM |
| 인덱스/쿼리 최적화 | 범위 스캔 최소화, 인덱스 정합성 | Next-key/GAP 락 확산 방지 | 인덱스 재검토, 쿼리 리팩토링 | 쿼리 프로파일러 |
| 멱등성·재시도 설계 | 충돌 시 안전한 재시행 보장 | 동시성 충돌 빈도 완화 | 멱등 키, 보상 트랜잭션 패턴 적용 | 코드 리뷰, 테스트 |
| 데드락/락 대기 모니터 | lock-wait, deadlock 감지 | 교착·대기 문제 조기탐지 | 경고·자동 재시도 정책 | Prometheus/Grafana |
| 언두/버전 스토어 관찰 | 언두·row-version 증가 모니터링 | 장기 tx 가 버전 저장소를 키움 | 롱 tx 차단, 주기 GC/cleanup | DB 내부 뷰, 모니터링 |
| 회귀 테스트 자동화 | 팬텀/쓰기왜곡 시나리오 테스트 | 배포 후 동시성 회귀 방지 | CI 에 동시성 테스트 포함 | CI 스크립트 |
| ORM 설정 점검 | JPA/Spring 의 isolation 옵션 명시 | 애플리케이션 레벨 tx 제어 일관성 | 트랜잭션 전파·격리 명시 | 코드 검사 |
| 레플리카 라우팅 정책 | 읽기/쓰기 라우팅 규칙 정의 | 일관성/지연 트레이드오프 관리 | 강일관 요청은 마스터로 | 미들웨어 라우터 |
| 운영 문서화 | DB 별 구현 차이·튜닝 팁 정리 | 같은 이름이라도 동작 다름 | 운영 runbook 작성 | Wiki/Runbook |
학습 로드맵
| 단계 | 권장 기간 | 주제 (요약) | 학습 목표 | 권장 실습 | 평가 포인트 |
|---|---|---|---|---|---|
| 1 | 0.5 일 | 격리 수준 기초 | 이상현상 식별 | 개념 퀴즈 | 정의 정확도 |
| 2 | 1–1.5 일 | MVCC vs 2PL, RR 메커니즘 | RR 동작 원리 이해 | 두 세션 재현 실습 | 실습 보고서 |
| 3 | 1–1.5 일 | 엔진별 동작 비교 | 엔진 간 차이 문서화 | MySQL/Postgres/Oracle 스크립트 | 차이 요약표 |
| 4 | 1 일 | 프레임워크 연계 | 서비스 적용 패턴 습득 | JPA/SQLAlchemy 코드 예제 | 코드 리뷰 체크리스트 |
| 5 | 1 일 | 성능·운영 계측 | 성능 영향 정량화 | pgbench/sysbench 벤치 | 비교 리포트 |
| 6 | 1–2 일 | 내부구조·최적화 (선택) | 고부하 최적화 능력 | 장기 TX 재현·완화 실습 | 문제해결 리포트 |
학습 항목 정리
| 단계 | 항목 (세부) | 목표 | 실무 연관성 | 설명 / 권장 도구 |
|---|---|---|---|---|
| 1 | 격리 수준 비교 | RU/RC/RR/SERIAL 개념 숙지 | 높음 | 슬라이드·퀴즈 |
| 1 | 이상현상 사례 | Dirty/Non-repeatable/Phantom 식별 | 높음 | 사례 매칭 |
| 2 | MVCC 내부 (스냅샷) | 스냅샷 생성/가시성 이해 | 높음 | 다이어그램·토론 |
| 2 | 2PL(락) 구조 | 공유/배타락, 데드락 이해 | 높음 | 시뮬레이션 |
| 2 | RR 반복 읽기 실습 | 반복 조회 결과 관찰 | 매우 높음 | 두 세션 SQL 스크립트 |
| 2 | Gap Lock / Next-Key | 팬텀 차단 메커니즘 이해 | 높음 | InnoDB 실습 |
| 3 | MySQL InnoDB 특성 | next-key lock 행동 실험 | 높음 | Docker MySQL |
| 3 | PostgreSQL 특성 | 트랜잭션 스냅샷 동작 실험 | 높음 | Docker Postgres |
| 3 | Oracle/Other | 엔진별 문서 학습 | 중간 | 엔진 문서 |
| 4 | ORM 연계 | 세션·트랜잭션 경계 구현 | 중간 | Spring JPA/SQLAlchemy 예제 |
| 4 | SELECT … FOR UPDATE | 결정적 경로 보호 패턴 | 높음 | 코드 예제 |
| 5 | 벤치마크 템플릿 | p50/p95/p99 측정 | 높음 | pgbench/sysbench |
| 5 | 모니터링 지표 | lock wait, long tx, deadlocks | 높음 | Prometheus/Grafana |
| 6 | MVCC bloat 관리 | vacuum/undo GC 전략 | 중간 | 운영 로그 분석 |
| 6 | SSI/Serializable 이론 | 직렬화 격리 이해 | 중간 | 논문·문서 읽기 |
용어 정리
| 카테고리 | 용어 (한글 (영문, 약어)) | 정의 | 관련 개념 | 실무 활용 (간단 예시) |
|---|---|---|---|---|
| 핵심 개념 | 반복 읽기 (Repeatable Read, RR) | 트랜잭션 내에서 동일 쿼리의 결과가 고정되도록 보장하는 격리 수준 | RC, Serializable, MVCC | 결산·승인 프로세스에서 재현성 보장 |
| 핵심 개념 | 팬텀 읽기 (Phantom Read,—) | 트랜잭션 중간에 다른 트랜잭션이 행을 추가/삭제해 범위 질의 결과가 달라지는 현상 | 범위 쿼리, Gap Lock | 페이징·집계에서 페이지 누락 문제 예방 |
| 구현 메커니즘 | 다중버전 동시성 제어 (MVCC, MVCC) | 트랜잭션별로 데이터 버전을 유지해 읽기 일관성을 제공하는 기법 | Undo Log, Snapshot Isolation | 최신 DBMS 의 기본 동시성 처리 (읽기 무블로킹) |
| 구현 메커니즘 | 언두 로그 (Undo Log,—) | 변경 전 값을 저장해 롤백·스냅샷 생성을 지원하는 로그 | MVCC, 복구 | 롤백·스냅샷 생성, GC/퍼지 관리 |
| 구현 메커니즘 | 갭 락 (Gap Lock,—) | 인덱스의 빈 구간을 잠궈 새로운 행 삽입 (팬텀) 을 방지하는 락 | Next-Key Lock, Phantom | InnoDB 에서 팬텀 억제 |
| 구현 메커니즘 | 넥스트키 락 (Next-Key Lock,—) | 행 락과 갭 락을 결합한 형태로 범위의 삽입/수정 방지 | Gap Lock, 인덱스 스캔 | InnoDB 의 팬텀 차단 구현 |
| 대안·격리 | 스냅샷 격리 (Snapshot Isolation, SI) | 트랜잭션이 시작 시점의 스냅샷을 읽어 일관성 제공 (Write Skew 주의) | MVCC, Repeatable Read | OLTP 에서 일관성 유지하며 동시성 확보 |
| 대안·격리 | 직렬화 (Serializable, S) | 가장 강한 격리 수준으로 모든 동시성 이상현상을 차단 | Repeatable Read, SI | 규정·회계 집계 등 최고 일관성 요구 시 |
| 동시성 이슈 | 쓰기 스큐 (Write Skew,—) | 독립 업데이트가 제약을 위반하는 상태를 초래하는 동시성 문제 | SI, Serializable | 정책 제약 위반 방지 위해 직렬화 또는 제약 강화 |
| 운영·관리 | 퍼지 (Purge,—) | 불필요해진 언두/버전 데이터를 정리하는 GC 작업 | Undo Log, MVCC | 스토리지/성능 관리 (정기 퍼지 필요) |
| 구현 메커니즘 | 리두/언두 (Redo/Undo,—) | Redo: 복구용 변경 기록, Undo: 롤백/스냅샷용 이전값 기록 | WAL, MVCC | 장애 복구, 트랜잭션 롤백 |
| 특성/주의 | Non-repeatable read(비반복 읽기,—) | 같은 트랜잭션에서 같은 쿼리 재실행 시 결과가 달라짐 | Read Committed, RR | 재현성 필요한 로직은 RR/S 적용 권장 |
참고 및 출처
- 트랜잭션 격리 수준 완벽 가이드: 실무에서 만나는 문제와 해결법
- REPEATABLE READ는 어떻게 구현되는가? (feat. MVCC)
- [MySQL] 트랜잭션의 격리 수준(Isolation Level)에 대해 쉽고 완벽하게 이해하기 - MangKyu’s Diary
- RepeatableRead 에서 발생할 수 있는 동시성 문제와 락
- [MySQL] REPEATABLE READ vs SERIALIZABLE 차이 완전분석
- Achieve a high-speed InnoDB purge on Amazon RDS for MySQL and Amazon Aurora MySQL (AWS Tech Blog)
- KCSE2022 proceedings v5 (한국소프트웨어공학 학술대회 논문집)
- 데이터베이스 설계 및 최적화 (CDragon)
- PostgreSQL: Transaction Isolation
- PostgreSQL: SET TRANSACTION
- MySQL :: InnoDB Locking
- MySQL :: Transaction Isolation Levels
- Microsoft Learn: SET TRANSACTION ISOLATION LEVEL (Transact-SQL)
- Oracle Database: Data Concurrency and Consistency (11g Release 2)
- A Critique of ANSI SQL Isolation Levels (Berenson et al., 1995) — PDF
- ODBC: Transaction Isolation Levels (Microsoft Learn)
- Cockroach Labs: SQL Isolation Levels Explained