우리가 다루는 대부분의 애플리케이션은 여러 사용자가 동시에 데이터를 읽고 쓰는 환경에서 동작합니다. 예를 들어, 온라인 쇼핑몰에서 같은 상품의 재고를 여러 고객이 동시에 구매하거나, 은행 시스템에서 계좌 잔액을 여러 트랜잭션이 동시에 변경하려 할 때 문제가 발생할 수 있죠. 이러한 상황에서 적절한 동시성 제어 메커니즘이 없다면, 데이터가 예상치 못하게 손실되거나 부정확해지는 ‘데이터 무결성’ 문제가 발생할 수 있습니다.
이를 해결하기 위한 여러 전략 중 ‘락(Lock)’은 매우 중요합니다. 대표적으로 ‘비관적 락(Pessimistic Lock)’은 데이터를 수정하기 전에 미리 락을 걸어 다른 트랜잭션의 접근을 막는 방식입니다. 이는 안전하지만, 동시에 많은 트랜잭션이 발생할 경우 성능 저하를 야기할 수 있습니다. 오늘 우리는 이와 대비되는, 조금 더 유연하고 ‘낙관적인’ 접근 방식인 옵티미스틱 락(Optimistic Lock)에 대해 심층적으로 알아보려 합니다.
옵티미스틱 락은 이름처럼 “충돌이 거의 발생하지 않을 것”이라는 낙관적인 가정을 기반으로 합니다. 데이터를 수정하려는 시점까지는 별도의 락을 걸지 않고 자유롭게 접근을 허용합니다. 그리고 실제 데이터를 업데이트할 때, 그 사이에 다른 트랜잭션이 데이터를 변경했는지 여부를 검증합니다. 만약 변경되었다면 현재 트랜잭션은 실패로 처리하고, 사용자에게 재시도를 요청하거나 적절한 방식으로 문제를 해결하도록 유도합니다.
이는 주로 낮은 데이터 충돌 빈도를 가진 환경이나 읽기 작업이 압도적으로 많은 환경에서 비관적 락보다 더 높은 동시성과 처리량을 제공할 수 있습니다.
옵티미스틱 락을 구현하는 가장 일반적인 방법은 데이터에 ‘버전(Version)’ 정보를 추가하는 것입니다. 이 버전 정보는 일반적으로 숫자(정수) 형태의 version 컬럼이나, 타임스탬프(last_updated_at) 컬럼을 사용합니다.
-- 상품 테이블 (products)
-- id: 상품 ID
-- name: 상품명
-- price: 가격
-- stock: 재고
-- version: 동시성 제어를 위한 버전 컬럼
CREATE TABLE products (
id BIGINT PRIMARY KEY,
name VARCHAR(255),
price DECIMAL(10, 2),
stock INT,
version INT DEFAULT 0
);
-- 상품 정보 조회 (트랜잭션 A)
SELECT id, name, price, stock, version
FROM products
WHERE id = 1;
-- 결과 예시: id=1, name='노트북', price=1200.00, stock=100, version=5
-- 상품 재고 업데이트 (트랜잭션 A)
-- id=1번 상품의 재고를 99로 변경하고, version이 5일 경우에만 업데이트
UPDATE products
SET stock = 99, version = version + 1
WHERE id = 1 AND version = 5;
UPDATE 쿼리의 영향을 받은 행(row)의 수가 1이라면, 업데이트가 성공적으로 이루어진 것이며, 트랜잭션 A가 데이터를 수정하는 동안 다른 트랜잭션의 변경이 없었음을 의미합니다. 이제 products 테이블의 id=1번 상품의 version은 6이 됩니다.UPDATE 쿼리의 영향을 받은 행의 수가 0이라면, 트랜잭션 A가 데이터를 읽어온 version (예: 5) 이후에 다른 트랜잭션이 이미 해당 데이터를 수정하여 version이 변경되었음을 의미합니다. 이 경우, 트랜잭션 A는 롤백되거나, 사용자에게 ‘데이터가 이미 변경되었습니다. 다시 시도해주세요.’와 같은 메시지를 보여주고 재시도를 유도해야 합니다.장점 (Pros):
단점 (Cons):
옵티미스틱 락은 다음과 같은 시나리오에서 특히 유용합니다:
옵티미스틱 락은 데이터 동시성 제어에 있어 강력하고 효율적인 도구입니다. 특히 높은 동시성과 확장성이 요구되는 현대적인 웹 서비스나 분산 시스템에서 그 가치를 발휘합니다. “충돌이 드물게 발생할 것”이라는 낙관적인 가설을 바탕으로 불필요한 락 대기를 줄여 전반적인 시스템 처리량을 향상시킬 수 있습니다.
하지만, 이는 만능 해결책이 아닙니다. 비즈니스 로직의 특성과 예상되는 데이터 충돌 빈도를 면밀히 분석하여 옵티미스틱 락이 최적의 선택인지, 아니면 비관적 락이나 다른 동시성 제어 전략이 더 적합한지 판단해야 합니다. 중요한 것은 각 메커니즘의 장단점을 정확히 이해하고, 우리 시스템의 요구사항에 가장 잘 맞는 균형점을 찾아 적용하는 것입니다. 데이터 무결성을 지키면서도 사용자에게 빠르고 안정적인 서비스를 제공하기 위한 여정에서 옵티미스틱 락은 분명 중요한 무기가 될 것입니다.
Text by Chaelin & Gemini. Photographs by Chaelin, Unsplash.