WIL| 트랜잭션 & 동시성 문제

Tasha Han·2023년 9월 19일
0

WHAT IS 동시성?!


동시성 문제란 여러 트랜젝션이 동시에 데이터 베이스에 접근할 때 생기는 문제.
ACID(Atomicity, Consistency, Isolation, Durabilty) 원칙을 지키기 위해 동시성을 관리해줘야 한다.

=>같은 파일을 접근하면서 문제가 생길 수 있기 때문에 신경써야 한다.

동시성 관련 현상들


  1. Dirty Read

    • 한 트랜젝션이 데이터를 변경했으나 그 변경값을 확정하지 않은 상태에서 다른 트랜잭션이 그 값을 읽는 경우.

    • 예를들어 A가 500만원을 출금함. 그 값을 update하고 select하는 와중에 오류가 나서 롤백이 되었음. 근데 은행원 B가 A의 은행 계좌를 보는데 update만 된 상태에서 다시 select해서 읽으면 잘못된 결과=더티한 결과를 읽은게 됨

  2. Non-Repeatable Read

    • 한 트랜잭션 내에서 동일한 데이터를 2번 이상 읽을 때, 그 사이에 다른 트랜잭션에 의해 데이터가 변경되어 두번째 읽은 값이 다른게 되는 현상
    • 은행원 B는 전체 은행내 현금을 확정하기 위해 SELECT 2번을 하는 트랜잭션을 진행. 근데 그 사이에 A가 500만원을 출금함. 은행원 B는 전체 은행현금을 제대로 확인할 수 없음.
  3. Phantom Read: 한 트랜잭션 내에서 두 번 이상 같은 데이터를 읽었을 때, 그 사이에 다른 트랜잭션에 의해 새로운 레코드가 추가되거나 삭제되어서 두 번째로 읽은 값에 새로운 레코드나 삭제된 레코드가 반영된 경우.

동시성 문제 해결 방법들


동시성 문제의 근본적인 해결방법은 가변데이터에 순차적으로 접근할 수 있는 방법을 구상하는 것.

  1. Locking: 데이터를 수정하거나 읽을 때 해당 데이터에 락을 걸어 다른 트랜잭션이 동시에 접근할 수 없게 합니다.
    • 공유 락(Shared Lock): 여러 트랜잭션이 동시에 읽을 수 있으나, 데이터 수정은 불가능.
    • 배타적 락(Exclusive Lock): 락을 건 트랜잭션만 데이터에 접근할 수 있음.
  2. Timestamping: 각 트랜잭션에 타임스탬프를 할당하여 순서를 정하고, 이 순서에 따라 데이터에 접귍하게 합니다.
  3. Optimistic Concurrency Control: 트랜잭션 시작 시에는 락을 사용하지 않지만, 커밋 시에 변경 여부를 확인하여 충돌이 발생하면 롤백합니다.
  4. Multi-Version Concurrency Control (MVCC): 여러 버전의 데이터를 저장하여 동시에 여러 트랜잭션이 데이터에 접근할 수 있게 합니다. PostgreSQL, MySQL의 InnoDB 스토리지 엔진 등이 이 방식을 사용합니다.

동시성으로 인한 속도저하 문제 해결 방안!


UPDATE, INSTERT 작업이 발생할 때 해당 데이터에 대한 락이 걸릴 수 있음.
락은 동시에 수행되는 다른 트랜잭션들이 대기 상태에 놓이게 하며, 이로 인해 성능 저하가 일어날 수 있다.

  1. CQRS: 조회(SELECT) 분리

    • 실질 기능하는 DB와 별도로 조회 전용 DB를 만들수 있음.
    • 조회용 DB는 인덱싱, 캐싱, 데이터 스키마 최적화 등을 사용해서 SELECT 전용으로 만든다.
    • 성능이 향상되고, 나중에 조회가 늘면 조회용 DB만 서버 증설해도 됨ㅇㅇ
    • 그렇다면 조회용 DB는 REDIS를 사용하는게 좋을지도?!
  2. 분산락:
    대충 레디스로 가능

  3. 쿼리가 느리다는건 대부분 대부분 조인 관계 때문!!!! -> 조인을 하지 않는다.

    • Foreign key로 연결된 db가 cascade delete가 일어나면 연결된 db에도 락이 걸린다. 여기서도 엄청 느려짐. ..
    • 그냥 조인이 아니라 interger /long등 일반 숫자를 사용해서 조인관계인 DB를 인지하는 방법도 있다.
    • 어차피 DB 전문가처럼 쿼리문을 잘쓰는게 아니라면 조인문을 안 쓰는게 방법일 수도 있다...ㅎㅎㅎ

격리수준을 통한 동시성 제어


  Read Uncommitted (읽기 미확정)
    가장 낮은 격리 수준.
    트랜잭션에서 변경된 데이터를 다른 트랜잭션이 커밋되지 않은 상태에서도 읽을 수 있습니다.
    Dirty Read가 발생할 수 있습니다.

  Read Committed (읽기 확정)
    트랜잭션에서 변경된 데이터는 해당 트랜잭션이 커밋을 한 후에만 다른 트랜잭션에서 읽을 수 있습니다.
    Dirty Read는 방지되지만, Non-Repeatable Read는 발생할 수 있습니다.

  Repeatable Read (반복 읽기)
    트랜잭션 동안 동일한 데이터를 여러 번 읽을 때 항상 동일한 결과를 보장합니다.
    Dirty Read와 Non-Repeatable Read는 방지되지만, Phantom Read(같은 조건으로 여러 번 조회했을 때 결과 집합이 다르게 나타나는 현상)가 발생할 수 있습니다.

  Serializable (직렬화 가능)
    가장 높은 격리 수준.
    트랜잭션들이 순차적으로 실행되도록 함으로써 동시성 문제를 완전히 방지합니다.
    성능 저하가 발생할 수 있지만, Dirty Read, Non-Repeatable Read, Phantom Read 모두 방지됩니다.
  

WHAT IS 트랜잭션


  • 쪼갤수 없는 업무 처리의 최소 단위
  • 데이터베이스의 상태를 변화시키기 위해 수행하는 하나의 작업 단위를 뜻한다.
  • 한번에 처리되야 하는 일련의 연산
  • 예를들어 새로운 글을 게시판에 입력해서 출력된 결과물을 볼려고 한다면 (INSERT+ SELECT)가 되어야 한다.
    => 롤백할 때도 INSERT+SELECT 단위로 롤백!

트랜잭션 주요 특성


  • AOMICITY(원자성)
    - 트랜젝션 내의 모든 연산은 완전히 수행되거나, 아예 수행되지 않아야 한다. 즉, 중간 단계에서 실패하면 모든 연산이 롤백되어야 한다.
  • Consistency (일관성)
    - 트랜잭션이 성공적으로 완료되면, 데이터베이스는 일관된 상태를 유지해야 한다.
    - ex)
트랜잭션 시작 전: A 계좌에는 1000달러, B 계좌에는 500달러가 있다고 가정합시다.
트랜잭션 동안: A 계좌에서 200달러를 빼서 B 계좌로 이체하려고 합니다.
트랜잭션 후의 예상 상태: A 계좌에는 800달러, B 계좌에는 700달러가 되어야 합니다.
이때 "일관성"이란, 트랜잭션 수행 후에도 모든 계좌의 잔액 합계가 변하지 않는 것 (여기서는 총 1500달러)을 의미합니다. 
만약 트랜잭션 수행 후 A 계좌에는 800달러가 남아있지만, B 계좌의 잔액이 600달러라면, 총합이 1400달러로 일관성이 깨진 것입니다.
  • Isolation (고립성)
    - 동시에 실행되는 여러 트랜잭션들이 서로 영향을 미치지 않아야 한다.
  • Durability (영속성)
    - 트랜잭션이 성공적으로 완료된 후에는, 그 결과는 영구적으로 데이터베이스에 반영되어야 한다.
profile
개발 잘하고 싶다~(고래)

0개의 댓글