분산 시스템 기초와 장애 감지
- 5.1 동시성과 병렬성
- 5.2 분산 컴퓨팅의 오류
- 5.3 네트워크 파티션
- 5.4 Two Generals Problem
- 5.5 FLP 불가능성
- 5.6 장애 모델
- 5.7 하트비트와 핑
- 5.8 타임아웃 기반 장애 감지
- 5.9 Phi-Accrual 장애 감지기
- 5.10 가십 기반 장애 감지
- 5.11 FUSE와 장애 통지
분산 시스템을 만들기 전에 알아야 할 게 있어 — 완벽한 합의는 이론적으로 불가능하고, "저 노드 죽은 거야, 느린 거야?"라는 질문에 완벽하게 답하는 것도 불가능하다는 거야.
네트워크는 신뢰할 수 없거든. 1994년 Peter Deutsch가 정리한 분산 컴퓨팅의 8가지 오류 중 핵심 세 가지만 봐도 알 수 있어 — 네트워크는 신뢰할 수 없고, 지연 시간은 0이 아니고, 대역폭은 무한하지 않아. 메시지는 유실되고, 지연되고, 중복되고, 순서가 바뀔 수 있지. 단일 머신에서는 함수 호출이 실패하면 에러가 바로 오지만, 분산 환경에서는 응답이 안 올 때 상대가 죽은 건지 느린 건지 알 수가 없어.
네트워크 파티션은 이 불확실성의 극단이야. 네트워크가 둘로 나뉘면 양쪽 모두 자기가 살아있는 쪽이라고 생각하고, 서로 다른 데이터 수정이 일어나면 스플릿 브레인이 발생해. AWS 같은 대형 클라우드에서도 자주 생기는 현실이지. Two Generals Problem은 신뢰할 수 없는 채널에서 두 당사자가 동시에 행동하기로 합의하는 게 불가능하다는 걸 보여주고, FLP 불가능성은 비동기 시스템에서 단 하나의 장애만 있어도 결정론적 합의 알고리즘이 존재할 수 없다고 증명해.
그렇다고 포기하라는 건 아니야. FLP가 불가능하다고 한 건 결정론적이고 항상 종료하는 알고리즘이지, 타임아웃이나 부분 동기 같은 현실적 가정을 추가하면 Paxos나 Raft 같은 실용적 알고리즘이 가능하거든. 그리고 어떤 장애 모델을 가정하느냐에 따라 알고리즘 복잡도가 달라져. 크래시, 크래시-복구, 생략, 비잔틴 순으로 어려워지는데, 대부분의 DB는 크래시-복구 모델을 기준으로 설계돼.
이론적 한계를 이해했으면, 실전에서 장애를 감지하는 방법을 봐야지. 가장 기본적인 방법은 핑이나 하트비트로 주기적으로 "나 살아있어" 메시지를 주고받는 건데, 둘 다 타임아웃에 의존하거든. 문제는 타임아웃 설정이야. 짧으면 네트워크 지연이나 GC 멈춤만으로도 살아있는 노드를 죽었다고 오판하는 거짓 양성이 생기고, 길면 실제로 죽은 노드를 한참 뒤에야 감지해. 네트워크 상태는 계속 변하는데 타임아웃은 고정이니까 한계가 명확하지.
Cassandra가 쓰는 Phi-Accrual 장애 감지기는 이 문제를 통계적으로 풀어. "살았다/죽었다" 이분법 대신 의심 수준(phi) 을 연속적인 값으로 제공하거든. 하트비트 도착 간격의 분포를 모델링해서, 마지막 하트비트 이후 경과 시간이 얼마나 이례적인지를 계산하는 거야. phi = 1이면 오판 확률 10%, phi = 3이면 0.1%. 네트워크 상태에 자동으로 적응하면서 거짓 양성 확률을 정밀하게 제어할 수 있어.
대규모 클러스터에서는 가십 기반 장애 감지가 거의 필수야. 중앙화된 감시는 감시자 자체가 죽으면 끝이잖아. 가십 방식은 각 노드가 아는 정보를 무작위 이웃에게 전파해서 단일 실패점 없이 동작하지. 감지가 즉시 안 되는 건 트레이드오프지만, 결국 장애 감지는 완벽할 수 없다는 걸 받아들이고 거짓 양성이 나도 시스템이 올바르게 동작하도록 설계하는 게 핵심이야.
정리
5장 읽고 기억할 거 세 가지:
- Two Generals Problem과 FLP 불가능성은 분산 합의의 근본적 한계를 보여준다. 완벽한 합의는 불가능하지만, 현실적 가정을 추가하면 실용적 알고리즘이 가능하다.
- 장애 감지의 핵심 딜레마는 타임아웃 설정이며, Phi-Accrual 감지기는 하트비트 간격의 통계적 분포를 모델링해서 네트워크 상태에 자동 적응한다.
- 가십 기반 장애 감지는 단일 실패점 없이 분산 방식으로 동작하며, 장애 감지는 완벽할 수 없다는 전제 위에 시스템을 설계하는 게 핵심이다.