Server

[비관적인락/PESSIMISTIC]_쓰기락과 읽기락

Raconer 2024. 2. 6. 00:33
728x90

동시성 제어를 위한 가장 보편적인 방법

락(Lock)을 통한 순차 실행 제어는 동시성 이슈를 해결하는 가장 기본적이고 보편적인 방식입니다.


중요 ✅ 1: 락의 범위는 최소화해야 한다

  • 락이 걸린 동안 다른 트랜잭션은 대기 상태가 되므로, 락 범위가 넓으면 시스템 전체 성능이 저하됩니다.
  • 심한 경우 단일 스레드처럼 직렬 처리되는 상황이 발생할 수 있습니다.
  • 특히 Connection Pool을 사용하는 경우 락이 길어지면 풀 고갈로 인해 새로운 요청 자체가 블로킹됩니다.

MySQL에서 락의 범위를 줄이는 방법

MySQL은 트랜잭션의 종료 시점(커밋/롤백)에 락이 해제됩니다.
따라서 트랜잭션의 길이 = 락의 유지 시간 입니다.

  • 트랜잭션 범위를 최소화하면 락 범위도 자연스럽게 줄어듭니다.

  • 예시: S3 업로드 같은 외부 작업은 트랜잭션 밖에서 실행하는 것이 좋습니다.

    // Bad: 트랜잭션 안에서 S3 업로드
    @Transactional
    fun upload() {
        saveToDatabase()
        uploadToS3() // 외부 API → 락이 길어짐
    }
    
    // Good: 트랜잭션 안에는 DB 처리만
    fun upload() {
        saveToDatabase()
        uploadToS3() // 트랜잭션 바깥에서 실행
    }

MySQL의 락 종류: 읽기락 vs 쓰기락

읽기락 (Shared Lock) 쓰기락 (Exclusive Lock)
읽기 요청 가능 (공유 가능) 대기
쓰기 요청 대기 대기

1. 읽기락 (Shared Lock)

  • 여러 트랜잭션이 동시에 읽기만 수행할 수 있음
  • 명령어:
    SELECT * FROM your_table WHERE condition FOR SHARE;

2. 쓰기락 (Exclusive Lock)

  • 쓰기 작업은 단독으로만 수행 가능
  • 읽기/쓰기 모두 대기시킴
  • 명령어:
    SELECT * FROM your_table WHERE condition FOR UPDATE;
    UPDATE your_table SET col = val WHERE condition;
    DELETE FROM your_table WHERE condition;

일반 SELECT락이 없는 Consistent Read로 처리되며, 성능에 영향을 주지 않습니다.
참고: MySQL Consistent Nonlocking Reads


중요 ✅ 2: 락의 범위 종류

MySQL에서는 락이 걸리는 범위에 따라 다양한 락 종류가 존재합니다.

  • 테이블 락: 테이블 전체에 락을 겁니다 (MyISAM, 명시적 테이블 락 등)
  • 레코드 락(Row Lock): 특정 ROW에 락을 거는 방식 (일반적으로 가장 중요)
    • MySQL InnoDB는 실제로 레코드가 아니라 인덱스에 락을 겁니다
    • WHERE 절에 인덱스가 없으면, 불필요한 범위까지 락이 걸릴 수 있습니다
  • 갭 락(Gap Lock): 두 ROW 사이의 공간(갭)에 락을 거는 방식
    • 팬텀 리드 방지용으로 사용됨 (Repeatable Read 격리 수준 이상에서 발생)

요약

  • 락은 데이터 정합성을 보장하는 핵심 수단이지만, 성능 저하의 원인이 될 수 있음
  • MySQL에서 트랜잭션 길이 = 락 유지 시간이므로, 외부 API 호출 등은 트랜잭션 밖으로 분리
  • WHERE 조건에 인덱스가 없으면 예상보다 더 넓은 범위에 락이 걸릴 수 있음
  • 갭락 등은 격리 수준과 관련이 있으며, 고급 트랜잭션 제어에 유의해야 함
728x90