책너두 (데이터 중심 애플리케이션 설계) 21일차 (~245p)

요약

  • 완화된 격리 수준 중 하나인 갱신 손실 방지에 대해 이해함.
    • 원자적 쓰기 연산
    • 명시적인 잠금
    • 갱신 손실 자동 감지
    • compare-and-set
    • 충돌 해소와 복제

메모

갱신 손실 방지

  • 동시에 실행되는 쓰기 트랜잭션 사이에 발생할 수 있는 충돌로 갱신 손실(lost update)이 있음.
    • 데이터베이스에서 값을 읽고 변경한 후에 변경된 값을 다시 쓸때 발생함. (read-modify-write 주기)
    • 만약 두 트랜잭션이 작업을 동시에 하면, 두 번째 쓰기 작업이 첫 번째 변경을 포함하지 않으므로 변경 중 하나는 손실될 수 있음.

원자적 쓰기 연산

  • 갱신 손실 방지를 위해 여러 데이터베이스에서 원자적 갱신 연산을 제공함.
    • 이 연산은 애플리케이션 코드에서 read-modify-write 주기를 구현할 필요를 없애줌.
      • 이 연산을 써서 코드를 표현할 수 있다면 가장 좋은 해결책임.
  • 원자적 연산은 객체를 읽을 때 그 객체에 독점적인(exclusive) 잠금을 획득해서 구현한다.
    • 이 기법을 커서 안전성(cursor stability) 라고 부름.
  • 객체 관계형 매핑 프레임워크를 사용하면 뜻하지 않게 데이터베이스가 제공하는 원자적 연산을 사용하는 대신 불안전한 read-modify-write 주기를 실행하는 코드를 작성하기 쉬움.
    • 테스트로 발견하기 어려운 미묘한 버그의 원인이 될 수 있음.

명시적인 잠금

  • 갱신 손실 방지의 또다른 방법으로, 애플리케이션에서 갱신할 객체를 명시적으로 잠그는 것임.
    • 애플리케이션이 read-modify-write 주기를 수행하고 있으면, 이 주기가 완료될 때까지 다른 트랜잭션은 해당 객체를 기다리도록 강제됨.
  • 특정 상황에서 원자적 연산으로는 구현을 충분히 할 수 없음.
    • ex) 여러 플레이어가 동시에 같은 물체를 옮길 수 있는 다중 플레이어 게임
      • 애플리케이션은 플레이어의 움직임이 게임 규칙을 준수하는지도 보장해야 하는데, 데이터베이스 질의만으로는 합리적으로 구현할 수 없는 로직이 포함될 수 있기 때문임.
  • 명시적 잠금이 올바르게 동작하려면 애플리케이션 로직에 대해 신중하게 생각해야 함.
    • 코드 어딘가에 필요한 잠금을 추가하는 것을 잊어버리면 경쟁 조건을 유발하게 된다.

갱신 손실 자동 감지

  • 트랜잭션 관리자가 갱신 손실을 발견하면 트랜잭션을 어보트시키고 read-modify-write 주기를 재시도하도록 강제한다.
  • 갱신 손실 감지는 애플리케이션 코드에서 어떤 특별한 데이터베이스 기능도 쓸 필요 없게 도와주는 매우 좋은 기능임.
    • 잠금, 원자적 연산 쓰는 것을 잊어버려서 생기는 버그 대신, 자동으로 갱신 손실이 감지되기 때문

Compare-and-set

  • 값을 마지막으로 읽은 후로 변경되지 않았을 때만 갱신을 허용함으로써 갱신 손실을 회피한다.
    • 현재 값이, 이전에 읽은 값과 일치하지 않으면(compare) 갱신(set)은 반영되지 않고, read-modify-write 주기를 재시도해야 함.
  • ex) UPDATE wiki_pages SET content = ‘new content’ WHERE id = 1234 AND content = ‘old content’;
    • old content 와 일치하지 않으면 갱신은 적용되지 않음.
    • 그러나 만약, 데이터베이스가 WHERE 절이 오래된 스냅숏을 읽는 걸 허용한다면 이 구문은 갱신 손실을 막지 못할 수 있음.
    • 따라서, compare-and-set 연산에 의존하기 전에 안전한지 먼저 확인해야 함.

충돌 해소와 복제

  • 복제된 데이터의 경우, 여러 노드에 데이터 복사본이 있고, 데이터가 다른 노드들에서 동시에 변경될 수 있으므로, 갱신 손실을 방지하려면 추가 단계가 필요함.
  • compare-and-set 연산은 데이터의 최신 복사본이 하나만 있다고 가정함.
    • 복제된 데이터가 있다면 최신 복사본이 하나만 있으리라 보장할 수 없으므로 compare-and-set 기반으로는 복제 상황에서 생기는 충돌을 해결할 수 없음.
  • 복제가 적용된 데이터베이스에서 흔히 쓰기 방법은 아래와 같다.
    • 한 값에 대해 여러 개의 충돌된 버전을 생성하는 걸 허용하고, 사후에 애플리케이션 코드나 특별한 데이터 구조를 사용해서 충돌을 해소하고 이 버전들을 병합한다
  • 원자적 연산은 복제 상황에서도 잘 동작함.
    • p246 참고
  • 반면 최종적 쓰기 승리(last write wins, LWW) 충돌 해소 방법은 갱신 손실이 발생하기 쉬움.

댓글

Designed by JB FACTORY