Write Skew란? 트랜잭션에서 발생하는 숨은 함정

Write Skew란 무엇인가

Write Skew는 두 개 이상의 트랜잭션이 서로 다른 데이터를 각각 읽고 수정하지만, 그 데이터들이 논리적으로 연결되어 있어서 결과적으로 비즈니스 규칙이 깨지는 동시성 이상 현상입니다. 각 트랜잭션이 자신이 쓴 로우만 보면 문제가 없어 보이지만, 두 트랜잭션의 결과를 합치면 애초에 허용되지 않아야 할 상태가 되어버립니다. 이는 Dirty Read나 Lost Update처럼 같은 로우를 두 트랜잭션이 동시에 건드리는 경우가 아니기 때문에, 일반적인 락(Lock) 기반 보호로는 잘 잡히지 않는 특징이 있습니다.

동작 원리와 예시

대표적인 예시는 병원의 당직 의사 스케줄입니다. 규칙상 ‘최소 1명의 의사는 당직을 유지해야 한다’고 가정해봅시다. 현재 의사 A와 B가 당직 중입니다.

  • 트랜잭션 1: A가 당직 인원을 조회 -> 2명 확인 -> 본인(A) 당직 해제 요청
  • 트랜잭션 2: B가 당직 인원을 조회 -> 2명 확인 -> 본인(B) 당직 해제 요청

두 트랜잭션은 서로 다른 로우(A의 레코드, B의 레코드)를 수정하기 때문에 충돌이 감지되지 않고 둘 다 커밋됩니다. 하지만 결과적으로 당직 의사는 0명이 되어 규칙이 깨집니다. 이것이 바로 Write Skew입니다. 격리 수준을 Snapshot Isolation으로 설정해도 이 문제는 방지되지 않는데, 각 트랜잭션이 조회한 시점의 데이터는 여전히 ‘2명’으로 유효했기 때문입니다.

실무에서 왜 알아야 하는가

Write Skew는 재고 관리, 예약 시스템, 권한 관리처럼 ‘조건을 만족하는 최소/최대 인원 유지’가 필요한 도메인에서 자주 발생합니다. 예를 들어 좌석 예약 시스템에서 ‘동시간대 최대 1건만 예약 가능’ 같은 제약을 로직으로만 처리하면 두 사용자가 동시에 서로 다른 좌석을 예약하려다 규칙이 깨질 수 있습니다.

이를 방지하려면 SELECT ... FOR UPDATE 같은 명시적 락으로 관련 로우를 잠그거나, 데이터베이스의 Serializable 격리 수준을 사용해 실행 순서를 강제해야 합니다. 또는 애플리케이션 레벨에서 유니크 제약이나 체크 제약을 걸어 DB가 직접 규칙 위반을 막도록 설계하는 것도 좋은 방법입니다. 결국 Write Skew를 이해하면 ‘락을 걸었는데도 왜 데이터가 깨지지?’라는 질문에 답할 수 있고, 트랜잭션 격리 수준을 선택할 때 훨씬 근거 있는 결정을 내릴 수 있습니다.

댓글 남기기