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

요약

  • 트랜잭션의 완화된 격리 수준에 대해 이해함
    • 트랜잭션 격리를 통해 동시성 문제를 감출 수 있음.
    • 직렬성 격리로 동일한 결과가 나오도록 보장할 수 있음.
      • 하지만 그만큼 비용이 많이 듦.
      • 완화된 트랜잭션 격리를 통해, 동시성 이슈를 어느정도 해결할 수 있음.
        • 하지만, 그만큼 버그가 있고, 금전적 손실을 발생시킬 수 있다.
  • 완화된 격리 수준 중 하나인 커밋 후 읽기에 대한 내용을 이해함.
    • 더티 읽기 방지
      • 커밋 후 트랜잭션이 보게 함.
    • 더티 쓰기 방지
      • 먼저 쓴 트랜잭션의 커밋 or 어보트 될 때 까지 다른 쓰기를 지연 시킨다.
    • 로우 수준 잠금을 이용하여 구현한다.
  • 완화된 격리 수준 중 하나인 스냅숏 격리와 반복 읽기에 대한 내용을 이해함.
    • 스냅숏 격리는 커밋 후 읽기의 문제인 일시적 문제를 허용하지 않음.
    • 트랜잭션은 시작할 때 데이터베이스의 커밋된 상태였던 모든 데이터를 보게 한다.
    • 구현 방법으로 다중 버전 동시성 제어(multi-version concurrency control, MVCC)을 사용한다.
      • 트랜잭션 ID 를 이용하여 일관된 스냅숏을 보는 가시성 규칙을 적용할 수 있음.
    • 색인이 포함된 경우, 여러 구현 세부사항에 따라 다중 버전 동시성 제어의 성능이 결정됨.

메모

완화된 격리 수준

  • 데이터베이스는 오랫동안 트랜잭션 격리를 제공함으로써 애플리케이션 개발자들에게 동시성 문제를 감추려고 함.
  • 직렬성 격리는 데이터베이스가 여러 트랜잭션들이 직렬적으로 실행되는 것과 동일한 결과가 나오도록 보장함.
    • 하지만, 직렬성 격리는 성능 비용이 있고 많은 데이터베이스들은 그 비용을 지불하려고 하지 않음.
    • 어떠한 동시성 이슈로부터는 보호해주지만, 사실, 흔히 시스템들은 모든 이슈로부터 보호해주지 않는 완화된 격리 수준을 사용한다.
  • 완화된 트랜잭션 격리가 유발하는 동시성 버그는 이론적인 문제만 있는게 아니라, 금전적 손실을 일으키고, 고객의 데이터베이스를 오염시킴.
    • 인기있는 관계형 데이터베이스 시스템조차 완화된 격리성을 사용하는 경우가 많고, 이런 버그가 발생하는 것을 반드시 막아주지 못함.

커밋 후 읽기

  • 가장 기본적인 수준의 트랜잭션 격리 → 커밋 후 읽기(read committed)
    • 더티 읽기가 없음. (커밋된 데이터만 본다.)
    • 더티 쓰기가 없음. (커밋된 데이터만 덮어쓴다.)

더티 읽기 방지

  • 트랜잭션이 커밋되지 않은 데이터를 본다면, 이를 더티 읽기라고 함.
  • 더티 읽기를 막기 위해서, 트랜잭션이 쓴 내용을 커밋된 후에야 트랜잭션이 보게 해야 함.

더티 쓰기 방지

  • 아직 커밋되지 않은 트랜잭션이 쓴 것을, 다른 쓰기작업이 덮어쓰면 이를 더티쓰기(dirty write) 라고 함.
  • 더티 쓰기를 막기 위해서, 먼저 쓴 트랜잭션이 커밋 or 어보트될 때까지 두번째 쓰기를 지연시키는 방법을 사용해야 함.

커밋 후 읽기 구현

  • 데이터베이스는 로우 수준 잠금을 사용해서 더티 쓰기를 방지한다.
    • 트랜잭션에서 특정 객체를 변경하고 싶다면 먼저 해당 객체에 대한 잠금을 획득해야 함.
  • 더티 읽기를 방지하는 방법은?
    • 동일한 잠금을 써서 객체를 읽기 원하는 트랜잭션이 잠금을 획득해야 함.
      • 하지만, 읽기 잠금은 트랜잭션의 응답 시간에 해를 끼치며, 운용성이 나쁨.
      • 데이터베이스는 과거에 커밋된 값과 현재 쓰기 잠금을 갖고 있는 트랜잭션에서 쓴 새로운 값을 모두 기억하고, 해당 트랜잭션의 커밋여부에 따라 이전 값 혹은 새로운 값을 보게한다.

스냅숏 격리와 반복 읽기

  • 커밋 후 읽기 격리 수준을 사용하더라도 동시성 버그가 생길 수 있는 경우가 많음.
    • ex) p237 참고
  • 트랜잭션 커밋 시점 전 후로 읽기를 하면 다른 값을 읽을 수 있음.
    • 비반복 읽기(nonrepeatable read) 혹은 읽기 스큐(read skew) 라고 함.
      • 스큐는 불균형적 작업부하 라는 뜻임. (여기서는 시간적인 이상 현상을 뜻함.)
    • 이는 일시적인 문제임.
      • 일시적인 문제조차 허용하지 못하는 경우가 있음.
        • 백업
          • 일시적으로 데이터 과거, 현재 버전을 백업하게 되면 비일관성이 영속적이게 됨.
        • 분석 질의와 무결성 확인
          • 데이터베이스의 큰 부분을 질의 할 때, 데이터 불균형이 있으면 불합리한 결과를 반환함.
  • 스냅숏 격리는, 백업이나 분석 질의를 통한 무결성 확인을 수행할 때, 해결할 수 있는 방법임.
    • 일관된 스냅숏으로 부터 읽기 때문임.
    • 즉, 트랜잭션은 시작할 때 데이터베이스의 커밋된 상태였던 모든 데이터를 본다.

스냅숏 격리 구현

  • 스냅숏 격리 구현을 위해, 더티 쓰기 방지를 해야하고, 쓰기 잠금을 사용한다.
    • 읽을 때 잠금은 필요없음.
  • 스냅숏 격리를 구현하려면 데이터베이스는 객체마다 커밋된 버전 여러 개를 유지할 수 있어야 함.
    • 진행 중인 여러 트랜잭션에서 서로 다른 시점의 데이터베이스 상태를 봐야할 수 있기 때문임.
      • 이를 다중 버전 동시성 제어(multi-version concurrency control, MVCC) 라고 함.
    • 스냅숏 격리가 아니라 커밋 후 읽기 격리만 제공한다면, 객체마다 버전 두개씩만 유지하면 됨.
      • 커밋된 버전
      • 아직 커밋되지 않은 버전
        • p239에 트랜잭션 ID와 버전에 대한 구현 예시 설명되어 있음.

일관된 스냅숏을 보는 가시성 규칙

  • 트랜잭션은 데이터베이스에서 객체를 읽을 때, 트랜잭션 ID 를 사용해서 어떤 것을 볼 수 있고, 어떤 것을 볼 수 없는지 결정한다.
    • 즉, 면밀히 가시성 규칙을 정의해서 데이터베이스의 일관된 스냅숏을 애플리케이션에 제공할 수 있음.
      • p240 참고
    • 이 규칙은 객체 생성 & 삭제에도 모두 적용됨.

색인과 스냅숏 격리

  • 다중 버전 데이터베이스에서 색인은 객체의 모든 버전을 가리키게 하고, 색인 질의가 현재 트랜잭션에서 볼 수 없는 버전을 걸러내야 함.
    • 가비지 컬렉션이 어떤 트랜잭션에게도 더이상 보이지 않는 오래된 객체 버전을 삭제할 때, 대응되는 색인 항복도 삭제된다.
  • 실제로, 여러 구현 세부사항에 따라 다중 버전 동시성 제어의 성능이 결정됨.
    • ex) 포스트그레스큐엘 → 동일한 객체의 다른 버전들이 같은 페이지에 저장될 수 있다면, 색인 갱신을 회피하는 최적화를 함.
    • ex) B 트리를 사용하지만, 추가 전용이며 쓸 때 복사되는 변종(= append-only / copy-on-write)을 사용한다.
      • 즉, 페이지 갱신 시, 덮어 쓰는 대신에 변경된 각 페이지의 새로운 복사본을 생성함.
      • 트리 페이지가 갱신될 때까지 부모 페이지들이 복사되고 그걸 자식 페이지들이 새 버전을 가리키도록 갱신된다.
      • 이를 사용하면 쓰기를 실행하는 모든 트랜잭션은 새로운 B 트리 루트를 생성하며, 특정 루트는 그것이 생성된 시점에 해당하는 데이터베이스의 일관된 스냅숏이 됨.
      • 나중에 실행되는 쓰기는 새로운 트리 루트만 생성할 수 있음 → B 트리 변경할 수 없으므로 트랜잭션 ID 기반 객체를 거를 필요가 없음.
        • 하지만 이 방법은 컴팩션과 가비지 컬렉션을 실행하는 백그라운드 프로세스가 필요함.

댓글

Designed by JB FACTORY