카테고리 없음

분산 잠금(Distributed Locking)과 Consul, etcd 활용법

우리모두 개발자되기 2025. 5. 1. 17:23

분산 잠금(Distributed Locking)과 Consul, etcd 활용법


1. 분산 잠금(Distributed Locking) 개요

분산 시스템에서는
여러 프로세스나 노드가 동시에 동일한 리소스(데이터, 파일 등)에 접근할 수 있습니다.
이로 인해 **경쟁 조건(Race Condition)**이나 데이터 불일치가 발생할 수 있으므로
**분산 잠금(Distributed Locking)**이 필수적입니다.

분산 잠금이란

  • 여러 인스턴스 간에 리소스에 대한 접근을 **직렬화(Serialize)**하는 메커니즘을 의미합니다.
  • 이를 통해 **동시성 제어(Concurrency Control)**와 **데이터 정합성(Data Consistency)**을 확보할 수 있습니다.

2. 분산 잠금의 핵심 요건

  • Mutual Exclusion(상호 배제): 하나의 노드만 리소스에 접근할 수 있어야 함
  • Deadlock Avoidance(교착 상태 방지): 잠금 획득 실패 시 시스템이 멈추지 않아야 함
  • Fault Tolerance(장애 복원력): 노드 장애 발생 시 잠금 자동 해제
  • Fairness(공정성): 모든 노드가 공평하게 잠금 획득 기회를 가져야 함

3. 대표적인 분산 잠금 방식

3.1 데이터베이스 기반 잠금

  • 관계형 데이터베이스에 Lock 테이블을 생성하여 관리
  • 단점: DB 부하 증가, 네트워크 지연에 취약

3.2 캐시 기반 잠금(Redis)

  • Redis SETNX 명령어를 이용한 분산 잠금
  • Expire(만료) 기능을 활용하여 장애 복구
  • RedLock 알고리즘을 통해 안정성 강화

3.3 분산 키-밸류 저장소 기반 잠금(Consul, etcd, Zookeeper)

  • 고가용성(HA) 클러스터 구성
  • 리더 선출, 세션 기반 락 관리 제공
  • 시스템 중단 없이 잠금 유지 가능

이 중 오늘은 특히 Consuletcd를 중점적으로 다루겠습니다.


4. Consul을 이용한 분산 잠금

4.1 Consul 소개

  • HashiCorp에서 개발한 서비스 디스커버리 및 구성 관리 툴
  • Key-Value 저장소 기능 제공
  • 세션(Session) 및 체크(Check) 기반 분산 락 지원

4.2 Consul의 락 원리

  1. 노드가 Session을 생성한다.
  2. 특정 Key에 대해 Acquire(획득) 요청을 한다.
  3. Session이 유효할 때만 해당 Key에 대한 소유권이 유지된다.
  4. 세션 만료(노드 장애 등) 시 잠금은 자동 해제된다.

4.3 Consul 락 구현 방법

# 1. 세션 생성
curl --request PUT http://localhost:8500/v1/session/create -d '{"Name":"my-lock-session"}'

# 2. Key 획득 시도
curl --request PUT http://localhost:8500/v1/kv/lock/my-key?acquire=<session_id> -d 'lock_value'

# 3. Key 해제
curl --request PUT http://localhost:8500/v1/kv/lock/my-key?release=<session_id>

또는 Consul APIConsul Template, HashiCorp SDK를 통해 락을 보다 고수준으로 관리할 수 있습니다.

4.4 Consul 락 사용 시 주의사항

  • **TTL(Session Timeout)**을 적절히 설정하여 장애 시 잠금 해제를 보장해야 함
  • Retry 로직을 추가하여 Lock 획득 실패 대비 필요
  • 네트워크 파티션(Network Partition) 발생 시 복구 전략 수립 필요

5. etcd를 이용한 분산 잠금

5.1 etcd 소개

  • CoreOS가 개발하고, 현재는 CNCF에서 관리
  • 고가용성(HA), 강력한 일관성(Strong Consistency)을 갖춘 Key-Value 저장소
  • Raft Consensus 알고리즘을 기반으로 리더 선출 및 데이터 복제 수행
  • Kubernetes의 주요 컴포넌트로 활용됨

5.2 etcd의 락 원리

  1. Lease를 발급받는다.
  2. Lease를 바탕으로 Key를 생성하고 소유권을 주장한다.
  3. Lease 만료 시 자동으로 Key 삭제 → Lock 해제
  4. 이를 통해 Deadlock 및 Zombie Lock 방지

5.3 etcd 락 구현 방법

Python 예제(etcd3 라이브러리 사용):

import etcd3

client = etcd3.client(host='localhost', port=2379)

# Lease 생성 (10초 동안 유효)
lease = client.lease(10)

# Key를 Lease와 함께 생성 (Lock 획득)
success, _ = client.transaction(
    compare=[
        client.transactions.version('my-lock-key') == 0
    ],
    success=[
        client.transactions.put('my-lock-key', 'locked', lease)
    ],
    failure=[]
)

if success:
    print("Lock acquired")
else:
    print("Lock not acquired")

# Lock 해제 (Key 삭제)
client.delete('my-lock-key')

5.4 etcd 락 사용 시 주의사항

  • Lease 갱신(KeepAlive) 기능을 사용하여 장시간 락 유지 시 세션 유지 필요
  • Lock 획득 실패 시 지수적 백오프(Exponential Backoff) 전략 적용 권장
  • etcd 클러스터 상태(리더 선출, 네트워크 상태)에 따라 일시적 오류 발생 가능

6. Consul vs etcd 분산 잠금 비교

항목 Consul etcd
기반 프로토콜 Gossip, Raft Raft
잠금 관리 방식 Session 기반 Lease 기반
복구 시나리오 세션 만료로 자동 해제 Lease 만료로 자동 해제
장애 복원력 강함 매우 강함
사용 난이도 쉬움 중간
Kubernetes 통합 별도 통합 필요 기본 통합(K8s Core 컴포넌트)
운영 도구 Consul UI, CLI, API etcdctl, API
확장성 높은 편 매우 높음

7. 실전 적용 팁

  • 고가용성 구성: Consul/etcd 모두 3개 이상의 노드로 클러스터 구성
  • Lock Timeout 설정: 네트워크 장애를 고려해 적절한 TTL/Lease 시간 설정
  • Retry 및 백오프 구현: Lock 획득 실패 시 무한 루프 방지
  • 모니터링 연동: Prometheus, Grafana 등을 통해 Lock 상태를 모니터링
  • 네트워크 장애 대비: 클러스터 간 Heartbeat, Health Check 주기 조정

8. 주의해야 할 함정

  • Split-Brain: 네트워크 분리로 두 개 이상의 노드가 동시에 Lock을 가진 것처럼 동작할 수 있음
  • Zombie Lock: 프로세스 죽음에도 락이 해제되지 않는 상황
  • 락 경합(High Contention): 대량의 Lock 요청이 집중될 때 지연 및 실패 발생

이를 방지하려면
정확한 TTL/Lease 설정,
Heartbeat 기반 Health Check,
Auto Failover 구현이 필수입니다.


9. 결론

분산 환경에서 안정적인 Lock 메커니즘은
데이터 정합성, 서비스 안정성, 장애 대응력을 좌우합니다.

  • Consul은 간편한 API와 서비스 디스커버리 통합 장점
  • etcd는 강력한 일관성과 Kubernetes 친화적 특성

환경과 요구사항에 맞추어 적절한 솔루션을 선택하고,
TTL/Lease를 통해 장애 복구까지 고려한
견고한 분산 잠금 체계를 구축해야 합니다.

끊임없이 복잡해지는 분산 시스템에서
**"Locking 전략"**은 더 이상 부가 기능이 아니라,
필수 생존 도구입니다.