Post

분산 환경의 데이터 일관성을 위한 캐싱과 락킹 전략

분산 환경의 데이터 일관성을 위한 캐싱과 락킹 전략

Ⅰ. 캐싱 전략을 통한 데이터 일관성 보장

분산 서비스 환경에서 애플리케이션 수준의 메모리 캐시를 사용할 경우, 요청이 서로 다른 서버 인스턴스에 분배될 때 서버 간 데이터 불일치 문제가 발생하여 사용자 경험에 악영향을 끼칠 수 있습니다. 이를 해결하고 일관성을 보장하기 위한 핵심 전략은 외부 캐시 서비스(External Level Cache Service)를 도입하는 것입니다.

외부 캐시 서비스 (External Level Cache) 도입

  • 일관성 (Consistency) 확보: Redis와 같은 별도의 캐시 담당 서비스를 둠으로써, 분산 환경(Multi-Instance)에서도 모든 인스턴스에 동일한 캐시 기능을 제공할 수 있습니다. 이를 통해 유저가 동일한 요청에 대해 어떤 인스턴스에 도달하더라도 같은 시간대에 다른 응답을 받는 상황을 방지합니다.
  • 고가용성 (HA) 용이: 캐시 데이터가 각 애플리케이션 인스턴스에 의존하지 않기 때문에, 분산 환경을 위한 고가용성(HA) 구성이 용이합니다.
  • DB 부하 감소: 외부 캐시를 통해 자주 요청되는 데이터를 빠르게 제공하여 DB I/O를 줄일 수 있으며, 이는 대규모 트래픽 상황에서도 DB에 과도한 부하 없이 안정적으로 기능을 제공하도록 돕습니다.

캐싱 전략의 고려 사항

캐시를 통해 일관성을 유지하기 위해서는 캐시 데이터가 오래되거나(Stale) 상하지 않도록 관리하는 전략이 중요합니다.

  • Eviction (제거): 캐시 메모리 확보를 위해 캐시 데이터를 삭제하며, 특히 데이터가 Stale 해진 경우 기존 캐시를 명시적으로 삭제시키는 기능이 사용됩니다.
  • Expiration (유효기간): 캐시 데이터에 유통기한(Lifetime)을 두어, 유효기간이 지난 캐시 데이터는 삭제시키고 새로운 데이터를 사용 가능하게 합니다.

Ⅱ. 락킹 전략 및 순차 처리를 통한 동시성 및 일관성 보장

분산 환경에서 데이터 무결성을 보장하고 동시 접근으로 인한 문제를 해결하기 위해 분산락(Distributed Lock) 또는 메시지 큐(Message Queue)를 활용한 순차 처리 방식을 사용합니다.

Redis 기반 분산락 (Distributed Lock) 전략

분산락은 분산 시스템에서 서로 다른 서버 인스턴스에 대해 일관된 락을 제공하기 위한 장치이며, Redis의 Key-Value 기반 원자성을 활용합니다.

락킹의 중요성과 순서 보장

데이터의 무결성을 보장하기 위해 분산락을 사용할 때는 락 획득과 DB 트랜잭션의 순서를 올바르게 보장해야 합니다.

  • 정상적인 순서: 락의 범위 내에서 트랜잭션이 일어나야 동시성 이슈가 발생하지 않습니다. 동시에 두 요청이 들어오더라도 락을 통해 하나의 작업만 진행되므로 상품 재고 차감 등에 동시성 이슈가 발생하지 않습니다.
  • 잘못된 순서가 초래하는 일관성 문제:
    • 트랜잭션 시작 후 락 획득 시: 앞단의 트랜잭션 커밋 결과를 확인하지 못한 채 재고를 조회하여 로직을 수행할 수 있어, 정상적으로 재고를 차감할 수 없습니다. 또한, 락 획득을 위한 대기 시간 동안 데이터베이스 커넥션을 유지하게 되어 DB에 부하를 유발하고 처리 성능을 감소시킵니다.
    • 락 해제 후 트랜잭션 커밋 시: 대기하던 요청이 락 해제 이후 트랜잭션의 커밋 반영 이전의 재고를 조회해와 차감하는 로직을 수행할 수 있어, 마찬가지로 정상적으로 재고를 차감할 수 없습니다.

분산락의 특징 및 이점

  • DB 부하 최소화: Redis의 높은 원자성을 활용하여 프로세스 처리 단위에 동일한 Lock을 여러 인스턴스에 적용할 수 있으며, 이는 DB의 Connection이나 오래 걸리는 I/O에 대한 접근 자체를 차단함으로써 DB에 가해지는 직접적인 부하를 원천 차단하는 데 매우 효과적입니다.
  • 동시 요청 제어: 유저의 잔액 충전과 사용과 같은 동시 요청을 제어하는 데 활용됩니다.

Redis 분산락 구현 방식

Redis를 활용한 분산락에는 세 가지 대표적인 방식이 있습니다:

  1. Simple Lock: 락 획득에 실패할 경우 비즈니스 로직을 수행하지 않고 예외를 발생시킵니다.
  2. Spin Lock: 락 획득에 실패할 경우 일정 시간/횟수 동안 락 획득을 재시도합니다. (단, 지속적인 재시도로 네트워크 비용 및 스레드 점유 문제가 발생할 수 있습니다).
  3. Pub/Sub: Redis의 구독 기능을 이용해 락을 제어합니다. 락 획득에 실패했을 때 “구독” 상태로 대기하며 차례가 될 때까지 이벤트를 기다리는 방식으로, 효율적인 락 관리가 가능하고 선점한 작업만 락 해제가 가능하여 안정적인 원자적 처리가 가능합니다.

메시지 큐 (Kafka)를 통한 순차 처리 전략

메시지 큐(예: Kafka)와 같이 순서 보장이 가능한 장치를 이용해 동시성 이슈를 해결하고 데이터 일관성을 보장할 수 있습니다.

  • Queue의 성질 이용: 메시지 큐의 Queue 성질을 이용하여 처리 순서를 보장함으로써 특정 데이터에 대한 동시 접근 문제를 근본적으로 해결할 수 있습니다.
  • 파티션 기반 순서 보장: Kafka의 발행 메시지는 기본적으로 파티션에 분산되지만, “동일한 key”로 메시지를 발행할 경우 항상 동일한 파티션에 메시지가 발행되는 것을 보장하여 컨슈머가 순서대로 처리하도록 할 수 있습니다.
  • 성능적 우위: 트랜잭션의 범위를 좁히고 순차 처리를 보장할 수 있으므로 성능적 우위를 가져올 수 있습니다. (단, 비동기 처리가 되므로 처리 결과를 바로 확인할 수 없다는 단점이 있습니다).
This post is licensed under CC BY 4.0 by the author.