동시성 제어 정리

Martin the dog·2024년 12월 1일

프로젝트

목록 보기
3/3

1. 비관적 락 (Pessimistic Lock)

  • 설명: 데이터를 읽거나 쓰기 전에 락을 걸어 다른 쓰레드나 트랜잭션의 접근을 차단합니다.
  • 사용 예: 은행 계좌 이체와 같은 중요한 트랜잭션에서 데이터를 신뢰할 수 있어야 할 때.
  • 구현:
    SELECT * FROM account WHERE id = 1 FOR UPDATE;
    위 쿼리는 id = 1 레코드에 락을 걸어 다른 트랜잭션이 읽거나 변경하지 못하도록 합니다.

2. 낙관적 락 (Optimistic Lock)

  • 설명: 충돌 가능성을 낮게 예상하고 작업을 수행하며, 충돌 발생 시 예외를 처리합니다.
  • 사용 예: 데이터 충돌 가능성이 낮고, 성능이 중요한 경우 (예: 웹 서비스 댓글 수정).
  • 구현:
    데이터에는 version 필드를 추가합니다. 업데이트 시 이 필드를 체크해 충돌을 감지합니다.
    @Transactional
    public void updateAccount(Account account) {
        Account existingAccount = accountRepository.findById(account.getId());
        if (!existingAccount.getVersion().equals(account.getVersion())) {
            throw new OptimisticLockingFailureException("Version mismatch!");
        }
        account.setVersion(account.getVersion() + 1);
        accountRepository.save(account);
    }

3. DB를 통한 업데이트

  • 설명: 계산을 애플리케이션에서 하지 않고, DB 쿼리에서 바로 처리해 동시성 문제를 방지합니다.
  • 사용 예: 값 증가/감소와 같은 간단한 연산.
  • 구현:
    UPDATE account SET balance = balance - 100 WHERE id = 1;
    DB 내부에서 원자성을 보장하기 때문에 안전하지만, 복잡한 연산은 비효율적일 수 있습니다.

4. Redis 사용

  • 설명: Redis의 빠른 속도를 활용해 임시 데이터를 저장하고, 주기적으로 DB에 반영합니다.

  • 사용 예: 실시간성이 덜 중요한 경우, 많은 읽기/쓰기 요청 처리.

  • 구현:

    # Redis에 임시로 값을 저장
    redis.incr("user:1001:balance", 100)
    
    # 주기적으로 Redis 값을 DB에 저장
    balance = redis.get("user:1001:balance")
    update_account_balance_in_db(user_id=1001, balance=balance)
    redis.delete("user:1001:balance")

어떤 방법을 선택할까?

  • 비관적 락: 동시성 문제가 중요한 시스템(은행, 재고 관리 등).
  • 낙관적 락: 충돌 빈도가 낮고, 성능이 중요한 시스템.
  • DB 업데이트: 단순한 연산으로 원자성을 유지해야 하는 경우.
  • Redis: 실시간성이 덜 중요한 대규모 요청을 처리해야 할 경우.
profile
Happy Developer

0개의 댓글