# 분산 락이 실패하는 이유? GC 일시정지 15초가 동시성을 무너뜨린 실제 사례

---

# # 서론 – “왜 우리 시스템은 갑자기 멈추나요?”

분산 시스템을 운영하다 보면 **“잠시 멈췄다가 다시 살아났다”**는 현상을 경험하게 됩니다.

특히 **Redis**와 같은 외부 저장소를 이용해 **분산 락(Distributed Lock)**을 구현했음에도 불구하고, 갑자기 락이 해제되지 않아 서비스가 정지하는 경우가 있습니다.

최근 Reddit에 올라온 한 개발자의 포스트에서는 **Java 애플리케이션이 15초 동안 가비지 컬렉션(GC) 일시정지**에 빠지면서, **Redis 락을 잡고 있던 프로세스 A**가 응답하지 않아 전체 결제 흐름이 멈춘 사례가 소개되었습니다.

> *“프로세스 A가 Redis에서 락을 잡고 출금 작업을 시작했지만, Java가 GC를 실행하면서 15초 동안 멈춰버렸다.”*

이 글에서는 **왜 GC 일시정지가 분산 락을 깨뜨리는지**, 그리고 **예방·대응 방법**을 초보자도 이해하기 쉽게 풀어보겠습니다.

---

# # 1️⃣ 분산 락이란 무엇이고, 어떻게 동작하나요?

## # 1-1. 기본 개념

- **분산 락**은 여러 서비스 인스턴스가 동시에 같은 자원(예: 데이터베이스 레코드, 파일, 결제 트랜잭션 등)에 접근하지 못하도록 제어하는 메커니즘입니다.

- 가장 흔히 쓰이는 구현체는 **Redis**의 `SET key value NX PX ttl` 명령으로, **키가 없을 때만 생성**하고 **TTL(Time‑To‑Live)** 로 자동 해제를 보장합니다.

## # 1-2. 일반적인 흐름

1. **락 요청** → `SET lock_key my_id NX PX 10000` (10초 TTL)

2. **성공** → 비즈니스 로직 수행 (예: 출금 처리)

3. **완료** → `DEL lock_key` 혹은 **TTL 만료**에 의해 자동 해제

## # 1-3. 실패 시나리오

- **프로세스 비정상 종료** → TTL이 지나면 자동 해제 → 정상 복구

- **프로세스가 일시정지**(GC, 스레드 대기 등) → **TTL이 감소**하지만 로직이 진행되지 않아 **락이 해제되지 않음** → 다른 인스턴스가 락을 획득 못함 → **서비스 정지**

> **핵심 포인트**: 분산 락은 **시간 제한**에 의존하므로, 락을 잡은 스레드가 **예상보다 오래 멈출 경우** 타임아웃보다 더 오래 락이 유지될 수 있습니다.

---

# # 2️⃣ GC 일시정지(Garbage Collection Pause)란?

## # 2-1. GC의 역할

Java 가상 머신(JVM)은 **힙 메모리**에 할당된 객체를 자동으로 정리해 메모리 누수를 방지합니다. 이 과정이 **가비지 컬렉션**이며, 크게 **Stop‑The‑World(STW)** 와 **Concurrent** 두 가지 방식이 있습니다.

## # 2-2. Stop‑The‑World(STW) 일시정지

- **STW** 모드에서는 **모든 애플리케이션 스레드가 멈추고** GC 스레드만 실행됩니다.

- **Pause 시간**은 힙 크기, 객체 생존율, GC 알고리즘 등에 따라 수 ms부터 수 초까지 다양합니다.

## # 2-3. 왜 15초가 나왔을까?

- **대용량 힙**(예: 8~16 GB) + **Full GC** (Mark‑Sweep‑Compact)

- **메모리 압박** → 오래된 객체가 많이 남아 있어 **전체 힙을 스캔**해야 함

- **JVM 옵션 미조정** → `-XX:+UseG1GC` 대신 **Parallel GC** 사용 → 일시정지 시간이 급증

> **결과**: 15초 동안 모든 비즈니스 로직이 멈추고, **Redis 락은 그대로 유지**되어 다른 인스턴스가 접근 못함.

---

# # 3️⃣ 실제 사고 분석 – Reddit 사례 상세 해부

| 단계 | 발생 상황 | 문제점 |

|------|----------|--------|

| 1️⃣ 락 획득 | Process A가 `SET lock_key A NX PX 15000` 호출 → 락 잡힘 | 정상 |

| 2️⃣ 비즈니스 로직 | 출금 처리 시작 (DB 업데이트, 외부 API 호출) | 진행 중 |

| 3️⃣ GC 발생 | JVM이 Full GC 실행 → **15초 STW** | 모든 스레드 멈춤 |

| 4️⃣ 락 유지 | TTL은 계속 감소하지만, 로직이 멈춰 **해제되지 않음** | 다른 인스턴스가 락을 못 잡음 |

| 5️⃣ 서비스 장애 | 사용자는 출금 요청에 대한 응답을 받지 못함 | 시스템 전체 정지 |

## # 교훈

- **GC 일시정지는 락 유지 시간보다 길어질 수 있다**.

- **TTL 설정만으로는 충분히 보호되지 않는다**.

- **모니터링과 알림**이 없으면 문제 발견이 늦어져 서비스 복구가 지연된다.

---

# # 4️⃣ 예방·대응 전략 – GC와 락을 동시에 관리하기

## # 4-1. GC 튜닝

1. **Heap Size 최적화** – 과도하게 큰 힙은 Full GC를 유발합니다.

2. **G1GC 혹은 ZGC 사용** – **Low‑Pause** 컬렉터로 STW 시간을 10 ms 이하로 유지합니다.

3. **JVM 옵션 예시**

   
```
bash

   -Xms4g -Xmx4g \

   -XX:+UseG1GC \

   -XX:MaxGCPauseMillis=200 \

   -XX:+UnlockExperimentalVMOptions -XX:+UseZGC

   
```

4. **Heap Dump & 분석** – `jmap`, `jvisualvm` 로 메모리 사용 패턴을 파악하고, **객체 생성량**을 줄입니다.

## # 4-2. 락 설계 보강

- **Lock Timeout보다 짧은 작업 타임** 보장 → **비즈니스 로직에 타임아웃** 적용 (예: `Future.get(5, TimeUnit.SECONDS)`)

- **Watchdog** 스레드 도입 → 락이 일정 시간 이상 유지되면 자동 해제하거나 알림 전송

- **Redlock 알고리즘** 사용 → 다중 Redis 인스턴스로 **내구성 강화**

## # 4-3. 모니터링 & 알림

| 항목 | 도구 | 알림 기준 |

|------|------|-----------|

| GC Pause Time | Prometheus + Grafana (jvm\_gc\_pause\_seconds) | 100 ms 초과 시 Slack 알림 |

| Lock Duration | Redis `INFO COMMANDSTATS` + custom metric | TTL 초과 시 PagerDuty |

| Application Latency | OpenTelemetry | 95th percentile > 2 s |

## # 4-4. 테스트 환경 구축

- **Chaos Engineering**: `Chaos Mesh` 혹은 `Gremlin` 으로 **GC 지연**을 인위적으로 발생시켜 시스템 복원력을 검증합니다.

- **Load Test**: `k6` 혹은 `JMeter` 로 동시에 여러 인스턴스가 락을 잡는 상황을 시뮬레이션합니다.

---

# # 5️⃣ 결론 – 지금 바로 적용할 수 있는 실천 체크리스트

1. **GC 로그 활성화** (`-Xlog:gc*`) → Pause 시간 확인

2. **Heap Size를 현재 사용량의 2배 이하**로 제한하고, **Low‑Pause GC** 도입

3. **Redis 락에 Watchdog**을 추가하고, **타임아웃을 비즈니스 로직보다 짧게** 설정

4. **Prometheus + Grafana** 로 GC Pause와 락 상태를 실시간 모니터링

5. **Chaos 테스트**로 GC 지연 상황을 사전에 검증

> **핵심 메시지**: *GC 일시정지는 눈에 보이지 않지만, 분산 락과 결합될 때 치명적인 서비스 중단을 일으킬 수 있습니다.* 적절한 **GC 튜닝**과 **락 설계 보강**, 그리고 **모니터링**을 통해 이러한 위험을 미리 차단하세요.

---

## # 📢 행동 유도

- **지금 바로** 프로젝트의 `pom.xml` 혹은 `build.gradle`에 **GC 튜닝 옵션**을 추가하고, **Redis 락 구현 코드를 리뷰**해 보세요.

- **팀 회의**에서 “GC 일시정지와 분산 락” 주제로 **5분 발표**를 준비하면, 팀 전체의 인식 개선에 큰 도움이 됩니다.

- **블로그 구독** 및 **댓글**로 여러분이 겪은 비슷한 사례를 공유해 주세요. 함께 해결책을 찾아갑시다!

---

*SEO 키워드: **분산 락**, **GC 일시정지**, **자바 가비지 컬렉션***
