Write Skew

Write Skew 는 두 트랜잭션이 같은 **판단 (읽기)**을 하고 각자 다른 레코드를 갱신해서 결과적으로 비즈니스 규칙이 깨지는 현상이다.
예: 두 의사가 동시에 당직 해제 판단 → 최종적으로 아무도 남지 않는 상황. Snapshot Isolation 은 읽기는 스냅샷에서 빠르게 처리하고 쓰기 충돌 (같은 행을 동시에 쓰는 경우) 만 검사하기 때문에 이런 상황을 허용할 수 있다.
예방은 DB 수준 (Serializable/SSI, predicate/next-key locks) 이나 애플리케이션 수준 (guard row, 명시적 락, 집계 테이블) 으로 수행하며, 운영적으로는 직렬화 오류율을 모니터링하고 재시도 정책을 설계해야 한다.

핵심 개념

Write Skew 는 두 개 이상의 트랜잭션이 같은 ’ 판단 근거 ‘(예: 현재 참가자 수) 를 보고 각자 다른 행을 수정해, 최종적으로 시스템 규칙 (예: 최대 인원) 이 깨지는 경우를 말한다.
SI(스냅샷 격리) 는 읽기 성능이 좋아 실무에서 자주 쓰이지만 이런 상황을 막지 못한다.
문제를 막으려면

  1. 핵심 트랜잭션엔 직렬 가능성 (Serializable) 또는 SSI 사용
  2. 범위/프레디케이트 락 (예: SELECT FOR UPDATE, next-key lock) 적용
  3. 애플리케이션 레벨 제약 (버전 체크·재시도)
    을 조합해 보완한다.
핵심 개념 (한글·약어)정의무슨 문제 해결?실무 적용 방식
다중버전 동시성 제어 (MVCC)스냅샷 기반 읽기, 각 트랜잭션은 고유 버전 사용읽기 성능 향상, 락 경합 감소PostgreSQL/InnoDB 등 기본 메커니즘 활용
스냅샷 격리 (SI)WW 충돌을 거부, 스냅샷에서 읽음대부분의 쓰기 충돌 방지 (그러나 RW 허용)기본 격리로 많이 사용 (성능 우수)
쓰기 스큐 (Write Skew)서로 다른 행을 수정해 전역 제약 위반SI 환경에서 발생 가능한 논리 위반Serializable/범위락/애플리케이션 제약으로 보완
직렬 가능성 (Serializable)어떤 순차 실행과 동일한 결과 보장모든 동시성 이상 제거성능 비용 수용 시 적용
Serializable SI (SSI)SI 위에 위험 구조 탐지 추가SI 장점 유지하면서 직렬성 수준 안전화PostgreSQL SSI 등에서 지원
2 단계 잠금 (2PL) / 프레디케이트 락획득/해제 규칙으로 락 관리, 범위 락 포함팬텀·범위 삽입 방지SELECT FOR UPDATE, next-key lock 등

쓰기 스큐는 SI 환경의 대표적 논리 이상이며, MVCC/SI 가 읽기 성능을 확보하는 동안 남는 빈틈을 SSI·Serializable·범위 락·애플리케이션 제약으로 막는다. 실무선택은 무결성 중요도와 성능 요구에 따라 달라진다.

개념 관계와 방지 메커니즘

출발 (원인)→ 작용 대상목적 (왜)결과 (어떤 영향)
MVCC→ SI 동작 기반 제공읽기 동시성 확보스냅샷 읽기 (읽기 경합 감소)
SI→ 트랜잭션 간 상호작용WW 충돌 거부, RW 허용Write Skew 가능성 발생
Write Skew 발생→ 시스템 무결성 위험비즈니스 규칙 위반필요시 Serializable 로 보완
SSI→ SI 에 검출 층 추가RW 사이클 탐지·차단직렬성 보장 (성능 - 무결성 균형)
2PL/Predicate Lock→ 범위/조건 보호팬텀/삽입 차단락 경합·교착 가능성 증가

관계의 핵심은 " 어떤 메커니즘이 어떤 이상을 막고, 그 대가로 어떤 비용 (성능/복잡도) 을 초래하는가 " 를 명확히 하고 적절히 조합하는 것이다.

Write Skew 실무 대책 매핑표

개념실무에서 무엇을 적용 (무엇)어떻게 적용 (방법)왜 적용 (비즈니스 이유)
SI (스냅샷 격리)기본 격리로 사용DB 기본값 또는 설정읽기 성능 우선, 대부분 충분
Write Skew위험 거래에 대해 보호해당 트랜잭션을 Serializable 로 전환 또는 범위락 적용무결성·규정 준수 확보
SSI핵심 트랜잭션에 권장PostgreSQL 의 SSI 사용 (재시도 처리)SI 장점 유지 + 직렬성 보장
범위 락 (next-key/gap)예약·유니크 제약에 적용SELECT FOR UPDATE / 인덱스 설계 병행과예약·삽입 충돌 차단
애플리케이션 제약 (버전)UI·API 경계에서 검증version 컬럼 + UPDATE WHERE version=?사용자 think-time 시 실무적 보완
모니터링/검증충돌률·직렬화 실패 측정Prometheus/Grafana 지표, Jepsen 스타일 테스트정책 결정 근거 제공

실무에서는 SI 를 기본으로 두되, 비즈니스 영향이 큰 트랜잭션에 대해서만 Serializable/SSI 또는 범위 락을 적용하는 ’ 선택적 엄격화 ’ 전략이 현실적이다. 애플리케이션 레벨 방어와 운영 모니터링은 필수 보완책이다.

기초 조사 및 개념 정립

Write Skew 이해와 실무적 대응

두 사람이 같은 규칙을 기준으로 동시에 판단해서 서로 다른 레코드를 바꾸면, 합쳐진 결과가 규칙을 깨는 경우가 있다.
예를 들어 " 항상 두 명의 담당자가 있어야 한다 " 는 규칙에서, A 와 B 가 동시에 서로를 대신할 수 있다고 판단해 각자 업무를 내려놓으면 결과적으로 둘 다 없어져 규칙을 위반하게 된다. 이런 현상이 바로 Write Skew 다.
방지하려면 DB 의 직렬화 격리 (Serializable/SSI) 를 사용하거나, 애플리케이션에서 명시적 잠금 (SELECT … FOR UPDATE) 또는 불변식 검증을 원자적으로 수행해야 한다.

왜 발생하는가
  • MVCC/Snapshot Isolation 에서는 각 트랜잭션이 자신만의 읽기 스냅샷을 가짐.
  • T1 과 T2 가 같은 프레디킷 P 를 읽어 " 조건 충족 " 으로 판단 → 각각 서로 다른 행 R1, R2 를 업데이트.
  • 서로의 업데이트를 보지 못했기 때문에 둘 다 커밋 가능 → 합쳐진 결과 (두 행의 상태 조합) 가 시스템 불변식을 위반할 수 있음.
간단한 재현 예제 (의사 SQL, 단계별 주석)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
-- 전제: 테이블 on_call(user_id, oncall boolean)
-- 불변식: 항상 on_call에서 oncall = true 인 사용자가 최소 1명은 존재해야 함

-- 트랜잭션 T1 시작
BEGIN;
-- T1은 현재 자신(1번)의 oncall 상태를 확인
SELECT * FROM on_call WHERE user_id = 1 AND oncall = true;  -- 결과: row exists

-- 트랜잭션 T2 거의 동시에 시작
BEGIN;
SELECT * FROM on_call WHERE user_id = 2 AND oncall = true;  -- 결과: row exists

-- T1: 자신을 off로 변경 (다른 사람이 여전히 on이라고 판단)
UPDATE on_call SET oncall = false WHERE user_id = 1;
COMMIT;  -- 커밋 성공 (T1은 T2의 변경을 보지 못함)

-- T2: 자신을 off로 변경
UPDATE on_call SET oncall = false WHERE user_id = 2;
COMMIT;  -- 커밋 성공

-- 결과: 모든 oncall이 false가 되어 '최소 1명 on' 불변식 위반
  • 위는 Snapshot Isolation 환경에서 전형적으로 발생하는 Write Skew 사례다.
방지 방법
  • Serializable / SSI 사용: DB 가 의존성 (읽기→쓰기 간 의존) 을 탐지해 충돌 시 하나를 Abort → 재시도 유도. 근본적 해결이나 성능·재시도 비용 존재.

  • 명시적 락: 문제 구간에서 SELECT … FOR UPDATE 등으로 관련 행 또는 범위를 잠금 → 다른 트랜잭션의 동시 판단 차단.

  • 원자적 불변식 검사·갱신: 애플리케이션이 불변식 검사와 갱신을 DB 내부 (예: 저장 프로시저) 에서 원자적으로 수행.

  • 데이터 모델/제약 강화: DB 제약 (예: 체크 제약, 트리거, 고유성) 으로 불변식을 강제할 수 있으면 애플리케이션 레벨 위험 감소.

  • 혼합 전략: 핵심 경로는 직렬화, 나머지는 SI + 검증으로 성능과 일관성 균형.

탐지·운영 관점
  • 탐지 신호: 도메인 규칙 위반 알림, 애플리케이션 레벨 검증 실패, 재시도 패턴 이상.
  • 진단 도구: 트랜잭션 로그, 직렬화 실패 (예: SQLSTATE 40001) 로그, APM 으로 긴 트랜잭션/동시성 패턴 분석.
  • 런북 (즉시 대처): 문제 트랜잭션 롤백/재시도 유도, 임시로 중요 경로의 격리 수준 올리기, 해당 기능의 트래픽 셰이딩.

등장 배경 및 발전 과정

  • 무엇이 문제인가?
    두 트랜잭션이 같은 데이터를 읽고 서로 다른 행을 _ 갱신 _ 하면, 충돌 (같은 행을 쓰는 경우) 이 없어 보이지만 결과적으로 데이터 제약이 깨질 수 있다. 이 현상이 write-skew다.

  • 왜 SI 에서 발생하나?
    SI 는 각 트랜잭션에 시작 시점 스냅샷을 보여주고, 서로 다른 행을 갱신할 때 쓰기 - 쓰기 충돌이 발생하지 않으면 커밋을 허용한다. 그 결과 스냅샷 기반으로 보았을 때 정합성 제약을 위반할 수 있다.

  • 어떤 기술이 해결했나?
    전통적 락 (2PL) 로 막을 수 있지만 비용이 크다. SI 의 장점은 살리되 write-skew 를 차단하려고 SSI 같은 런타임 충돌 검출 기법이 도입되었다.

등장 배경

대규모 OLTP 와 MVCC 기반 DB 의 확산으로 읽기 성능을 중시하는 설계가 보편화되었다.
이 과정에서 SI 는 읽기 성능과 일관성의 좋은 절충을 제공했지만, 현실 비즈니스 제약 (예: " 적어도 한 명은 on-call 이어야 한다 “) 에서 SI 가 허용하는 특정 병렬 패턴이 제약을 깨뜨리는 사례가 발견되었다.
이 문제 (동시성 패턴으로 인한 제약 위반) 가 바로 write-skew이며, 이로 인해 SI 의 한계를 보완하는 연구·기술 (SSI 등) 이 촉발되었다.

발전 과정
시기 (개념 순서)기술/개념등장 이유 (문제)개선/효과
12PL / 전통적 락동시 쓰기 충돌·정합성 보장직렬성 보장, 락 경합·교착 발생
2MVCC읽기 경합·성능 문제 완화읽기 스냅샷 제공, 읽기 성능 향상
3Snapshot Isolation (SI)MVCC 기반 읽기 일관성 강화스냅샷 읽기 제공, 동시성↑ (하지만 write-skew 가능)
4Write-Skew 문제 인식SI 하에서 비직렬화 사례 보고SI 의 한계 (비즈니스 제약 훼손) 드러남
5Serializable SI (SSI)SI 의 취약점 보완 필요런타임 충돌 검출로 직렬성 보장 (일부 트랜잭션 abort)
6애플리케이션/설계 보완모든 트랜잭션 강제 직렬화 비용 회피하이브리드 설계 (CQRS, 제약, 샤딩) 적용
timeline
    title Write-Skew 등장과 대응 진화
    "2PL / 락 중심" : 1
    "MVCC 도입" : 2
    "Snapshot Isolation (SI)" : 3
    "Write-Skew 문제 인식" : 4
    "Serializable SI / SSI" : 5
    "애플리케이션/설계 보완" : 6
  • 전통적 락 (2PL) 은 write-skew 같은 문제를 막지만 읽기 성능 저하라는 비용이 따라왔다. MVCC 와 SI 는 읽기 성능을 대폭 개선했으나 SI 는 write-skew 를 허용할 수 있어 비즈니스 제약을 손상시킬 소지가 드러났다. 이를 보완하기 위해 **SSI(런타임 충돌 검출)**가 등장했고, 실제 시스템에서는 비용과 효과를 고려해 **DB 수준의 SSI + 애플리케이션 설계 보완 (제약·검증·샤딩)**을 혼용하는 방식이 널리 채택된다. 또한 같은 이름의 격리 수준이라도 DB 별 구현 차이를 반드시 검증해야 한다.

Write Skew 문제·목적·해결

Write Skew 는 서로 다른 행을 동시에 업데이트한 두 트랜잭션이 합쳐져 전체 규칙 (불변식) 을 깨는 문제로, 주로 Snapshot Isolation 같은 격리 환경에서 발생한다.

  • 간단 예시 (의료 온콜):

    • T1: 읽기—의사 A on_call? yes; T2: 읽기—의사 B on_call? yes
    • T1: A.on_call = false; 커밋
    • T2: B.on_call = false; 커밋 → 결과: 병동에 on_call 담당자 0 명 (불변식 위반).
  • 해결 아이디어 (직관): 두 트랜잭션이 서로의 판단에 영향을 주지 못하도록 _ 공유 자원에 대한 동시성 제어 _ 를 적용하거나 (락/직렬화), 애플리케이션 단에서 집계를 단일화해 원자적으로 갱신한다.

Write Skew 가 유발하는 문제들
문제 유형구체 증상비즈니스 영향
도메인 불변식 위반서로 다른 행 동시 변경 → 전체 제약 (예: 최소 1 명 유지) 위반규정 위반, 서비스 중단, 안전사고 가능
상태 불일치트랜잭션 간 상태 판단 불일치 (스냅샷에 의존)예측 불가능한 동작, 버그 발생
탐지 어려움각 트랜잭션 자체론 정상 → 문제는 합쳐졌을 때 발생디버깅·감사 곤란
  • Write Skew 는 ’ 부분적으로 보면 정상 ’ 이지만 전체 규칙엔 치명적인 오류**를 만드는 동시성 결함이다. 특히 안전·규제·금융 같은 도메인에서 즉시 문제로 이어질 수 있어 주의 깊은 설계가 필요하다.
Write Skew 해결의 핵심 목적
목적구체 목표기대 효과
도메인 불변식 보장시스템 상태가 불변식 항상 만족하게 함안전성·무결성 확보
합성 동작 신뢰도 향상다중 트랜잭션 합성 결과 예측 가능오류·사후 처리 비용 감소
운영·감사 용이성이상상황 희소화로 디버깅 용이규정 준수·감사 준비성 강화
  • 핵심: 목적은 단순히 오류를 줄이는 게 아니라 시스템 레벨에서 규칙 (불변식) 을 항상 지키게 만들어 비즈니스 신뢰성을 확보하는 것이다.
문제와 목적의 연계 (Write Skew)
문제 (증상)대응 목적연계 방식
도메인 불변식 위반도메인 불변식 보장트랜잭션 수준 충돌 차단 또는 불변식 단일화
상태 불일치합성 동작 신뢰도 향상읽기/쓰기 가시성 조정 (격리 수준/락)
탐지 어려움운영·감사 용이성실패 시 재시도·로그·경보 체계 구축
  • 핵심 연결: 각 문제는 불변식 보장·가시성 제어·운영 지원이라는 목적에 직접적으로 매핑된다. 해결책은 문제 유형에 맞춘 기술 (격리·락·애플리케이션 설계) 과 운영 정책 (재시도·모니터링) 을 조합하는 것이다.

Write Skew 발생요건과 확인 체크리스트

  • 무슨 문제인가?
    두 트랜잭션이 같은 _ 읽기 결과 _ 를 기반으로 서로 다른 행을 수정하면, 최종 상태가 시스템의 규칙 (불변식) 을 깨는 현상이 생길 수 있다. 이 현상이 바로 Write Skew다.

  • 언제 발생하나? (체크리스트)

    1. DB 가 MVCC/Snapshot 기반 (스냅샷 읽기) 을 사용한다.
    2. 불변식이 여러 행/범위에 걸쳐 정의되어 있다.
    3. 동시 트랜잭션들이 같은 읽기 집합을 읽고 서로 다른 행을 쓴다 (WW 충돌 없음).
    4. 격리 수준이 SERIALIZABLE 이 아니거나 SI 만 적용되어 있는 경우.
  • 가장 쉬운 예: 두 의사가 각각 다른 레코드를 지워서 결국 아무도 남지 않는 상황 (Doctors on-call 예).

  • 단기·실무적 대처: 애플리케이션 수준에서 검증 및 재시도, SELECT FOR UPDATE 또는 의도적 업데이트 (충돌 물질화) 사용. 장기적으로는 SERIALIZABLE/SSI 도입 검토.

Write Skew 발생 전제·요구조건 체크표
항목요구사항 (명세)왜 필요한가 (핵심 이유)검증 방법 / 지표
실행 모델MVCC / Snapshot Isolation 또는 비잠금 읽기 환경스냅샷 읽기로 다른 트랜잭션의 중간 쓰기를 보지 못함.DB 문서 확인 (SHOW transaction_isolation 등).
불변식 형태불변식이 여러 행/범위에 걸쳐 표현됨 (조합적 제약)조합적 제약은 단일 행 잠금으로는 보장 불가.비즈니스 규칙 분석 (제약 SQL/유즈케이스 확인).
동시성 패턴여러 트랜잭션이 동시에 동일한 읽기 집합을 읽음읽기 기반 의사결정이 서로를 인지하지 못하는 상황 생성.부하/동시성 로그, 트랜잭션 타임라인.
쓰기 충돌각 트랜잭션의 쓰기 집합이 서로 서로 다른 행(WW 충돌 없음)WW 충돌이 없으면 DB 가 둘 다 커밋시키고 write-skew 발생 가능.쓰기 대상 분석, EXPLAIN/트랜잭션 로그.
격리 수준격리 수준이 SERIALIZABLE 보다 약함 (예: SI/REPEATABLE READ 등)SERIALIZABLE 이면 이 클래스의 이상을 방지하거나 탐지 가능.격리설정 확인 및 SSI 여부 점검.

Write Skew 가 발생하려면

  1. MVCC/Snapshot 기반 읽기 모델이면서
  2. 불변식이 여러 행/범위에 걸쳐 정의되어 있고
  3. 동시 트랜잭션들이 같은 읽기 집합을 읽은 뒤 서로 다른 행을 수정 (즉, WW 충돌이 없을 때) 해야 하며,
  4. 격리 수준이 완전한 직렬성을 보장하지 않을 때 발생 가능성이 높다.
    위 항목을 하나하나 점검하면 write-skew 취약성을 판단할 수 있다.

Write Skew: 원인·특징·실무 대응

Write Skew 는 서로 다른 행을 동시에 바꾸는 두 트랜잭션이 함께 실행될 때, 각각은 정당해도 합치면 전체 규칙 (예: 최소 인원 유지) 을 깨는 문제다.
스냅샷 격리 (SI) 는 이런 상황에서 종종 탐지하지 못한다. 해결하려면 직렬성 보장 (Serializable/SSI) 을 쓰거나, 중요한 읽기 집합을 잠그거나, 커밋 전에 규칙을 다시 확인해 실패 시 재시도하는 패턴을 적용한다.

Write Skew 특징·근거·차별표
핵심 특징기술적 근거다른 동시성 이상과의 차별점실무적 의미 (대응 포인트)
발생 조건: 다른 행 동시 갱신MVCC 스냅샷 + WW 검사만 수행Lost Update/Dirty Write 는 동일 행 충돌중요 불변식 관련 트랜잭션 식별
직렬성 위반 (비가시적)의존성 그래프에서 read–write 로 사이클 생성Phantom 은 범위 변화 연계, Write Skew 는 불변식 초점자동화된 동시성 테스트 필요
탐지 어려움WW 가 없어 SI 검사 누락버전비교/WW 기반 검사로는 탐지 불가Serializable/SSI 또는 읽은 집합 잠금 권장
대응의 비용 - 효과 트레이드오프SSI(오버헤드), FOR UPDATE(락 경합), 제약 (단순화)다른 이상보다 복합적 대응 요구우선순위: DB 제약 → 잠금 → 격리상향 순 적용

Write Skew 는 SI 환경에서 특히 주의해야 할 동시성 이상으로, 탐지·예방이 단순 충돌 검사로는 어렵다. 실무에서는 불변식 관련 트랜잭션을 식별해 우선적으로 DB 제약이나 읽은 집합 잠금으로 보호하되, 필요한 경우 Serializable/SSI 전환을 검토해 전체 무결성을 확보한다. 각 선택은 성능·운영 비용을 동반하므로 테스트로 트레이드오프를 확인해야 한다.

Phase 2: 핵심 원리 및 이론적 기반

Write Skew 대응 원칙과 설계 전략

Write Skew 는 트랜잭션 A 와 B 가 같은 판단 근거 (읽기 결과) 를 보고 각자 다른 레코드를 수정했을 때 발생하는 일관성 위반 현상이다.
SI 는 읽기는 스냅샷에서 빠르게 처리하고, 같은 행을 동시에 쓸 때만 충돌을 막기 때문에 이런 시나리오가 가능하다.
해결책은

  1. DB 가 직렬성 보장 (SSI/Serializable) 하도록 설정하거나
  2. 중요한 판단 구간에 **명시적 잠금 (SELECT FOR UPDATE)**을 거는 것
  3. 스키마/애플리케이션 레벨로 제약을 물질화 (guard row/집계 테이블) 하거나
  4. 재시도·모니터링 정책을 운영하는 것이다.

실무에서는 비용·성능을 고려해 핵심 트랜잭션에만 강한 제어를 적용하는 전략이 일반적이다.

Write Skew 핵심 원칙 요약표
핵심 원칙설명목적왜 필요한가
SI: 스냅샷 읽기 + WW 검사트랜잭션은 시작 스냅샷을 읽고, 동일 튜플 동시 쓰기만 충돌로 처리.읽기 성능 극대화높은 동시성 환경에서 락 경합 최소화 필요
Write Skew 조건동일 상태 읽기 → 서로 다른 객체 쓰기 → 전체 불변식 위배.이상 현상 식별SI 의 WW 전제 때문에 발생 가능
직렬화 (Serializable/SSI)반의존성 추적 후 직렬성 위반 시 abort근본적 예방SI 로는 잡히지 않는 패턴 제거
충돌 물질화 (guard row)논리 제약을 실제 쓰기로 표현DB 충돌 검사 활용SI 의 한계 보완, 단순·효과적

핵심 원칙은 **SI 의 설계 (스냅샷 +WW 검사)**와 그로 인해 생기는 write-skew 조건을 이해하는 데 초점이 있다. 예방은 DB 수준 (직렬성 보장), 스키마 보강 (충돌 물질화), 애플리케이션 수준 (명시적 락/재시도) 으로 나뉘며, 실무는 성능 비용을 고려해 선택적으로 적용한다.

Write Skew 대응 설계 철학 요약
설계 철학핵심 아이디어적용 목적고려사항
선택적 강화핵심 트랜잭션만 Serializable 적용비용 절감 + 정합성 보장분류 정확성·테스트 필요
충돌 물질화가드 행/집계 업데이트로 충돌 유도SI 환경에서 안전성 확보정규화 위배·운영 복잡성
애플리케이션 락 & 재시도FOR UPDATE/분산 락·재시도 정책외부 사이드이펙트 포함 작업 보호재시도 안전성 (idempotency) 확보 필요

설계 철학은 " 전부를 포기하지 않되, 중요한 것만 강하게 지킨다 " 는 실무적 균형을 표현한다. 각 방식은 장단이 뚜렷하므로 워크로드·제약·운영문화에 맞춰 조합 적용해야 최적의 결과를 얻는다.

Write Skew 작동원리와 방지전략

Write Skew 는 두 사용자가 같은 기준으로 " 괜찮다 " 고 판단한 뒤 각각 다른 데이터를 바꿔서, 최종적으로 전체 규칙이 깨지는 상황이다. 예: 병동에 on_call 담당자가 1 명인데 A 와 B 가 각각 자신을 off 로 바꾸면 결과적으로 0 명이 된다. Snapshot Isolation 은 보통 이 상황을 막지 못하니, 중요한 규칙이 있다면 범위 잠금이나 직렬화 (Serializable/SSI) 를 적용하거나 애플리케이션에서 버전 검증·재시도를 구현해야 한다.

쓰기스큐 동작 원리와 메커니즘
핵심 메커니즘 (순서 기준)
  1. 트랜잭션 A/B 가 동일 조건의 쿼리 (SELECT) 를 각자 스냅샷에서 수행해 같은 판정 (예: 참가자 수 = 1) 을 얻음.
  2. 각 트랜잭션은 서로 다른 row(또는 객체) 를 업데이트 (또는 삭제) 함—WW 충돌은 없음.
  3. 트랜잭션들이 독립적으로 커밋되면, 시스템 전체에선 전역 제약 (invariant) 이 깨지게 됨 (예: 온콜 담당자 수 = 0).
  4. 발생 이유는 SI/Repeatable Read 에서 RW 반의존성(read→other write) 경로가 허용되어 직렬성 그래프에 RW 엣지들이 사이클을 형성할 수 있기 때문.
방지 옵션 (요약)
  • 직렬 가능성 확보 (Serializable): 모든 이상을 차단하지만 비용 큼.
  • SSI (Serializable Snapshot Isolation): SI 기반에서 위험 구조를 런타임 탐지·차단해 재시도 유도.
  • 범위 락 (Next-Key / Predicate / SELECT FOR UPDATE): 조건 단위를 잠가 삽입/삭제로 인한 변화 방지.
  • 애플리케이션 레벨 검증 (버전·제약): 사용자 think-time 포함 시 실무적 보완.
Write Skew 동작요약 표
단계동작핵심 기술적 포인트왜 문제가 되는가
1동일 조건 SELECT스냅샷 (SI/MVCC) 기반 읽기각 트랜잭션이 같은 판단을 함
2서로 다른 row 에 WRITEWW 는 거부되지만 RW 는 허용될 수 있음서로 다른 행 쓰기여도 전역 규칙 위반 가능
3동시 COMMIT커밋 시점에 최종 상태 확정최종 상태가 불변식 위반으로 귀결
4결과전역 비즈니스 규칙 (제약) 위반심각한 비즈니스 오류 초래

쓰기 스큐는 " 같은 판단 근거 " 를 읽고 서로 다른 객체를 변경하는 패턴에서 발생한다. 핵심은 WW 충돌만 차단하는 SI 가 RW 에 의한 논리적 위반을 허용할 수 있다는 점이며, 이를 막으려면 조건 단위를 보호하거나 직렬화를 보장해야 한다.

쓰기스큐 흐름도
flowchart TD
  Start([시작]) --> T1_BEGIN["T1: BEGIN (SI)"]
  Start --> T2_BEGIN["T2: BEGIN (SI)"]

  T1_BEGIN --> T1_SELECT[T1: SELECT count WHERE predicate -> v]
  T2_BEGIN --> T2_SELECT[T2: SELECT count WHERE predicate -> v]

  T1_SELECT --> T1_DECIDE["T1: 판단 (조건 충족?) -> 예"]
  T2_SELECT --> T2_DECIDE["T2: 판단 (조건 충족?) -> 예"]

  T1_DECIDE --> T1_WRITE[T1: UPDATE/DELETE 다른 row]
  T2_DECIDE --> T2_WRITE[T2: UPDATE/DELETE 다른 row]

  T1_WRITE --> DB_OK1["DB: 쓰기 OK (WW 없음)"]
  T2_WRITE --> DB_OK2["DB: 쓰기 OK (WW 없음)"]

  DB_OK1 --> T1_COMMIT[T1: COMMIT]
  DB_OK2 --> T2_COMMIT[T2: COMMIT]

  T1_COMMIT --> FinalCheck[DB: 최종제약 검증]
  T2_COMMIT --> FinalCheck

  FinalCheck --> Violation{제약 위반?}
  Violation -- Yes --> InvariantBroken["결과: 불변식 위반 (Write Skew 발생)"]
  Violation -- No --> OK[결과: 무결성 유지]

  %% 방지 지점(검사/대응)
  subgraph Mitigations [방지/완화 지점]
    M1["선택지: SELECT … FOR UPDATE(범위락)"] 
    M2[선택지: SERIALIZABLE / SSI]
    M3[선택지: 애플리케이션 버전검사 + UPDATE WHERE version=?]
  end

  T1_SELECT -.-> M1
  T2_SELECT -.-> M1
  T1_SELECT -.-> M3
  T2_SELECT -.-> M3
  T1_COMMIT -.-> M2
  T2_COMMIT -.-> M2

위 흐름도는 쓰기 스큐의 전형적 시나리오를 단계별로 보여준다.
핵심은 트랜잭션이 같은 predicate 를 읽고 (스냅샷 기반) 서로 다른 대상에 쓰기를 한 뒤 동시 커밋하면 전역 불변식이 깨지는 지점이다.
방지 옵션은 세 가지 주요 지점에서 개입한다:

  1. SELECT 직후 범위락 (SELECT … FOR UPDATE) 로 조건을 보호
  2. 커밋 단계에서 Serializable/SSI 로 위험 구조를 검출해 재시도 유도
  3. 애플리케이션 레벨에서 버전검사 (UPDATE WHERE version=?) 로 충돌을 탐지하고 재시도한다.

실무에서는 이들을 혼합해 ’ 성능 - 무결성 ’ 의 균형을 맞춘다. 또한 운영상 충돌률·재시도 통계를 수집해 정책 (예: 일시적 격리 상향, 샤드 리밸런싱) 을 동적으로 적용하는 것이 권장된다.

Write Skew 흐름·생명주기·탐지

트랜잭션 A 와 B 가 같은 규칙을 보고 각각 다른 레코드를 수정하면, 서로의 변경을 보지 못한 채 둘 다 커밋해 합쳐진 결과가 규칙을 깨는 경우가 생긴다.
핵심은 _ 읽기 시점의 스냅샷 가시성 _ 과 _ 커밋 시 검사 범위 _ 가 불일치한다는 점이다.
이를 막으려면 DB 의 직렬화 또는 명시적 잠금, 또는 불변식을 원자적으로 검사·갱신하는 설계가 필요하다.

Write Skew 생명주기 흐름
  1. 트랜잭션 시작 (Start)

    • 트랜잭션이 시작되고, MVCC 환경이면 읽기 스냅샷이 고정된다.
    • 타이밍: 스냅샷은 일반적으로 트랜잭션 시작 시점 (또는 첫 읽기 시점) 에 결정된다.
  2. 읽기·검증 (Read & Validate)

    • 동일한 Predicate(예: currentParticipants < maxParticipants) 을 읽음.
    • 판단은 스냅샷 기준으로 이루어짐 (다른 트랜잭션의 미커밋/커밋된 변경을 보지 못할 수 있음).
  3. 업데이트 (Update)

    • T1 은 행 R1 을, T2 는 행 R2 를 업데이트 (서로 다른 행).
    • 변경 내용은 각자의 쓰기 버퍼에 저장 (커밋 전까지 다른 트랜잭션에 보이지 않음).
  4. 커밋 (Commit)

    • DB 는 보통 WW 충돌 (동일 행에 대한 동시 쓰기) 만 검사하거나 격리 정책에 따라 추가 검사.
    • 두 트랜잭션이 서로 다른 행을 썼다면 둘 다 커밋될 가능성이 높음.
  5. 합성 상태 (Composite State) 노출

    • 커밋 후의 전체 상태가 비즈니스 불변식을 위반하면 Write Skew 발생.
    • 문제는 단일 트랜잭션의 관점에서는 정당하지만 전체 관점에서 불일치가 발생하는 것.
Write Skew 단계별 제어·데이터 흐름표
단계동작 (데이터 흐름)제어 포인트 (검증·잠금)발생 위험운영적 체크
Start트랜잭션 시작 → 스냅샷 고정트랜잭션 시작 시점스냅샷 시점 불일치트랜잭션 시작 로그
Read & ValidatePredicate 기준 읽기 (스냅샷)애플리케이션 불변식 검사 (스냅샷 기준)잘못된 ‘OK’ 판단동시 요청 패턴 모니터링
Update서로 다른 행 업데이트 (쓰기 버퍼)(보통 잠금 없음)서로의 변경 미가시성쓰기 패턴·대상 분포 분석
CommitDB 가 충돌 검사 (주로 WW) → 커밋격리 정책별 충돌 검증합성 불변식 위반 노출직렬화 실패/불변식 알람
Post-Commit합성 상태로 불변식 위반 확인애플리케이션·감시 시스템비즈니스 규칙 위반자동 롤백 불가 → 수동 대응/패치

핵심: **스냅샷 시점 (읽기 기준)**과 커밋 시 충돌 검사 범위가 달라 발생한다. 탐지 포인트는 동시 읽기 패턴, 특정 API 의 동시 호출, 커밋 시점의 불변식 위반 로그다. 운영에서는 트랜잭션 길이·동시성 패턴·직렬화 실패 및 애플리케이션 레벨 불일치 알람을 주의 깊게 모니터링해야 한다.

Write Skew 기본 흐름도
sequenceDiagram
    participant T1 as 트랜잭션 T1
    participant T2 as 트랜잭션 T2
    participant DB as 데이터베이스

    T1->>DB: BEGIN (스냅샷 고정)
    T2->>DB: BEGIN (스냅샷 고정)
    T1->>DB: SELECT predicate (스냅샷 기준) -> OK
    T2->>DB: SELECT predicate (스냅샷 기준) -> OK
    T1->>DB: UPDATE row R1 (쓰기 버퍼)
    T2->>DB: UPDATE row R2 (쓰기 버퍼)
    T1->>DB: COMMIT
    DB-->>T1: COMMIT 성공
    T2->>DB: COMMIT
    DB-->>T2: COMMIT 성공
    DB-->>All: 결과 상태 불변식 위반 -> Write Skew 발생

위 순서도는 MVCC/Snapshot 환경에서 전형적인 Write Skew 발생 경로를 보여준다. 핵심은 두 트랜잭션이 동일한 판단 (스냅샷 기준) 을 내리고 서로 다른 행을 수정한 뒤 둘 다 커밋되어 합쳐진 결과가 규칙을 깨는 것이다. 흐름도 개선 시점은 스냅샷 확정 타이밍, 격리 수준 분기 (Abort 가능성), 그리고 명시적 락 도입 지점이다.

Write Skew 생명주기 상태도
stateDiagram-v2
    [*] --> Started: 트랜잭션 시작\n(스냅샷 고정)
    Started --> ReadValidate: Predicate 읽기/검증
    ReadValidate --> Update: 행 업데이트
    Update --> CommitAttempt: 커밋 시도
    CommitAttempt --> Committed: 커밋 성공
    CommitAttempt --> Aborted: 충돌 탐지 → Abort (Serializable/SSI)
    Committed --> PostState: 합성 상태 노출
    PostState --> [*]: 정합성 확인 / 운영 알람

생명주기 다이어그램은 트랜잭션 상태 전이를 중심으로 Write Skew 의 가능 지점을 보여준다. 핵심은 CommitAttempt 에서의 분기 (Committed vs Aborted) 이며, Abort 는 직렬화 보장 메커니즘에서 발생해 재시도 로직을 요구한다. PostState 에서의 운영 감시와 회복 루프는 실제 서비스 안정성 확보에 필수적이다.

특성 분석 및 평가

Write-Skew 방지: 이점·현실적 선택

  • 핵심 요지:
    동시성을 높이면 성능이 좋아지지만 일부 상황에서는 write-skew 같은 보이지 않는 오류가 생긴다.

  • 무엇을 얻나:
    MVCC/SI 같은 기법으로 읽기 성능과 동시성을 크게 올릴 수 있다.

  • 무엇을 더해야 안전한가:
    SSI(런타임 검출), 범위락, DB 제약, 애플리케이션 락 같은 보완으로 중요한 비즈니스 규칙을 지켜야 한다.

  • 실무 규칙 (간단):
    성능 우선이면 낙관적 접근 (SI) + 모니터링, 정합성 우선이면 강한 격리 (SSI/2PL/제약).

Write-Skew 대응 기법의 장점 한눈표
장점기술 근거 (Why)실무 효과 (So what)적용 조건 / 예시
동시성 향상 (MVCC/SI)스냅샷 읽기로 읽기 - 쓰기 경합 회피읽기 많은 서비스에서 처리량·응답성 개선읽기 우선 시스템, 통계·로그 집계
성능 최적화 (낮은 격리)락 최소화로 짧은 트랜잭션 유지P99·TPS 개선, 인프라 효율성낮은 정합성 요구, 캐주얼 데이터
개발 유연성격리 수준/명시적 락 선택으로 정책화 가능빠른 기능 출시·도메인별 처리다양한 도메인 요구 공존
SSI (직렬성 보장)런타임 의존성 그래프 검출로 위험 패턴 차단SI 성능 확보 + 정합성 보장 (일부 abort)핵심 금융 트랜잭션 (부분 적용 권장)
2PL / 범위락predicate/next-key lock 으로 범위 변경 차단팬텀/Write-Skew 예방, 예측 가능성↑고정 규칙·작업 범위가 명확한 도메인
스키마 제약 · 집계 행DB 가 불변식 원자적으로 보장애플리케이션 오류 감소, 무결성 강화불변식이 DB 수준으로 표현 가능한 경우
애플리케이션 락도메인 키 기반 락 (Advisory)핫스팟만 보호·점진적 도입 가능분산·마이크로서비스 환경
  • 요약: 성능 향상 (동시성) 은 MVCC/SI 가 주로 담당하고, 정합성 확보는 SSI·범위락·DB 제약·애플리케이션 락으로 보완한다.

  • 실무 권장 패턴: 대부분 시스템은 혼합 전략(일반 작업은 SI/낙관적, 핵심 트랜잭션은 SSI/범위락 또는 DB 제약) 으로 운영한다. 적용 전에는 충돌률·핫스팟·비즈니스 민감도를 계량화해 정책을 정하라.

Write Skew 의 한계와 실무적 완화책

Write Skew 를 막으려면 _ 일관성 확보 수단 _ 을 도입해야 하는데, 그 수단들은 보통 성능 저하·운영 복잡성·확장성 제약을 함께 가져온다.

강한 일관성 (Serializable/범위 락) 은 안전하지만 느리고, 느슨한 일관성 (SI/낙관적) 은 빠르지만 write skew 가 생길 수 있다. 실무에서는 * 비용 (성능)* 과 * 리스크 (무결성)* 를 저울질해 부분 적용 또는 애플리케이션 레벨 보완을 사용한다.

Write Skew 의 주요 단점 표
단점설명원인실무 영향완화/해결 방안대안 기술
재시도 비용 (SSI)충돌 시 트랜잭션 롤백 (예: SQLSTATE 40001)직렬화/충돌 탐지 메커니즘지연·재시도 폭주·자원 낭비지수 백오프, 멱등 설계, 재시도 한계2PL, 애플리케이션 집계
락 경합 (2PL)강한 락으로 동시성 저하·데드락장기간 락 보유, 넓은 범위 잠금Throughput 저하·타임아웃인덱스 최적화, 트랜잭션 단축, 락 순서 규약SSI(부분 보완)
제약 복잡성복잡 불변식으로 운영·유지보수 부담복합 도메인 규칙코드·DB 동기화 문제, 버그 증가불변식 단순화, 설계 가이드, 테스트 강화SSI(자동 보호 일부)
분산 확장성 한계샤딩된 환경에서 전역 불변식 유지 어려움데이터 분산·파티션전역 트랜잭션 필요, 높은 지연파티션 재설계, Sagas, 합의 스토어Spanner/Calvin, 이벤트 소싱
  • 핵심: 단점은 _ 일관성을 위해 투입한 비용 _ 이 곧 발생하는 문제들 (지연·대기·복잡도) 이다. 완화는 기술적 (백오프, 인덱스, 재설계)·운영적 (재시도 정책, 테스트) 조합으로 수행해야 효과적이다.
환경 기반 제약사항 표
제약사항설명원인영향완화/해결 방안대안 기술
ORM 기본 설정Lazy load·비잠금 읽기 기본값 노출프레임워크 편의성Write Skew 노출, 트랜잭션 오용트랜잭션 경계 명확화, 락 힌트, 명시적 SQL명시 SQL/Stored Proc
인덱스 부재범위 잠금 비효율·스캔 증가설계 미비잠금 범위 확대·성능 저하복합 인덱스, 통계 갱신SSI(일부 보완)
격리 수준 선택 한계Serializable 은 성능 저하 유발성능·일관성 트레이드오프처리량 감소·재시도 증가선택적 직렬화, 하이브리드 전략분산 일관성 DB
샤딩/마이크로서비스전역 불변식 구현 난해데이터 분산전역 락/2PC 필요, 지연파티션 재설계, Sagas글로벌 일관성 DB
  • 핵심: 제약사항은 환경 (도구·구조) 이 제공하는 한계로 인해 특정 해법 적용이 어렵게 만든다. 이를 해결하려면 **설계 (인덱스·파티셔닝) 와 운영 (트랜잭션 경계·ORM 설정)**을 함께 고쳐야 한다.

Write Skew 트레이드오프 & 하이브리드 전략

  • 문제 맥락: 데이터베이스에서 ’ 정확한 상태 ’ 를 보장하려면 트랜잭션 격리 수준을 높여야 하지만, 격리 수준을 높이면 동시에 처리할 수 있는 작업 수가 줄어들어 성능이 떨어진다. Write Skew 는 이런 트레이드오프가 실제로 문제를 일으키는 대표 사례다.

  • 핵심 쟁점 (짧게):

    • SI: 빠르지만 일부 복합 제약 위반 허용 → Write Skew 가능.
    • SERIALIZABLE/SSI: 안전하지만 재시도·오버헤드 발생.
    • 실무: 모든 트랜잭션을 직렬화하기보다 중요 트랜잭션 식별 → 고격리 적용, 또는 애플리케이션 레벨 해결을 조합해 사용.
SI Vs Serializable 비교표
비교 축Snapshot Isolation (SI)Serializable / SSI
핵심 장점높은 동시성·읽기 성능완전한 직렬성·정확성
핵심 단점write-skew 등 이상 허용충돌·abort 로 처리량 저하
성능 영향낮은 지연, 높은 처리량재시도·락으로 처리량 감소
구현·운영 복잡도낮음 (일반 MVCC)높음 (충돌 탐지·모니터링)
적합 사례웹 트래픽, 읽기많은 서비스금융, 핵심 비즈니스 트랜잭션
실무 대안애플리케이션 검증·재시도선택적 직렬화, 모니터링

성능 (처리량/지연) 과 일관성 (데이터 무결성) 은 반비례 경향이 있다. SI 는 처리량을, Serializable 은 무결성을 우선한다. 실무에서는 워크로드별로 어느 쪽을 우선할지 기준을 세우고 (예: 금전·법적 영향이 큰 트랜잭션은 무결성 우선), 하이브리드로 보완하는 것이 현실적 해법이다.

Write Skew 하이브리드 대안 비교표
방법구성 요소적용 목적장점고려사항/단점
선택적 직렬화 (Selective)트랜잭션 분류 (critical vs normal), 격리 설정 정책핵심 불변식만 강제해 전체 성능 보전중요한 경로 무결성 확보·전체 성능 저하 제한트랜잭션 분류 실수 위험, 복잡한 정책 관리.
SELECT FOR UPDATE / 명시잠금읽기 시점 행 잠금, 잠금 해제 시점 관리읽은 정보로 결정하는 트랜잭션 간 충돌 방지확실한 충돌 차단 (애플리케이션 제어)잠금 경합·데드락·지연 유발.
Sentinel / Materialize Conflictsentinel 행/집계 같이 업데이트충돌을 강제하여 DB 가 하나를 abort 하게 유도DB 수준 충돌 감지 활용, 간단 구현 사례 많음추가 업데이트 오버헤드, 설계·정합성 유지 필요.
낙관적 버전 + 재시도버전 칼럼/ETag, 재시도 로직 (백오프)충돌 드문 환경에서 효율 유지높은 처리량 유지, 단순 구현 가능재시도 비용·사용자 영향·복잡성 존재.
엔진 수준 개선 (SSI 등)SSI 알고리즘·충돌 추적·인덱스 최적화MVCC 장점 유지하면서 직렬성 보장읽기·쓰기 분리 이점 유지, 일관성 보장엔진 복잡도·운영 오버헤드·abort 가능.

요약: 하이브리드 방법은 **정확성 향상 (또는 충돌 회피)**과 성능 유지 사이에서 서로 다른 지점을 선택한다. 운영에서는 트랜잭션 특성 (충돌 가능성, 응답성 요구, 실패 복구 용이성) 에 따라 적절한 하이브리드 조합을 설계해야 한다. 예를 들어 빈번한 충돌이 예상되는 경로에선 SELECT FOR UPDATE 나 직렬화 적용, 충돌이 드문 대량 처리 경로에선 SI+ 재시도 전략을 택하는 식이다.

Write Skew: 적용 적합성·운영 가이드

Write Skew 대응은 한마디로 위험도 기반 선택이다. 읽기 많은 서비스에선 Snapshot Isolation 을 써서 성능을 확보하고, 돈·안전처럼 핵심 규칙이 깨지면 안 되는 영역만 격리 수준을 올리거나 잠금/애플리케이션 검증을 더해 보호한다. 적용 전에는 어떤 쿼리와 불변식이 위험한지 찾아내고 (분석), 변경은 단계적으로 적용해 (설계) 모니터링 (운영) 으로 검증해야 한다.

Write Skew 적용 적합성 평가와 운영 전략
  • 읽기 중심이면서 불변식 위험이 낮고 핫스팟이 크지 않은 서비스: Snapshot Isolation(혹은 SSI 로 성능 - 정합 균형) 을 1 차 선택.
  • 핵심 무결성이 최우선인 서비스 (금융·의료·결제 등): Serializable(혹은 SSI + 추가 잠금/재검증) 적용 권장.
  • 대규모 혼합 워크로드: Hybrid(선별적 직렬화 + 애플리케이션 레벨 검증 + 파티셔닝) 전략 권장.
설계 관점 (Design)
  • 데이터 경계 정의: 불변식이 적용되는 도메인 경계를 명확히 나눠, 핵심 도메인만 강격리 적용.
  • 모델 선택: 충돌 가능 영역은 집계 행 (single-row counters) 혹은 CQRS 로 분리해 충돌률을 낮춘다.
  • 락 전략 설계: 범위·읽은 집합을 잠그는 전략 (선택적 SELECT … FOR UPDATE) 을 설계해 불변식 보호.
분석 관점 (Analysis)
  • 리스크 평가: 불변식 위반 시 비즈니스 영향 (금전·안전·법적 리스크) 을 정량화해 격리 레벨 결정 근거로 사용.
  • 성능 트레이드오프 분석: SSI/Serializable 적용 전후로 벤치마크 (throughput, latency, abort rate) 비교.
  • 데이터 분포 분석: 핫 - 키, 파티션 스키마, 쓰기 집중 구간을 분석해 파티셔닝/샤딩 필요 여부 판단.
운영 관점 (Operations)
  • 모니터링·알림: 재시도율, serialization failures, deadlocks, 비즈니스 무결성 체크 실패 등을 실시간 모니터링.
  • 운영 플레이북: 무결성 위반 발생 시 우선격리 상향, 트래픽 셰이핑, 롤백·수정 절차 등 대응 시나리오 준비.
  • 점진 적용·테스트: Canary/배치별로 격리 설정 변경 후 관측 (사전 자동 동시성 테스트 권장).
Write Skew 적용 적합성 판단표
시나리오 유형권장 기본 전략보완 조치 (필요 시)고려 포인트 (설계·운영)
읽기 - 중심 대규모 서비스 (예: 콘텐츠, 피드)Snapshot Isolation (SI)모니터링, 불변식 테스트핫스팟 여부, 낮은 불변식 민감도
사용자 참여 많은 실시간 서비스 (예: 예약, 이벤트)SI 우선 + 핫 - 스팟 차단 (파티셔닝)특정 경합 영역에 FOR UPDATE동시 쓰기 패턴, 배치 삽입 시간대
핵심 금융/의료/결제Serializable 또는 SSI읽은 집합 잠금, DB 제약, 애플리케이션 재검증비즈니스 리스크·감사요구
혼합 워크로드 (읽기 + 쓰기 모두 높음)Hybrid(선별적 격리 상향)CQRS/집계 분리, 파티셔닝도메인 경계 정의·테스트 계획
배치/ETL 중심 (대량 삽입)SI + 배치 격리 처리 (창구화)일괄처리 창구·동시성 제어배치 시간대·리소스 스케줄링
  • 원칙: 성능 우선인가, 무결성 우선인가를 먼저 결정하고 그에 따라 격리 전략을 선택하라.

  • 실무흐름: 위험 식별 → 기본 전략 (SI 권장) 적용 → 핵심 도메인에 보완 (잠금/Serializable) → 성능·무결성 테스트 → 운영 모니터링.

  • 운영 팁: 격리 상향은 전체 시스템에 적용하기보다 도메인 단위로 점진 적용하고, 재시도·abort 상황을 자동화·관측해야 안전하다.

실무 적용 및 사례

실습 예제 및 코드 구현

실습 예제: 병동 온콜 불변식 (최소 1 명)
목적
  • SI 에서 Write Skew 발생을 재현하고, SERIALIZABLE 과 잠금 기반 해결을 체득.
사전 요구사항
  • PostgreSQL 14+ (로컬), psql
단계별 구현
  1. 스키마 및 시드

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    
    DROP TABLE IF EXISTS doctors;
    CREATE TABLE doctors (
      id SERIAL PRIMARY KEY,
      ward TEXT NOT NULL,
      name TEXT NOT NULL,
      on_call BOOLEAN NOT NULL
    );
    INSERT INTO doctors(ward, name, on_call) VALUES
    ('A','Alice', TRUE),
    ('A','Bob',   TRUE);
    
  2. Write Skew 재현 (REPEATABLE READ≈SI)

    • 세션 1:

      1
      2
      3
      4
      
      BEGIN ISOLATION LEVEL REPEATABLE READ;
      SELECT count(*) FROM doctors WHERE ward='A' AND on_call=TRUE; -- 기대: 2
      UPDATE doctors SET on_call=FALSE WHERE name='Alice';
      -- COMMIT는 잠시 보류
      
    • 세션 2:

      1
      2
      3
      4
      
      BEGIN ISOLATION LEVEL REPEATABLE READ;
      SELECT count(*) FROM doctors WHERE ward='A' AND on_call=TRUE; -- 기대: 2 (스냅샷)
      UPDATE doctors SET on_call=FALSE WHERE name='Bob';
      COMMIT; -- 성공
      
    • 세션 1:

      1
      2
      
      COMMIT; -- 성공 → 결과적으로 on_call=0 (불변식 위반)
      SELECT count(*) FROM doctors WHERE ward='A' AND on_call=TRUE; -- 0
      
  3. 해결 1: SERIALIZABLE(SSI)

    • 초기화 후 재실행, 차이만 표시:

       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      
      TRUNCATE doctors RESTART IDENTITY;
      INSERT INTO doctors(ward, name, on_call) VALUES ('A','Alice',TRUE),('A','Bob',TRUE);
      -- 세션1
      BEGIN ISOLATION LEVEL SERIALIZABLE;
      SELECT count(*) FROM doctors WHERE ward='A' AND on_call=TRUE; -- 2
      UPDATE doctors SET on_call=FALSE WHERE name='Alice';
      -- 세션2
      BEGIN ISOLATION LEVEL SERIALIZABLE;
      SELECT count(*) FROM doctors WHERE ward='A' AND on_call=TRUE; -- 2
      UPDATE doctors SET on_call=FALSE WHERE name='Bob';
      COMMIT; -- 둘 중 한 세션이 여기 또는 다음 COMMIT에서 40001로 롤백됨
      -- 세션1
      COMMIT; -- 40001 Serialization failure 발생 가능 → 재시도 필요
      
  4. 해결 2: 가드 행 + 명시적 잠금

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    
    -- 가드 테이블: 병동별 on_call 수 카운트
    CREATE TABLE ward_guard (
      ward TEXT PRIMARY KEY,
      on_call_count INT NOT NULL
    );
    INSERT INTO ward_guard VALUES ('A', 2);
    
    -- 트리거로 유지(단순화 예시)
    CREATE OR REPLACE FUNCTION upd_guard() RETURNS trigger AS $$
    BEGIN
      IF NEW.on_call <> OLD.on_call THEN
        UPDATE ward_guard SET on_call_count = on_call_count + (CASE WHEN NEW.on_call THEN 1 ELSE -1 END)
        WHERE ward = NEW.ward;
      END IF;
      RETURN NEW;
    END;
    $$ LANGUAGE plpgsql;
    
    DROP TRIGGER IF EXISTS trg_doctors_guard ON doctors;
    CREATE TRIGGER trg_doctors_guard AFTER UPDATE ON doctors
    FOR EACH ROW EXECUTE FUNCTION upd_guard();
    
    -- 세션1
    BEGIN;
    SELECT on_call_count FROM ward_guard WHERE ward='A' FOR UPDATE; -- 가드 행 잠금
    UPDATE doctors SET on_call=FALSE WHERE name='Alice';
    -- 세션2는 같은 가드 행에서 대기 또는 타임아웃
    
실행 결과
  • REPEATABLE READ: Write Skew 재현.
  • SERIALIZABLE: 한 트랜잭션이 **Serialization Failure(40001)** 로 중단 → 재시도 시 불변식 유지.
  • 가드 행: 두 세션이 동일 행에 WW 충돌 → 순차화.
추가 실험
  • SELECT … FOR UPDATE 로 프레디킷을 인덱스 범위로 잠그는 설계 비교.
  • 충돌 빈도에 따른 재시도 백오프 파라미터 실험.

Phase 6: 운영 및 최적화

Write Skew 관측·모니터링 실무 가이드

Write Skew 등의 직렬성 이상을 잡으려면 직렬화 실패 (40001), 데드락 (40P01), 락 대기 시간, 애플리케이션 재시도 빈도, 그리고 핫 로우 (키별 집중) 같은 지표를 모니터링해야 한다.
DB 내 pg_locks·pg_stat_activity 를 정기 조회하고, 에러 로그와 exporter(예: postgres_exporter) 를 통해 메트릭을 Prometheus/Grafana 나 SIEM 으로 집계하면 실시간 탐지·알람·포렌식이 가능하다.
임계값 (알람) 은 워크로드·SLA 에 맞춰 실험적으로 정하라.

Write Skew 관측 카테고리
시그널 메트릭 (에러·지연 중심)

serialization_failure_rate(SQLSTATE 40001), deadlock_rate(40P01), lock_wait_ms(avg/95p), retry_count.
이 지표들은 직렬성 위반·락 경합·재시도 과부하를 조기에 감지한다. 알람 예: 5 분간 serialization_failure_rate > 0.5% → P1 알람.

지표왜 보는가구현 예
serialization_failure_rate직렬성 위반 (직접 신호)DB 로그/애플리케이션 에러 → Prometheus counter
deadlock_rate락 정책 문제·교착DB 로그 (40P01) 파싱 → SIEM 이벤트
lock_wait_ms성능저하 전조pg_locks/pg_stat_activity → exporter metric
retry_count재시도 과부하앱 레이어 로그 → central metrics
  • 시그널 메트릭은 Write Skew 가능성 뿐 아니라 운영성 문제 (지연·재시도 과부하) 를 빠르게 알려주는 역할을 한다. 직렬화 오류 (40001) 는 반드시 수집·집계해 재시도 정책과 연동하라.
락·세션 관측 (상태·그래프 중심)

pg_locks, pg_stat_activity 정기 스냅샷 및 deadlock 그래프 캡처.
블로킹/대기 세션 트리거 시 자동 스냅샷 (locks + queries) 저장.

항목왜 보는가구현 예
pg_locks 스냅샷누가 무엇을 잠그는지 파악주기 cron job 또는 트리거 시 수집
pg_stat_activity세션별 현재 쿼리 상태대기 중인 쿼리·트랜잭션 길이 확인
deadlock graph교착 원인 분석deadlock 발생 시 자동 수집 스크립트
  • 락·세션 관측은 문제의 근본 원인 (누가, 어떤 쿼리가 락을 잡고 있는지) 을 파악하는 데 필수적이다. deadlock 발생 시 즉시 그래프를 캡처해 원인분석에 사용하라.
애플리케이션 레벨 지표 (재시도·비즈니스 실패)

애플리케이션에서 발생한 retry_count, 재시도 후 성공률, idempotency 실패 로그, 비즈니스 규칙 위반 알람 등.
재시도 로직의 폭주 여부를 감지해 자동 백오프·큐잉 유도.

항목왜 보는가구현 예
retry_count재시도 과부하 감지미들웨어/라이브러리에서 카운트 노출
retry_success_rate재시도 효과성 평가성공/총 재시도 비율 계산
business_violation_events규칙 위반 감지애플리케이션 레벨 감사 이벤트
  • 애플리케이션 지표는 DB 알람과 결합해 전체 워크플로의 건강도를 판단하게 해준다. 재시도 증가와 직렬화 실패가 함께 나타나면 자동화 대책을 검토하자.
핫스팟/스케일 지표 (키·노드 중심)

특정 키·인덱스에 집중된 요청 (QPS), 노드별 리소스·latch contention, 샤드별 트래픽 편중 등. 핫스팟이 확인되면 샤딩·파티셔닝·레디스 캐시 등 아키텍처적 대응을 검토.

항목왜 보는가구현 예
key QPS 분포특정 키 집중 확인pg_stat_statements + 로그 파싱
node contention분산 DB 노드 문제벤더 콘솔/노드 메트릭
index contention인덱스 락 집중index-level statistics 수집
  • 핫스팟은 시스템 전반 성능·정합성에 악영향을 준다. 조기 탐지로 샤드·캐시·데이터 모델 변경을 통해 충돌을 국지화하라.
Write Skew 관측 통합 대시보드 항목
카테고리핵심 메트릭/로그목적우선순위
시그널 메트릭serialization_failure_rate(40001), deadlock_rate(40P01), lock_wait_ms, retry_count이상 탐지·알람높음
락·세션 관측pg_locks, pg_stat_activity, deadlock graph원인 분석 (누가,무엇을)높음
애플리케이션 지표retry_count, retry_success_rate, business_violation_events재시도/비즈니스 영향 파악높음
핫스팟 지표key QPS 분포, index contention, node resource확장성·샤딩 판단 근거중~높

이 네 카테고리를 통합한 대시보드는 Write Skew·직렬성 이상을 조기에 탐지하고, 원인 분석→자동화 대응→아키텍처 개선으로 이어지는 운영 루프를 완성한다. 먼저 serialization_failure_ratepg_locks 기반 알람을 구성하고, 이후 애플리케이션 재시도·핫스팟 분석을 추가하라.

6.2 보안 및 컴플라이언스

Write Skew 는 동시 트랜잭션이 같은 판단 근거로 행동해 전역 규칙을 깨는 현상이다.
보안·컴플라이언스 관점에서는 단순 성능 조치로 해결되지 않으므로, 권한 통제, 트랜잭션 복구 정책, 멱등성/아웃박스 패턴, 불변의 감사 로그, 데이터 암호화, 그리고 모니터링을 조합해 리스크를 관리해야 한다.
규제 업종은 특히 증적 보관·무결성·접근 통제가 엄격하다.

Write Skew 보안·컴플라이언스 카테고리

접근 제어 & 거버넌스

접근 제어는 누가 어떤 트랜잭션을 실행할 수 있는지를 제한해, 권한 남용이나 오작동으로 인한 불변식 위반을 방지한다. 실무적 적용으로는 RBAC, 최소 권한, 서비스 계정 분리, 운영자 액션 감사 (log of admin actions) 를 둔다. 규제 요건 (감사·접근 통제) 을 매핑해 권한 부여·검토 주기를 정한다.

트랜잭션 안전성 & 롤백

트랜잭션 안전성은 실패 시 데이터 일관성을 보장하는 메커니즘과 복구 절차를 포함한다. 자동 재시도는 멱등성 전제하에 적용하고, 복구 불가능한 실패엔 보상 (Saga) 또는 수동 복구 절차를 문서화한다. 또한 트랜잭션 실패에 대한 알림·수정 프로세스를 운영에 포함한다.

멱등성 & 아웃박스

멱등성은 동일 요청을 여러 번 적용해도 결과가 동일하도록 설계하는 것 (요청 토큰, idempotency key). 아웃박스 패턴은 DB 트랜잭션과 이벤트 발행을 원자적으로 묶어 분산 불일치 위험을 줄인다. 두 패턴은 재시도·비동기 통합에서 필수적이다.

감사 추적 & 증적 보존

트랜잭션 로그·변경 이력·트랜잭션 ID·버전 정보를 불변 (append-only) 으로 보관하고, 보관 기간·무결성 (암호화·서명) 을 규정에 맞춰 설정한다. 포렌식·감사 요청 시 재현 가능하도록 메타데이터를 포함해 저장한다.

데이터 보호 (암호화·키관리)

민감 데이터는 전송·저장에서 암호화하고, 키 관리는 중앙화 (KMS/HSM) 하여 접근·사용을 통제한다. 데이터 최소화·익명화 정책도 병행해 규제 위험을 축소한다.

모니터링·경보·운영 정책

충돌률, 재시도 실패율, 직렬화 실패 (HTTP 40001 등), lock-wait 등을 지표로 수집하고, 임계치 초과 시 자동 정책 (일시적 격리 상향, 트래픽 제한) 실행한다. Jepsen 스타일 검증을 주기적으로 실행해 실환경 가설 검증을 권장한다.

쓰기스큐 보안 종합 실행표

영역주요 조치목적운영 지표 (예시)
접근 통제RBAC, 세분화된 DB 권한권한 오남용 방지관리자 액션 로그 수, 권한 변경 빈도
트랜잭션 복구멱등 재시도, Saga, 보상실패 시 무결성 유지재시도율, 보상 성공률
아웃박스·멱등성Outbox 테이블, idempotency key분산 이벤트 일관성Outbox 미전송 건수, 소비자 중복률
감사·증적변경 이력, 불변 로그, 서명규제 증빙·포렌식감사로그 보관완료율, 검색 응답시간
데이터 보호TLS/TDE, KMS 관리데이터 유출 방지암호화 적용률, 키 회전 주기
모니터링충돌률, serial failures, lock-wait조기 경보·자동 조치충돌률 (%), 직렬화 실패 건수

Write Skew 성능·확장 최적화 전략

Write Skew 같은 동시성 문제는 일관성 강화를 위해 모든 트랜잭션을 무조건 직렬화하면 성능이 급격히 떨어진다.
그래서 실무에서는 짧은 트랜잭션 유지·인덱스 튜닝으로 락 범위를 줄이고, 핵심 경로만 높은 격리 적용, 지수 백오프 재시도와 같이 성능과 일관성의 균형을 맞춘다. 대규모일수록 샤딩·캐시·비동기 처리를 통해 충돌 표면을 분할·완화하는 것이 핵심이다.

Write Skew 성능·확장 카테고리

재시도·백오프 정책
  • 내용: 충돌 (직렬화 실패·낙관적 잠금 충돌) 시 재시도 로직을 지수 백오프로 구현하고 재시도 횟수 제한과 랜덤 지터를 추가한다. 재시도 시 멱등성(idempotency key) 확보가 필수.

  • 구현 팁: base=100ms, 재시도 n 일 때 delay = base * 2^n ± rand(0, base); 최대 재시도 3~5 회; 실패 시 사용자 피드백 또는 작업 큐로 이관.

항목목적구현 예주의점
지수 백오프 + 지터재시도 폭주 방지base*2^n ± jitter멱등성 미보장 시 중복 문제
최대 재시도 제한자원 낭비 방지maxRetries=3~5사용자 경험 고려
멱등키중복 처리 방지request_id 토큰토큰 저장소 필요 (짧은 TTL)
  • 요약: 재시도는 필수지만 제어하지 않으면 시스템을 망가뜨린다. 지수 백오프·지터·멱등성 조합으로 안전하게.
트랜잭션·락 설계
  • 내용: 트랜잭션을 짧게 유지하고, 불가피한 경우 핵심 행만 SELECT … FOR UPDATE 로 잠그거나 핵심 경로만 Serializable 로 설정한다. 인덱스를 통해 락 범위를 좁힌다.

  • 구현 팁: EXPLAIN 으로 범위 스캔 확인, 트랜잭션 내 외부 호출 제거, 필요 시 저장 프로시저로 원자화.

항목목적구현 예주의점
트랜잭션 단축락 보유 시간 최소화읽기 후 계산, 쓰기만 트랜잭션외부 I/O 제거 필요
행 수준 잠금충돌 방지 (핫스팟)SELECT … FOR UPDATE동시성 저하 가능
혼합 격리부분적 직렬화 적용핵심 API 만 Serializable운영 복잡성 증가
  • 요약: 락·격리 수준을 좁게·선택적으로 적용해 성능을 지켜라.
데이터 접근 패턴 (인덱스·캐시)
  • 내용: 인덱스를 통한 범위 축소로 락 효과를 높이고, 읽기 부담은 캐시로 오프로드한다. 쓰기 직후의 일관성 보장은 세션 강제 마스터 읽기나 캐시 무효화 전략으로 보완.

  • 구현 팁: EXPLAIN → 복합 인덱스 추가, 캐시에는 쓰기 후 즉시 무효화 또는 이벤트 기반 동기화.

항목목적구현 예주의점
인덱스 튜닝락 범위 축소복합 인덱스, 커버링 인덱스인덱스 비용 (쓰기 비용)
캐싱읽기 부하 완화Redis, TTL, pub/sub 무효화캐시 일관성 관리 필요
마스터 강제 읽기스테일 리드 방지세션 레벨 설정리플리카 부하 고려
  • 요약: 선제적 인덱스와 캐시 전략으로 DB 충돌 표면을 줄여라.
아키텍처적 확장 (샤딩·분산락·CQRS)
  • 내용: 도메인 분할 (샤딩) 으로 충돌 범위를 줄이고, 글로벌 불변식은 분산 락이나 이벤트 방식으로 처리. 쓰기·읽기 분리, CQRS 로 확장성 확보.

  • 구현 팁: 샤드 키는 균등 분포 목표, 분산 락은 TTL·리더 선출로 안전성 확보, CQRS 시 보상 트랜잭션 설계.

항목목적구현 예주의점
샤딩충돌 도메인 분리user_id % N 샤드크로스샤드 트랜잭션 비용
분산 락글로벌 불변식 보장etcd / Redis RedLock네트워크 지연·가용성 고려
CQRS / 이벤트확장성·비동기 처리Command queue + read model복잡성·운영 부담 증가
  • 요약: 샤딩·분산락·CQRS 는 강력하지만 설계·운영 비용이 크다—꼭 필요한 곳에만 적용하라.
운영·모니터링
  • 내용: 재시도율, 직렬화 실패율, 락 대기 p95/p99, 트랜잭션 길이 등의 지표로 성능·충돌을 관측하고 자동화된 런북으로 1 차 대응을 실행.

  • 구현 팁: Prometheus + Grafana, OpenTelemetry, 알람 임계값 (예: 직렬화 실패 >0.5% 경고).

지표목적임계값 예시대응
재시도율충돌 빈도 감지>2% 경고백오프 조정, 패치
직렬화 실패율SSI/Serializable 문제 신호>0.5% 심각핵심 경로 점검
락 대기 p95락 경합 탐지p95 > 2000ms트랜잭션 분해
  • 요약: 계측 (모니터링) 은 모든 설계의 필수 전제—지표 기반으로 조치하라.

Write Skew 대응 종합 전략표

카테고리핵심 기법목적구현 포인트
재시도 · 백오프지수 백오프 + 지터, 멱등키, 재시도 한도재시도 폭주/리소스 낭비 방지base delay, maxRetries, 멱등성 확보
트랜잭션·락 설계트랜잭션 단축, 행 잠금, 혼합 격리락 보유시간·경합 최소화EXPLAIN, FOR UPDATE, 핵심만 Serializable
데이터 접근인덱스 튜닝, 캐시, 마스터 강제 읽기락 범위 축소·읽기 부하 완화복합 인덱스, 캐시 무효화 전략
아키텍처 확장샤딩, 분산 락, CQRS샤드 단위 충돌 축소·확장성 확보샤드키 설계, TTL 락, 이벤트소싱
운영·관측재시도율·직렬화 실패·락 p95 모니터링조기 경보·자동화 대응Prometheus/Grafana, Runbook

6.4 트러블슈팅 및 문제 해결

Write-Skew 트러블슈팅 종합 가이드

  • 증상: 간헐적으로 집계·제약이 깨져 결과가 틀림.
  • 원인: 동시 트랜잭션이 같은 스냅샷을 보고 서로 다른 행을 바꿔도 DB 가 이를 막지 못하는 상황 (=write-skew).
  • 당장 해야 할 일: 문제 트랜잭션 찾아 재현 → 임시로 해당 경로에 락 적용 또는 격리 상향 → 근본적으로는 버전검사·원자적 업데이트·DB 제약으로 해결.
  • 중요: 프로덕션 격리 변경은 비용 (성능/가용성) 을 수반하므로 단계적으로 적용하고 모니터링해야 한다.
왜 발생하는가 (근본 원인)
  • 동시 트랜잭션이 같은 시점의 스냅샷을 읽고 서로 다른 행을 갱신할 때, 쓰기 - 쓰기 충돌이 명시적으로 없으면 SI 등 낮은 격리에서 커밋을 허용하여 비즈니스 불변식을 위배한다 (=write-skew).
  • 또한 핫 파티션 (동일 키/범위에 집중된 트래픽), 잘못된 인덱스 또는 조건 기반 업데이트가 원인을 악화시킨다.
무엇으로 어떻게 해결하는가 (구체적 수단)
  • 단기 완화 (빠른 대응)

    1. 문제 트랜잭션을 식별해 임시로 해당 경로에 SELECT … FOR UPDATE 같은 비관적 잠금 적용.
    2. 문제 범위가 좁으면 격리 수준을 Serializable(또는 DB 의 SSI 활성화) 로 높여 보수적으로 처리 (단, 카나리아/제한 적용).
    3. 임시로 해당 키에 애플리케이션 락 (Advisory lock) 적용.
  • 근본 해결 (설계/코드 변경)

    1. 원자적 SQL로 표현 가능한 연산은 DB 쪽으로 위임 (UPDATE … WHERE version = x 또는 UPDATE accounts SET bal = bal +? WHERE id=?).
    2. 낙관적 락 (버전 컬럼) + 재시도 로직 도입 (지수 백오프 + 지터).
    3. 비즈니스 불변식은 DB 제약 (CHECK, EXCLUSION, UNIQUE) 또는 가드 행 (집계 행) 으로 모델링.
    4. 핵심 트랜잭션은 SSI/Serializable 로 처리하고 일반 트랜잭션은 SI 로 운영하는 하이브리드 전략 도입.
  • 운영 보완

    1. 충돌·재시도·abort 지표화 (모니터링→경보).
    2. 정기적 동시성 스트레스 테스트 및 재현 시나리오 자동화.
    3. 감사 로그·CDC 기반 포렌식과 복구 절차 준비.
Write-Skew 트러블슈팅
탐지·탐색 (Detection & Triage)

증상 식별과 우선순위 분류 단계.

  • 핵심 활동:
    • 사용자 리포트·경고 수집 (에러/무결성 불일치)
    • 관련 트랜잭션 ID·타임스탬프·쿼리 패턴 확보
    • 초기 영향 범위 결정 (테이블/파티션/서비스)
  • 도구/명령 예:
    • PostgreSQL: pg_stat_activity, pg_locks, pg_stat_wal
    • MySQL: SHOW PROCESSLIST, SHOW ENGINE INNODB STATUS
    • 애플리케이션 로그, APM(트레이스)
항목목적도구/증거
에러/리포트 수집문제 인지Sentry/로그/유저 리포트
트랜잭션 식별원인 트래픽 타겟tx id, timestamp
초기 영향 범위긴급도 판정테이블/파티션 목록
  • 핵심: 문제를 빠르게 탐지하고 영향 범위를 좁혀 우선순위를 정하라.
재현·분석 (Reproduction & Root Cause)

원인 재현과 근본 원인 분석 단계.

  • 핵심 활동:
    • 스테이징에서 동시성 재현 (다중 세션, sleep 타이밍)
    • EXPLAIN ANALYZE 로 실행계획 확인
    • 락/대기 로그, deadlock 로그 분석
    • WAL/Redo 또는 CDC 로 커밋 시퀀스 검증
  • 도구/명령 예:
    • SQL 스크립트 (동시 트랜잭션), EXPLAIN, SHOW ENGINE INNODB STATUS, pg_waldump
항목목적도구/증거
동시성 재현문제 원인 확인동시 스크립트/트랜잭션 시뮬레이터
락·대기 분석잠금 원인 규명pg_locks / innodb status
로그 타임라인커밋 시퀀스 검증WAL / binlog / CDC
  • 핵심: 재현 가능한 시나리오를 만들고 로그로 타임라인을 검증하면 근본 원인을 정확히 파악할 수 있다.
단기 완화 (임시 대책) (Immediate Mitigation)

프로덕션 영향 최소화를 위한 신속한 조치.

  • 핵심 활동:
    • 문제 트랜잭션에 대한 SELECT … FOR UPDATE 적용 (범위 제한)
    • 키·범위에 advisory lock(앱 레벨) 적용
    • 제한적 격리 상향 (카나리아/특정 서비스에만)
    • 트래픽 셰이딩 (핫파티션 임시 분리)
  • 도구/명령 예:
    • SQL 변경 (롤링 적용), 앱 레벨 락 코드, 트래픽 라우팅
항목목적실행 예
FOR UPDATE 적용즉시 일관성 확보특정 쿼리 변경
Advisory Lock분산 락 적용Redis/DB advisory lock
격리 상향 (카나리아)근본 변경 전 임시 보호SERIALIZABLE on subset
  • 핵심: 임시완화는 최소범위·단기간 적용하고 영향 (성능) 을 면밀히 모니터링하라.
근본 해결 (설계/코드) (Permanent Fixes)

재발 방지 위한 설계·코드 변경.

  • 핵심 활동:
    • 원자적 SQL 또는 version 기반 낙관적 락 구현
    • DB 제약 (CHECK/EXCLUSION/UNIQUE) 추가
    • 핵심 트랜잭션을 SSI/Serializable 로 전환 (선별 적용)
    • CQRS/파티셔닝/leader-per-shard 등 아키텍처 변경
  • 도구/명령 예:
    • DB 마이그레이션 (제약 추가), 코드 배포, 테스트 자동화
항목목적구현 예
원자적 SQL네트워크/중간상태 제거UPDATE … WHERE version =?
DB 제약 추가무결성 강제CHECK / UNIQUE / EXCLUSION
하이브리드 격리비용 - 효율적 정합성SSI for critical
  • 핵심: 설계 변경은 충분한 테스트·롤아웃 계획 (카나리아) 과 모니터링을 동반해야 안전하다.
운영·모니터링 (Monitoring & Prevention)

지표 기반 탐지와 예방적 운영.

  • 핵심 활동:
    • 충돌률 (abort rate), 재시도 횟수, lock wait, P99 레이턴시 지표 수집
    • 경보 임계치 설정 및 자동화 대응 (서킷브레이커)
    • 정기 동시성 스트레스 테스트 및 회귀 테스트
  • 도구/명령 예:
    • Prometheus/Grafana, APM, Synthetic Tests
항목목적구현 예
충돌률 지표이상탐지prometheus metric
자동 경보신속 알림PagerDuty
정기 테스트회귀 방지CI 스트레스 테스트
  • 핵심: 측정 가능한 지표를 정하고 자동 경보와 주기적 테스트로 사전 예방하라.
회복·감사 (복구/포렌식) (Recovery & Forensics)

사건의 복구와 원인 증거 확보.

  • 핵심 활동:
    • WAL/binlog/CDC 기반 타임라인 복원 및 증거 수집
    • 무결성 검증 (체크섬), 복구 시나리오 실행 (restore drill)
    • 사후보고 (RCA) 와 교훈 문서화
  • 도구/명령 예:
    • pg_waldump, mysqlbinlog, Debezium CDC, WORM 보관소
항목목적도구
로그 기반 복구시계열 재구성WAL / binlog / CDC
복구 연습복구 능력 검증복원 시나리오
사후보고프로세스 개선RCA 문서
  • 핵심: 사건 증거를 안전히 보관하고 정기적으로 복구 능력을 검증하라.
Write-Skew 문제해결 요약표
카테고리핵심 목표대표 조치 (단기 → 중기 → 장기)대표 도구/지표
탐지·탐색빠르게 문제 인지·영향파악로그 수집 → tx id 확보 → 영향도 분류Sentry, pg_stat_activity, SHOW ENGINE
재현·분석근본 원인 규명스테이징 재현 → EXPLAIN/락 로그 분석EXPLAIN, pg_locks, innodb status
단기 완화프로덕션 영향 최소화FOR UPDATE / advisory lock / 카나리아 격리SQL 변경, App lock
근본 해결재발 방지 설계 적용version lock, DB 제약, SSI 적용마이그레이션, 코드배포
운영·모니터링사전 탐지·자동화 대응지표 채택 → 경보 → 정기 테스트Prometheus, Grafana, APM
회복·감사복구·증거 확보WAL/binlog 복구 → RCA → 문서화pg_waldump, mysqlbinlog, CDC
  • 핵심 흐름: 탐지 → 재현·분석 → 임시완화 → 근본해결 → 모니터링 → 회복 (사후분석).

  • 운영 규칙: 프로덕션 변경은 항상 제한적 (카나리아)·모니터링 기반으로 수행하고, 근본 해결은 충분한 재현·테스트 후 단계적으로 롤아웃하라.


최종 정리 및 학습 가이드

내용 종합

Write Skew 는 실무에서 특히 위험한 동시성 버그다. 두 트랜잭션이 동일한 조건을 읽고 (예: " 이 병동에 on_call 이 있나?”) 서로 다른 행을 변경하면, 각각의 로컬 판단은 옳지만 합쳐진 결과가 도메인 규칙을 위반할 수 있다. 예컨대 의사 A 와 B 가 각자 " 나만 off 처리하면 다른 사람이 남아있다 " 는 판단으로 동시에 off 를 처리하면 실제로는 아무도 남지 않는다.

기술적으로 SI(스냅샷 격리) 는 각 트랜잭션에 안정된 읽기 스냅샷을 제공하지만, 서로의 쓰기를 보지 못하므로 전역 불변식을 보장하지 못한다. 따라서 실무에서는 다음 중 하나 혹은 조합을 택한다.

  • 직렬화 (Serializable): DB 가 논리적 직렬화를 보장하지만 충돌 시 트랜잭션을 롤백하므로 재시도 비용 발생.
  • 비관적 락: 관련 리소스에 락을 걸어 문제를 예방하나 동시성·스루풋 손실과 데드락 위험 존재.
  • 애플리케이션 설계 변경: 불변식 경계를 좁혀 단일 행으로 묶거나 원자적 연산으로 처리하면 비용을 줄일 수 있다.
  • 분산 시스템 대책: 샤딩 경계 재설계나 Sagas 와 같은 보상 패턴을 통해 전역 일관성 요구를 낮추는 방법도 있다.

결론적으로 현실적 운영에서는 SSI/2PL/스키마 개선/앱 락의 혼합 전략으로 안전성과 성능을 균형 맞춘다.

실무 적용 가이드

단계작업 항목대상 (레벨)구현 예시장점주의사항
1불변식 식별 및 우선순위화비즈니스/도메인불변식 목록, 영향도 점수 (금전·안전성)보호 우선순위 명확화식별 누락 위험—리뷰 필요
2인덱스·범위 설계DB 쿼리/스키마인덱스 추가·쿼리 리팩토링, EXPLAIN범위 노출 축소 → 위험 감소인덱스 과다로 쓰기 비용 증가
3방어전략 선택 (권장 조합)DB / App / InfraDB: SERIALIZABLE/SSIApp: SELECT FOR UPDATE, sentinel rowInfra: Redis 분산락불변식 보호 (여러 층의 보강)성능 영향, 데드락·가용성 고려
4재시도·멱등성애플리케이션지수 백오프 + 지터, 멱등 토큰, max 3~5 회충돌 시 자동 복구·사용자 영향 최소화재시도 비용·UX 지연
5관측·알람·튜닝운영/모니터링지표: tx_latency, abort_rate, long_tx_count, undo_size조기탐지·원인분석 용이임계치 설정과 노이즈 관리 필요
6테스트·검증QA/스테이징재현 시나리오 (동시 트랜잭션 스크립트), 격리수준별 A/B 테스트실제 영향 확인·정책 검증스테이징이 프로덕션과 다를 수 있음
7운영 룰북 작성운영팀/개발팀deadlock victim 정책, 자동 rollback 기준 문서화신속 대응·책임소재 명확화룰 유지보수 필요

학습 로드맵

단계주제 범위학습 목표실습 (구체)평가 지표권장 도구
1 기초ACID, Read Committed / Repeatable Read / Serializable, MVCC 개념격리 수준과 이상 종류 이해두 세션 동시 UPDATE 재현 (Lost Update)데이터 일관성 위반 여부Postgres, MySQL
2 핵심Serialization Graph, Write Skew, Phantom읽기 - 쓰기 의존성 이해 및 재현On-call Write Skew 시나리오 실행무결성 위반 재현 여부Postgres(SI)
3 응용SELECT FOR UPDATE, 가드 행, 트리거·제약불변식 보호 패턴 적용 능력FOR UPDATE 적용 후 재검증, 집계 행 모델 적용abort 률, P99, 무결성 유지pgbench, EXPLAIN
4 고급SSI, Predicate Lock, Index Range Lock, 분산 트랜잭션고급 직렬성, 분산 불변식 설계SSI 켜고 성능 비교, 분산 트랜잭션 (2PC) 시뮬throughput, abort rate, 운영 복잡도OpenTelemetry, Jaeger, 2PC 툴

학습 항목 정리

단계항목목표실습/과제실무 연관성비고
기초ACID/트랜잭션 시작/종료트랜잭션 흐름 파악BEGIN/COMMIT/ROLLBACK 실습모든 서비스 필수문서 숙지
기초격리 수준 차이이상별 차이 재현Dirty/Lost/Non-repeatable 실습디버깅용EXPLAIN 병행
핵심Write Skew 재현SI 한계 직접 체감의사 on-call 예제 (2TX)예약/의료SQL 스크립트 제공
핵심Serialization Graph사이클 탐지 이해그래프 작성 연습설계 검토 도구수기 그래프/자동화 스크립트
응용SELECT FOR UPDATE읽은 집합 잠금 적용적용 후 성능/무결성 비교트랜잭션 보호록 웨이트 관찰
응용가드 행/집계 행충돌 영역 축소모델 변경 후 테스트이벤트·카운터 시스템CQRS 연계
고급SSI 내부충돌 검출 원리 학습SSI 활성화로 비교 실험고신뢰 시스템Postgres SSI
고급Predicate/Index Range Lock범위 잠금 이해INDEX 기반 갭락 실험범위 쿼리 많은 시스템인덱스 설계 병행
고급분산 불변식 설계전역 불변식 유지 전략2PC/사건 소싱 시나리오샤드된 시스템conflict resolution 설계

용어 정리

카테고리용어 (한글)—(영어 풀네임, 약어)정의 (간략)관련 개념실무 활용
핵심쓰기 스큐—(Write Skew)동일 판단 기반의 분산 쓰기로 비즈니스 제약 위반SI, RW 사이클핵심 트랜잭션 직렬화/락 적용
핵심팬텀—(Phantom)범위 쿼리 결과 집합이 다른 트랜잭션으로 바뀜Predicate/Range Lock, Gap Lock범위 락/인덱스 설계, 트랜잭션 검증
핵심스냅샷 격리—(Snapshot Isolation, SI)시작 시점 스냅샷 읽기, WW 만 충돌 검사MVCC, Write Skew 허용 가능읽기 중심 워크로드 성능 최적화
구현명시적 잠금—(Explicit Lock / SELECT FOR UPDATE)쿼리 수준의 선점 락 제어Lock granularity, Deadlock민감 판단구간 락 적용
구현2 단계 잠금—(Two-Phase Locking, 2PL)락 확장/축소로 직렬성 보장Predicate Lock, Phantom 방지강한 일관성 트랜잭션에 적용
구현갭/넥스트키 락—(Gap / Next-Key Lock)인덱스 gap 잠금으로 범위 삽입 차단Phantom 방지, 인덱스 의존인덱스 기반 범위 보호 (InnoDB)
고급SSI—(Serializable Snapshot Isolation, SSI)SI 에 직렬성 위반 탐지 추가Serializable, abort/retry고성능과 정확성 균형 적용
운영멱등성—(Idempotency)동일 요청 반복시 결과 불변성 보장재시도 정책, 외부 사이드이펙트재시도 안전화, API 설계
운영직렬성 격리—(Serializable Isolation)모든 트랜잭션이 직렬 실행 결과와 동일2PL, MVCC+SSI금융·원장 등 최고 수준 보장

참고 및 출처