동시성 문제 해결을 위한 PostgreSQL 행 레벨 락 사용
카테고리
프로그래밍/소프트웨어 개발
서브카테고리
데이터 분석
대상자
- 데이터베이스 개발자 및 시스템 아키텍트: 동시성 문제를 해결하고 데이터 일관성을 유지하는 방법을 학습하고자 하는 분
- 중급~고급 수준: 트랜잭션, 고립 수준, 락 메커니즘에 대한 기초 지식이 있는 개발자
핵심 요약
SELECT ... FOR UPDATE
사용: 동시성 문제를 해결하기 위해 행 레벨 락을 통해 데이터를 잠금 상태로 유지- 예:
SELECT balance FROM accounts WHERE id = '1' FOR UPDATE;
- 성능과 일관성의 균형: 락 사용은 데이터 정확성을 보장하지만, 요청 지연(latency) 증가 가능성 있음
- 적용 시기: 금융 계좌, 티켓 판매, 재고 관리 등 정확성이 필수적인 시스템에서 유용
섹션별 세부 요약
1. 동시성 문제의 기본 이해
- 트랜잭션의 내부 동작:
UPDATE
명령어는 데이터를 찾고 잠금을 걸어 수정 - 예:
UPDATE users SET name = 'Nick' WHERE id = 1;
- 고립 수준(isolation level): PostgreSQL 기본값은
READ COMMITTED
로, 미커밋 데이터는 읽지 않음
2. 동시성 문제 사례: 계좌 인출 예제
- 경쟁 조건(race condition): 두 트랜잭션이 동시에 계좌 잔액을 읽고 수정 시 오류 발생
- 예: 초기 잔액 1000 → 300, 500 인출 → 최종 잔액 500, 총 인출 800
- 락을 통한 해결:
SELECT ... FOR UPDATE
로 행 잠금 적용 - 수정된 명령어:
SELECT balance FROM accounts WHERE id = '1' FOR UPDATE;
3. 성능과 트레이드오프
- 락의 부작용: 동일한 행에 대한 요청이 대기열에 추가되어 지연 증가
- 대안 고려: 저지연이 필수적인 경우 비동기, 이벤트 기반 아키텍처 활용
4. 데드락(deadlock) 방지
- 데드락 발생 조건: 두 트랜잭션이 서로의 락을 기다리는 순환 구조
- 예: 트랜잭션1 → id=1 잠금 → 트랜잭션2 → id=2 잠금 → 트랜잭션1 → id=2 잠금
- 해결 방법: 락 획득 순서를 일관성 있게 유지
5. 사용 시기 판단
- 필수 사례: 금융, 재고, 티켓 판매 등 정확성이 필수적인 시스템
- 비추천 사례: 뷰 카운트, 좋아요 수 등 조금의 오차가 허용되는 시스템
결론
- 핵심 팁:
SELECT ... FOR UPDATE
를 사용해 동시성 문제를 해결하되, 성능 영향을 고려한 설계가 중요 - 예:
SELECT balance FROM accounts WHERE id = '1' FOR UPDATE;
- 시스템 요구사항에 맞는 선택: 정확성이 필수적인 시스템에서는 락 사용, 반면 오차가 허용 가능한 시스템에서는 이벤트 기반 아키텍처 활용
- 데드락 방지: 락 획득 순서를 일관성 있게 유지해 순환 기다림 방지