728x90
반응형
- DBMS나 트랜잭션 시스템이 아닌 동시성 제어의 개념적인 패러다임에서 출발한 이론
- 다중 사용자/프로세스가 동일자원(DB row 등)을 동시에 읽고 쓰는 상황에서의 충돌을 방지하기 위해 등장
- 해당 문제는 1970 ~ 1980년대 DBMS/OS 이론에서 활발히 논의됨
비관적 락
고전적인 RDBMS의 트랜잭션 동시성 제어 이론에서 등장했고 대표 기술로 2-Phase Locking(2PL)으로 트랜잭션이 자원을 모두 락으로 확보한 후 커밋합니다. 이 방식은 직렬화를 보장합니다.
기본 아이디어는 “다른 놈이 반드시 충돌할 거야” → 그래서 미리 락을 걸고 진입을 통제합니다.
적용방식으로 공유 자원(예: DB row)에 접근 전에 락을 선점합니다. 다른 트랜잭션은 대기하거나 실패합니다.
주의 사항 & 병목 및 데드락 유발
- 개발자의 손을 타기 때문에 락 범위가 의외로 넓어 질 수 있다.(의도치 않은 락 확산)
- WHERE 절이 인덱스를 제대로 타지 않거나, 조건이 모호할 경우
- 의도한 row 보다 더 많은 row가 락에 걸림
- 특히 JOIN, LIKE, IN 조건 주의 필요
- 커넥션/세션을 장시간 점유 → 커넥션 풀 고갈 가능성
- 락은 트랜잭션 종료 시까지 유지되므로 긴로직이 있으면 락 + 커넥션 둘다 점유
- 특히 커넥션 풀이 작거나 TPS가 일정 수준 이상이면 DB가 hang 상태로 진입
- 데드락 위험
- 두 개 이상의 트랜잭션이 서로가 가진 row를 요구하면 교착상태 발생
- 예
- T1: SELECT … FOR UPDATE WHERE id = 1
- T2: SELECT … FOR UPDATE WHERE id = 2
- → 이후 서러 반대 row를 요청하면 데드락 발생
- DBMS는 보통 내부적으로 데드락 감지 후 한 쪽을 롤백 처리하지만, 이로 인해 업무 실패 발생
- 성능 저하 및 확장성 한계
- 락을 거는 순간 → 해당 row는 병렬 처리 불가
- 멀티노드, 다중DB세션, 분산 환경에서는 사용 불가
- 읽기 전용 replica 환경에서 사용 불가
- 락 해제가 명확하지 않으면 논리 오류
- 트랜잭션이 명확히 커밋/록백되지 않으면 락이 계속 유지됨
- 비정상 종료 시 해당 세션의 락은 복구까지 시간이 걸림
SLECT … FOR UPDATE 적용 체크리스트
- 락 범위와 조건 최소화
- WHERE 적이 명확한 인덱스를 타는지?
- JOIN, IN, LIKE 등의 조건으로 확대되지 않는가?
- 필요한 row만 select 하도록 쿼리를 조정했는가?
- 트랜잭션 시간 최소화
- 빨리 끝나야함
- 락 보유 시간 동안 외부 로직이 포함되어 있지 않은가?
- 락 이후의 로직에서 예외가 발생할 경우 즉시 롤백 처리가 이루어 지는가?
- 데드락 방시 설계
- 항상 동일한 순서로 접근하도록 설계했는가?
- 병렬 트랜잭션 간에 락 충돌 가능성이 있는 경우 순서를 명확히 했는가?
- 비즈니스 로직상 두 트랜잭션이 동일한 대상에 동시에 접근할 수 있는지 시뮬레이션 했는가?
- 타임아웃 및 예외 처리
- 락 획득 시간 설정이 되어있는가?
- 락 획득 실패(데드락, 타임아웃 등)에 대해 재시도 또는 사용자 안내 처리가 되어있는가?
- 락 예외 바생 시 정합성에 영향을 주지 않도록 상태 복원 로직이 있는가?
- 환경 별 적용 가능성 확인
- 읽기 전용 replica에서 사용하지 않도록 구성되었는가?
- 멀티 인스턴스, 분산 환경에서는 다른 동시성 제어 방식(Redis 락 등)이 고려되었는가?
- 모니터링 및 운영 점검 항목
- 락 대기 시간, 데드락 발생 횟수, 트랜잭션 평균 수행 시간을 모니터링 하고 있는가?
- 시스템에 타임아웃, 데드락 알림 체계가 존재하는가?
- 락 병목이나 커넥션 점유율이 급증했을 때 대응 프로세스가 마련되어 있는가?
실무 코멘트
지금 확실하게 락을 걸어야 할 때에만 사용해야만 한다. 그냥 사용해보는 식은 운영 리스크가 매우 큽니다.
정말 필요한 곳에만 짧고, 명확하게 사용하고, 확장 가능성과 운영 대응책까지 갖춘다면 강력한 도구로 활용할 수 있습니다.
낙관적 락
- Optimistic Concurrency Control(OCC) 이론으로 1979년 Kung & Robinson 논문에 기재되어있습니다. 비정형 시스템이나 대규모 분산 환경, API 서버 등에서 많이 활용됩니다.
- 기본 아이디어는 “충돌은 드물어. 일단 자유롭게 작업하고, 마지막에 확인하자” → 검증단계에서만 충돌 여부 확인 합니다.
- 읽을 때 락을 안 걸고 자유롭게 처리합니다. 커밋 직전에 버전 비교나 타임스탬프 등으로 변경 여부를 검증합니다. 충동 시 록백 or 재시도를 합니다.
주의 사항
- 충돌 시 반드시 재시도 로직 필요
- 버전이 다르면 OptimisticLockingFailureException 예외 발생
- 예외 발생 시 자동 재처리 없이 종료되면 사용자 데이터 손실 또는 로직 누락 위헙이 있습니다.
- 트랜잭션이 길어질수록 충돌 확률 증가
- 중간에 다른 트랜잭션이 같은 데이터를 수정할 가능성 증가
- 복잡한 로직, 외부 API 호출, 사용자 대기 등과 함께 쓰지 말 것(단일 기능으로 만 적용하자)
- 작은 충돌 시 성능 저하
- 충돌이 자주 발생하면 매번 rollback → retry로 인해 낙관적이 아니게 됩니다.
- 경쟁이 많은 상호아(주문 처리, 실시간 재고 등)에서는 비관적 락이 더 적합
- 병합 불가: 필드 단위 충돌 감지 없음
- @Version은 단일 엔티티 기준
- 동일 엔티티를 두 사용자가 다른 필드만 수정해도 충돌로 간주되어 무조건 롤백합니다.
- 분산 환경에서만 쓸 수 있는 건 아님
실무 적용 시 체크 포인트
- @Version 필드가 엔티티에 정확히 명시되어 있는가?
- OptimisticLockingFailureException 발생 시 재시도/로그 처리 설계가 되어있는가?
- 동시 수정 가능성이 높은 업무에는 적용을 피하고 있는가?
- 충돌 로그를 수집하여 실제 빈도를 모니터링하고 있는가?
비교 요약
단순 비교
구분 | 비관적 락 (Pessimistic) | 낙관적 락 (Optimistic) |
---|---|---|
충돌 예상 | 항상 예상 (보수적) | 드물게 발생 (낙관적) |
락 시점 | 초기 선점 | 커밋 시점 검증 |
성능 | 저TPS에서 안전 | 고TPS/분산 환경에서 유리 |
구현 방식 | SELECT FOR UPDATE, LOCK TABLE | @Version, Timestamp 비교 등 |
충돌 시 처리 | 대기 or 데드락 발생 | 롤백 후 재시도 |
후처리 필요성 요약
항목 | 비관적 락 (SELECT FOR UPDATE) | 낙관적 락 (@Version) |
---|---|---|
락 실패 시 처리 | 데드락, 타임아웃 발생 시 → 예외 발생 | 버전 충돌 시 → 예외 발생 |
후처리 필요성 | 예외 로그, 사용자 안내, 롤백, 재시도 전략 | 예외 감지, 재시도 or 충돌 안내 |
후속 트랜잭션 처리 | 커밋 전까지 락 유지됨 → 락 범위 줄이기 필요 | 커밋 직전 충돌 확인 → 재시도 보장 필요 |
운영 안정성 확보 | 트랜잭션 중단 시 락 해제 감지 | 충돌률 모니터링 필요 |
사용자 경험 보완 | “처리 중” 안내 → 응답 지연 | “다른 사용자가 먼저 수정했습니다” 안내 필요 |
현실 적용 예시
환경 | 방식 |
---|---|
RDBMS (MySQL, Oracle 등) | 기본적으로 비관적 락 구조 |
Spring + JPA | 낙관적 락: @Version / 비관적 락: @Lock(PESSIMISTIC_*) |
대규모 API 서버 | Optimistic Lock (충돌 적고 성능 중시) |
실시간 재고/거래 처리 | Pessimistic Lock (정합성 최우선) |
결론
비관적 락과 낙관적 락은 데이터베이스의 트랜잭션 충돌 회피를 위한 동시성 제어 전략으로 탄생한 이론적 개념입니다.
DMBS, ORM(Spring JPA 등), 분산 시스템에서 상황에 맞는 전략을 선택해 구현하는 것이 실무 적용 포인트입니다.
728x90
반응형
'CS > 데이터베이스' 카테고리의 다른 글
2.3 뷰(VIEW) (0) | 2019.09.26 |
---|---|
2.2 테이블(TABLE) 생성, 삭제, 변경, 복사 (2) | 2019.09.25 |
1. SQL이란? (0) | 2019.09.25 |
2.1 데이터베이스 객체 (0) | 2019.09.25 |