이 아키텍처 문제의 기원은 고차율 및 지역 간 배포가 발생하는 클라우드 네이티브 환경에서 Apache ZooKeeper의 한계에서 시작됩니다.
초기 분산 시스템은 중앙 집중식 조정에 의존했지만, etcd와 Consul은 엄격한 쿼럼 기반 합의가 대륙 간 150ms를 초과하는 WAN 지연에 어려움을 겪는다는 것을 밝혀냈습니다.
현대의 요구사항은 Kubernetes 제어 평면이 가용성 영역 간에 리더를 선출하면서 섬유 절단 및 지역 저하 동안 엄격한 안전 보장을 유지해야 한다는 것입니다.
근본적인 긴장은 비동기 네트워크를 통한 합의 프로토콜(예: Raft 또는 Paxos)을 구현할 때 CAP 정리 제약을 조화시키는 데 있습니다.
분산 잠금은 임대 만료 후 좀비 프로세스가 상태를 손상시키지 않도록 방지하기 위한 펜싱 메커니즘이 필요하고, 리더 선출은 통신이 중단된 비대칭 네트워크 파편화 시에도 고유성을 보장해야 합니다.
또한, 수천 개의 일시적인 세션을 조정하는 것은 백업 저장소에 대한 쓰기 증폭을 초래하여 대량 재배포 또는 스팟 인스턴스 종료 중 성능 저하를 일으킬 수 있습니다.
아키텍처는 Raft 그룹을 사용한 계층적 합의 모델을 채택하고, 결함 도메인에 따라 분할되어 있으며, 전체 상태 로그를 유지하지 않고 쿼럼 계산에 참여하는 위원 노드를 추가합니다.
etcd에 저장된 단조적인 펜싱 토큰을 활용하여 Redis-호환 Redlock 알고리즘을 구현하고, 자원 작업의 유효성을 보장하여 구식 요청을 거부하도록 해야 합니다.
네트워크 지연과 노드 충돌을 구별하기 위해 Phi Accrual 장애 감지를 사용하고, gossip 프로토콜을 통해 효율적인 클러스터 멤버십 업데이트를 수행합니다.
일시적인 지역적 연결 끊김을 우아하게 처리하기 위해 자동 유지 관리 재시도가 포함된 Chubby 스타일 세션 임대 구현하는 사이드카 프록시를 배포합니다.
글로벌 금융 거래 플랫폼은 해저케이블 손상 동안 재앙적인 분할 뇌 시나리오를 경험하여 두 개의 지역 리더가 동일한 자산 분할에 대해 동시에 권한을 주장할 때 상충되는 거래 실행이 발생했습니다.
해결책 1: 전 세계 쿼럼을 갖춘 단일 etcd 배포. 이 접근 방식은 미국 동부 지역에 하나의 etcd 클러스터를 배포하고 다른 곳에는 읽기 전용 미러를 두었습니다. 장점으로는 간단한 선형화 및 최소 구성 복잡성이 포함됩니다. 단점은 아시아 태평양 트레이더에게 300ms를 초과하는 쓰기 지연 및 미국 동부 지역 실패 동안 완전한 서비스 불능 상태가 발생하여 필수 99.999% 가동 시간 SLA를 위반했습니다.
해결책 2: 비동기 복제를 통한 독립 지역 클러스터. 각 지역마다 별도의 etcd 클러스터를 배포하고 마지막 쓰기 승리 휴리스틱을 통한 충돌 해결을 수행했습니다. 장점으로는 10ms 미만의 지역 지연 및 운영 분리가 있었습니다. 단점으로는 임시적으로 여러 리더가 동시에 공유 상태를 수정할 수 있게 하여 재정 규제 요구사항을 위반하고 이중 지출 취약점을 허용했습니다.
해결책 3: 위원 노드 및 펜싱 토큰을 가진 계층적 합의. 지역 Raft 그룹을 구현하여 지역 조정을 수행하고, 전 세계 합의 레이어를 통해 경량 위원 노드를 사용하여 지역 간 쿼럼을 유지했습니다. 장점으로는 50ms 미만의 지역 작업 및 리더 승격을 위해 주 지역 합의와 다수의 위원이 필요한 중단 동안 안전 보장이 포함되었습니다. Redis 클러스터는 거래 엔진에 의해 확인된 일정하게 증가하는 펜싱 토큰을 사용한 분산 잠금을 제공했습니다. 이 솔루션은 네트워크 파편화 동안 안전성을 유지하면서 지역이 실제로 고립될 때만 가용성을 희생하는 방식으로 안전 불변 조건(단일 리더)을 보존했습니다.
결과적으로 분할 뇌 사건이 완전히 제거되고 잠금 대기 시간이 250ms에서 12ms로 감소하였으며 프랑크푸르트 데이터 센터의 완전한 중단 동안 거래 지속성을 성공적으로 유지했습니다.
질문 1: Raft는 높은 상태 회전율이 있는 환경에서 로깅 압축을 어떻게 처리합니까? 그 과정에서 리더 선출 또는 클라이언트 작업을 차단하지 않습니다.
답변: Raft는 스냅샷을 통해 로그 성장을 처리하지만, 후보자들이 종종 간과하는 중요한 구현 세부사항은 스냅샷 설치가 비동기적으로 이루어져야 리더 차단을 방지할 수 있다는 점입니다. 리더는 Copy-on-Write 의미를 사용하여 유한 상태 기계의 시점 스냅샷을 생성한 다음, 지체된 추종자에게 청크화된 gRPC 스트림을 통해 스냅샷을 전송합니다. 필요한 뉘앙스: 리더는 모든 추종자가 스냅샷 수신을 확인할 때까지 로그 항목을 유지해야 하며, 정상 복제를 통해 따라잡도록 요구하여 대규모 재연결 시 OOM 오류를 방지하기 위한 면밀한 메모리 관리가 필요합니다.
질문 2: 왜 Redis Redlock은 안전 보장을 위해 본질적으로 시계 동기화를 요구하며, 이 의존성을 없애는 메커니즘은 무엇입니까?
답변: 후보자들은 종종 Redlock이 시계 드리프트로 인해 잠금 중첩이 발생하기 때문에 본질적으로 안전하지 않다고 주장합니다. Redlock은 대략 동기화된 시계를 가정하지만, 시계 동기화 없이 실제 안전성을 확보하려면 각 잠금 부여와 관련된 단조적으로 증가하는 정수인 펜싱 토큰을 구현해야 합니다. 보호된 자원(데이터베이스, 파일 시스템)은 처리된 최대 토큰을 추적해야 하며, 더 낮은 토큰을 지닌 모든 작업을 거부하여 지연된 프로세스가 부활하여 만료된 잠금을 사용하려 할 경우 해당 구식 토큰이 자원 계층에 의해 자동으로 거부되도록 해야 합니다.
질문 3: 리더 잠금이 만료되고 수천 개의 클라이언트가 동시에 인수하려 할 때 Thundering Herd 문제를 방지하는 정확한 메커니즘은 무엇입니까?
답변: 리더가 충돌할 경우, 나이브 구현은 수천 개의 클라이언트가 동시에 잠금을 요청하게 하여 조정 서비스를 압도합니다. 후보자들은 종종 지수 백오프를 추천하지만, 이는 단지 조정된 스파이크를 줄이는 것일 뿐입니다. 올바른 아키텍처 패턴은 ZooKeeper의 일시적 순차적 노드 또는 etcd의 Watch와 prevKV를 사용하여 분산 큐를 구현하는 것입니다. 클라이언트는 정렬된 항목을 생성하고 즉각적인 이전 항목만 모니터링합니다. 잠금이 해제되면, 순서대로 다음 클라이언트만 알림을 받아 인수 문의 세분화 및 요청 곡선을 **O(n)**에서 O(1) 알림으로 평탄화합니다.