- 분산 시스템을 다루는 것은 단일 컴퓨터에서 소프트웨어를 작성하는 것과 근본적으로 다르다.
- 결국 엔지니어로서 우리의 과제는 모든 것이 잘못되는 와중에도 시스템이 자신의 일을 하도록 만드는 것
- 9장에서 우리는 분산 시스템에서 그러한 보장을 제공할 수 있는 알고리즘의 예를 살펴보겠습니다.
❐ 1. 결함과 부분 장애(Faults and Partial Failures)
부분장애란?
- 분산 시스템에서는 시스템의 어떤 부분은 정상 동작하지만, 어떤 부분은 아닐 수도 있다는 것
- 부분장애는 비결정적(nondeterministic) ➔ 같은 조건에서도 결과가 매번 달라질 수 있음.
- 이런 비결정성과 부분 장애 가능성이 분산 시스템을 어렵게 만듬.
🌀 1-1. Cloud Computing and Supercomputing
대규모 컴퓨팅 구축 방법(철학)
- 고성능 컴퓨터
- 클라우드 컴퓨팅
- 위 두 철학의 중간
철학에 따라 결함 처리 방법이 다름
- 슈퍼 컴퓨터 (단일 노드에 가까움)
- 노드 하나에 장애가 나면, 모든 작업을 중단한다.
- 장애가 복구되면 중단 시점부터 다시 계산을 한다.
- 결론 : 부분 장애를 전체 장애로 확대해서 해결
분산 시스템이 동작하게 하려면...
- 부분 장애 가능성을 받아들이고, 소프트웨어에 내결함서 메커니즘을 넣어야 한다.
- 신뢰성 없는 구성 요소를 사용해 신뢰성 있는 시스템을 구축해야 함.
신뢰성 없는 구성 요소를 사용해 신뢰성 있는 시스템을 구축하기
개별 구성 요소가 가끔 오류를 내더라도, 상위 계층에서 보정·재전송·검증 같은 메커니즘을
추가하면 전체 시스템의 신뢰성을 끌어올릴 수 있다.
예를 들어, 무선 통신처럼 잡음으로 오류가 생길 수 있어도, 오류정정코드가 있으면 잘못된 비트를
감지·수정해 올바른 데이터로 복구할 수 있다. 또 IP는 패킷을 유실·지연·중복·순서 뒤바꿈할 수 있는
“신뢰할 수 없는” 프로토콜이지만, 그 위의 TCP가 유실된 패킷을 재전송시키고, 순서를 맞춰 재조립해
“더 신뢰성 있는” 연결처럼 보이게 한다.
하지만 한계는 있다. 오류정정코드가 처리할 수 있는 오류량에는 상한이 있고, TCP가 손실·중복은 해결해도
네트워크 지연 자체를 없애진 못한다. 그럼에도 이런 상위 계층의 설계 덕분에 낮은 수준의 잡다한 장애를 단순화해
다루기 쉬워지고, 남은 문제에 집중할 수 있게 된다.
❐ 2. 신뢰성 없는 네트워크 (Unreliable Networks)
- 인터넷과 데이터센터 내부 네트워크 대부분은 비동기 패킷 네트워크
- 이런 종류의 네트워크에서 노드끼리 메시지(패킷)을 보낼 수 있음.
- 하지만 네트워크는 메시지가 언제 도착할지 혹은 메시지 도착 여부를 보장하진 않음.
- 요청을 보내고 응답을 기다리는 동안 여러가지 문제가 발생할 수 있음.
- 요청 손실
- 요청이 큐에서 늦게 전송
- 원격 노드에 장애 발생
- 원격 노드의 응답이 늦음
- 네트워크가 손실
- 다른 노드로 요청을 보내서 응답을 받지 못했다면 그 이유를 아는 것은 불가능함.
- 이런 문제를 다루는 흔한 방법은 타임아웃
- 근데 이것도 원격노드가 응답을 받았는지 여부는 알 수 없음.
🌀2-1. 현실의 네트워크 결함 (Network Faults in Practice)
- 어떤 연구에서..
- 네트워크 장비를 중복 추가하는 것은 기대만큼 결함을 줄여주지 못한다는 것을 발견
- 즉, 하드웨어 중복만으로는 운영·설정 실수를 예방할 수 없어서 전체 장애율 개선에 한계가 있다.
- 암튼 다양한 이유로 네트워크 결함이 생김
- 소프트웨 어 업그레이드
- 상어 이슈 등등
- 결국 네트워크 결함은 일어날 수 있음! 피할 방법이 없다.
- 그렇다고 반드시 네트워크 결함을 견더내도록(tolerating) 처리할 필요는 없음.
- 그냥 네트워크에 문제가 있다고 사용자에게 보여주는 것도 타당한 방법
- 그러나 시스템이 복구될 수 있도록 보장해야 함
🌀2-2. 결함 감지(Detecting Faults)
시스템은 결함 있는 노드를 자동으로 감지할 수 있어야 함.
- 예를 들면
- 로드 벨런서는 죽은 노드로 요청을 그만 보내야 한다.
- 단일 리더 복제를 사용하는 분산DB에서 리더에 장애가 나면 팔로워 중 하나가 리더로 승격돼야 한다.
- 근데 네트워크의 불확실성 때문에 노드가 동작 중인지 아닌지 구별하기 어려움.
- 원격 노드가 다운되고 있다는 피드백은 유용하지만 여기에 의존 할 수 없음.
- 일반적으로 아무 응답도 받지 못할 것이라 가정해야 함.
- 결국 몇번이고 다시 요청보내서 타임아웃 내에 응답받지 못하면, 마침내 노드가 죽었다고 선언할 수 있음.
🌀2-3. 타임아웃과 기약 없는 지연 (Timeouts and Unbounded Delays)
타임 아웃은 얼마나 길어야 될까?
- 답이 없음.
- 노드가 일시적으로 느려졌을 뿐인데, 죽었다고 잘못 선언할 위험이 있음.
- 노드가 죽었다고 선언되면, 다른 노드가 죽은 노드의 일도 해야 됨.
- 근데 너무 성급하게 죽었다고 선언하면
- 다른 노드가 과부하고 응답이 느려질 수 있음.(최악의 경우 죽음)
- 타임 아웃이 낮으면
- rtt(round-trip time)가 순간적으로 급증하기만 해도 시스템 균형이 깨짐
패킷의 최대 지연 시간이 보장된 네트워크를 사용하는 경우
- 모든 패킷은 전송 시간이 d 보다 더 걸리지 않음.
- 장애가 나지 않은 노드는 항상 요청을 r 시간 내에 처리한다고 가정
- 그렇다면 2d+r을 타임아웃으로 사용하는게 합리적
유감스럽게도 대부분의 시스템은 위와 같은 상황을 보장하지 않음!
- 비동기 네트워크는 기약 없는 지연(unbounded delay)가 있고, 요청을 특정 시간 내에 처리한다고 보장 못함.
네트워크 혼잡과 큐대기
- 네트워크에서 패킷 지연의 변동성은 큐 대기 때문인 경우가 많음.
- 네트워크 혼잡 (network congestion)
- CPU 코어가 바쁜 경우 큐에서 댇기
- 가상 환경에서 실행되는 운영체제
- TCP의 흐름 제어(flow control)
- TCP는 타임아웃 내에 확인 응답을 받지 못하면 패킷이 손실됐다고 간주
- 그리고 손실된 패킷은 자동으로 재전송 ➔ 지연에 한 몫함
타임아웃 대안책 : 파이 증가 장애 감지기 (Phi Accrual failure detector)
- 고정된 타임아웃을 설정하는 대신
- 시스템이 지속적으로 응답 시간과 변동성(jitter)을 측정하고
- 관찰된 응답 시간 분포에 따라 타임아웃을 자동으로 조절하게 하는 방안
🌀2-4. 동기 vs 비동기 네트워크 (Synchronous Versus Asynchronous Networks)
하드웨어에서는 왜 네트워크를 신뢰성 있게 만들 수 없을까?
- 고정 회선 전화 네트워크와 데이터센터 네트워크를 비교해보자.
- 전화 네트워크 (동기식)
- 극단적인 신뢰성 (음성 프레임이 지연되거나 통화가 유실되는 일은 매우 드뭄)
- 회선(circuit)이 만들어짐 ➔ 통화가 끝날때 까지 유지
- 두 명 사이에 있는 전체 경로를 따라서 그 통화에 대해 고정되고 보장된 양의 대역폭이 할당
- 데이터가 라우터를 거치더라도, 큐 대기 문제를 겪지 않음. (동기식)
- 네트워크 종단 지연 시간의 최대치가 고정돼 있음
- 이를 제한 있는 지연(bounded delay)라고 함.
그냥 네트워크 지연을 예측 가능하게 만들 수는 없을까?
| 전화 네트워크 | 데이터센터 네트워크 |
| 그 누구도 사용할 수 없는 회선을 사용함 | 가용 네트워크 대역폭을 기회주의 적으로 사용 |
| 회선이 구성됐을 때 왕복 시간의 최대치를 보장 | 큐 대기의 영향을 받는 패킷 교화 프로토콜(기약 없는 지연) |
| 초당 비트 개수가 상당히 고정되어 있음. | 순간적으로 몰리는 트래픽(bursty traffic)에 최적화 |
지연 시간과 자원 사용률
- 자원이 정적으로 분할된다면 어떤 환경에서는 지연 시간을 보장할 수 있지만, 사용률이 떨어짐.
- 반대로 동적으로 자원을 분할하면 사용률을 높여 비용은 줄이지만 자원 변동이 큼.
❐ 3. 신뢰성 없는 시계 (Unreliable Clocks)
- 두 가지 관점
- 지속 시간 (Durations)
- 시점 (Points in time)
- 분산환경에서 통신은 즉각적이지 않기 때문에 다루기 까다로움.
🌀 3-1. 단조 시계 vs 일 기준 시계 (Monotonic Versus Time-of-Day Clocks)
일 기준 시계 (Time-of-Day Clocks)
- 특정 달력에 따라 현재 날짜와 시간을 반환
- ex. 2025-10-13 21:34:12.123 KST
- 벽시계 시간(wall-clock time)이라고도 함.
- NTP(Network time protocol)로 동기화
- 한 장비의 timestamp는 다른 장비의 timestamp와 동일한 의미를 지닌다는 뜻
'일 기준 시계'는 이상한 점
- 시계 점프 (clock jump)
- NTP 보정 시 시계가 과거로 되돌아가거나 순간적으로 뛰는 현상 발생 → 경과 시간 측정에 부적합
- 윤초(leap second)
- 지구 자전의 불규칙성으로 인해 발생하는 시간 차이를 보정하기 위해
협정 세계시(UTC)에 1초를 더하거나 빼서 시간을 조정하는 것 - 윤초 반영이 불완전해 시계가 실제 시간과 미묘하게 어긋날 수 있음
- 지구 자전의 불규칙성으로 인해 발생하는 시간 차이를 보정하기 위해
- 낮은 해상도(coarse-grained)
- 과거 시스템은 10ms 단위로만 시간 갱신 → 세밀한 타이밍 측정 불가
단조 시계 (Monotonic)
- 지속 시간(시간 구간)을 재는데 접합한 시계
- ex. 32500523123ns, 523.411s
- 해상도가 상당히 좋음
- 시간 구간을 마이크로초나 그 이하 단위로 측정할 수 있음.
- 분산 시스템에서 단조 시계는 나름 good
- 다른 노드의 시계 사이에 동기화가 돼야 한다는 가정이 없고,
- 측정이 약간 부정확해도 민감하지 않기 때문
- 한 시점에서 단조 시계 값을 기록하고, 일정 일을 한 후 나중에 다시 값을 확인하면
➔ 두 값의 차이로 경과 시간을 구할 수 있음. - 단조 시계의 절대적인 값 자체는 의미 없음. 단지 두 시점 사이의 차이가 의미를 가짐.
- 따라서 “이 값이 실제 시간 몇 시인가?” 같은 질문에는 사용할 수 없다.
다중 CPU 환경에서 단조 시계
- 여러 CPU 소켓이 있는 서버의 각 CPU는 독립된 타이머를 가질 수 있음.
- 운영체제는 여러 CPU에서 실행되는 스레드 간의 시간 차이를 줄이기 위해 단조적으로 보이게 하려고 노력
- 하지만 완벽한 단조성 보장은 불가능
NTP와 단조 시계
- NTP는 단조 시계가 진행하는 진도수를 조정할 수 있음 - 시계를 돌린다(slewing)라고 함
- 컴퓨터의 로컬 시계가 NTP 서버 보다 빠르거나 느리다는 것을 발견했을 때
- NTP가 조절할 수 있는 범위는 0.05%
- 단, 단조 시계가 앞이나 뒤로 뛰게 할 순 없음. (시간 점프 X)
🌀 3-2. 시계 동기화와 정확도 (Clock Synchronization and Accuracy)
시계 동기화
- 단조 시계는 동기화가 필요 없음.
- 일 기준 시계는 NTP 서버나 다른 외부 시간에 맞춰 설정돼야 유용함.
시계가 정확한 시간을 알려주게 하는 방법은 신뢰성이 높지 않음.
- 컴퓨터의 quartz(석영) 시계는 아주 정확하지 않음.
- 드리프트(drift) 현상이 생김 : 더 빠르거나 느리게 실행되는 현상
- 드리프트는 장비의 온도에 영향을 받음.
- 컴퓨터 시계가 NTP 서버와 차이가 많이 나면, 동기화 거부 또는 로컬 시계 강제 리셋 가능성 있음.
- 윤초가 발생하는 경우
- 가상화 된 하드웨어
- 완전히 제어할 수 없는 장치에서 소프트웨서 실행하는 경우
- 등등...
🌀 3-3. 동기화된 시계에 의존하기 (Relying on Synchronized Clocks)
시계도 완벽하지 않다!
- 네트워크와 마찬가지로 시계도 결함이 생길 수 있다는 가정하에 설계되어야 하며, 대비되어야 함
- 동기화된 시계가 필요한 소프트웨어는 필수적으로 시계를 모니터링 해야 함.
- 이렇게 함으로써 시계에 문제가 있음을 알아차려야 함.
이벤트 순서화용 타임스탬프 (Timestamps for ordering events)
- 여러 노드에 걸친 이벤트들의 순서를 정하는 경우
- LWW(Last Write Win)라고 배웠음.
- 이때 "최근"의 정의는 '로컬-일 기준 시계'에 의존하면 틀릴 수도 있음!!
- 그래서 순서가 보장되도록 NTP 동기화를 정확히 할 수 있나? 불가능
- 하지만 대안책은 있음.
- 카운터를 기반으로하는 논리적 시계(Logical clock)
- 논리적 시계는 오직 이벤트의 상대적인 순서만 측정.
시계 읽기는 신뢰 구간이 있다. (Clock readings have a confidence interval)
- 불확실성 경계는 시간 출처(time source)를 기반으로 계산할 수 있음.
- 불확실성 = 동기화 후 드리프트 오차 + NTP 서버의 오차 + RTT
- 아쉽게도 대부분 시스템은 불확실성을 노출하지 않음.
- `clock_gettime()`은 해당 타임스탬프의 예상 오차 범위를 말해주지 않음.
- 구글의 트루타임(TrueTime) API는 로컬 시계의 신뢰 구간을 명시적으로 보고함.
- 반환 값 : [earliest, latest]
전역 스냅숏용 동기화된 시계 (Synchronized clocks for global snapshots)
- 스패너(Spanner)
- 트루타임 API가 보고한 시계 신뢰 구간을 사용하여 스냅숏 구현한다.
- 두 개의 신뢰 구간이 있는데, 두 구간이 겹치지 않는다면 B는 분명히 A보다 나중에 실행 된 거임
- 읽기 쓰기 트랜잭션을 커밋하기 전에 의도적으로 신뢰 구간 길이만큼 기다린다.
➔ 트랜잭션 타임스탬프가 인과성을 반영하는 것을 보장하기 위함임.
➔ 이렇게 하면, "데이터를 읽을 지도 모를 트랜잭션"이 충분히 나중에 실행되는게 보장됨
➔ 대기 시간을 가능하면 짧게 유지하기 위해, 스패너는 시계 불확실성을 가능하면 작게 유지해야 함.
🌀 3-4. 프로세스 중단 (Process Pauses)
임차권 (lease)
- 다른 노드들에게 리더가 죽었다고 알 수 있게 해주는 방법 중 하나
- 타임아웃이 있는 잠금과 비슷함.
- 임차권을 획득한 노드는 임차권이 만료될 때까지 본인이 리더임을 알 수 있음.
// 아래 코드의 문제점은?
while (true) {
val request = getIncomingRequest()
// 항상 임차권이 적어도 10초는 남아 있게 보장한다
if (lease.expiryTimeMillis - System.currentTimeMillis() < 10_000) {
lease = lease.renew()
}
if (lease.isValid()) {
process(request)
}
}- 동기화된 시계에 의존
- 임차권 만료 시간(lease.expiryTimeMillis)가 다른 장비에서 설정됐는데 로컬 시계랑 비교함.
- 동기화가 깨지게 되면, 이 코드는 더 이상 기대했던대로 동작안함.
- 프로그램 실행 중에 예상치 못한 중단이 있는 경우
- `lease.isValid()` 줄 근처에서 15초 동안 멈춘다면?
- 요청이 처리되는 시점에 임차권이 만료됐을 수 있음. (하지만 만료 됐음을 알 수 있는 방법이 없음...)
- 쓰레드가 아주 오랫동안 멈출 경우도 가정할 수 있음.
- 아래와 같은 문제가 생기면, 선점 된 쓰레드는 자신이 잠시 멈췄던 사실을 모름.
- "stop-the-world" GC가 동작하는 경우
- 가상 장비가 "suspend" 됐다가 다시 "resume" 되는 경우
- 운영체제가 다른 스레드로 컨텍스트 스위치하는 경우
- 하이퍼바이저가 다른 가상 장비로 스위치되는 경우
- 느린 디스크 I/O 작업이 있는 경우 (ex. 페이지 폴트, 스와핑 등등)
- 아래와 같은 문제가 생기면, 선점 된 쓰레드는 자신이 잠시 멈췄던 사실을 모름.
응답 시간 보장
- 노력하면 위에서 말했던 기약 없는 시간동안의 중단의 원인을 제거할 수 있음.
- 어떻게? 데드라인 설정
- 데드라인을 만족시키지 못하면 전체 시스템 장애를 유발할 수 있음.
- 이를 이른바 엄격한 실시간 시스템(hard real-time systems)이라고 함.
실시간 시스템
- 웹에서 실시간이란?
- 서버가 클라이언트에게 데이터를 푸시하고 엄격한 응답 시간 제약 없이
스트림 처리하는 것을 나타냄
- 서버가 클라이언트에게 데이터를 푸시하고 엄격한 응답 시간 제약 없이
- 실시간을 보장하려면?
- "실시간 운영체제(RTOS)"가 필요함
- 대부분 서버측 데이터 처리 시스템에서 실시간 보장은 경제적이지도 적절하지도 않음.
- 결과적으로 고통 받을 수 밖에 없음.
가비지 컬렉션의 영향을 제한하기 (Limiting the impact of garbage collection)
- GC로 인한 중단을 노드가 중단되는 것으로 간주하고,
노드가 GC를 하는 동안, 다른 노드가 클라의 요청을 처리- 이 방법은 GC로 인한 중단을 클라한테 감추고 응답 시간을 줄여줌.
- 지연 시간에 민감한 금융 거래 시스템에서 이 방법을 쓰는 곳도 있음.
- (방법1의 변형)
- 수명이 짧은 객체만 가비지 컬렉터를 사용하고, 수명이 긴 객체는 GC가 돌기전에 프로세스 재시작
➔ 이 방법들이 GC로 인한 중단을 완전히 막을 순 없지만, 애플리케이션에 유의미한 영향을 미칠 수 있음.
❐ 4. 지식, 진실 그리고 거짓말 (Knowledge, Truth, and Lies)
🌀 4-1. 진실은 다수결로 결정된다.
- 분산 시스템은 한 노드에만 의존할 수 없음.
- 대신 여러 분산 알고리즘은 정족수(quorum), 즉 노드들 사이의 투표에 의존한다.
- 정족수를 이룬 노드들이 다른 노드를 죽었다고 선언하면, 그 노드는 (살아있더라도) 진짜 죽은거
- 노드의 과반수 이상을 정족수로 삼는게 가장 흔함.
- 과반수 정족수를 사용하면 개별 노드들에 장애가 나더라도 시스템은 계속 동작
리더와 잠금
- 오직 하나만 필요한 상황의 예시
- 리더 선출
- 자원 잠금
- 유일한 사용자 등록
- 분산 시스템에서 이런 상황을 구현하려면 중의해야 함.
- A 노드가 스스로를 유일한 노드라고 믿어도, 네트워크 끊겼거나 GC 중단의 이유로
다른 노드들이 동의하지 않을 수 있음. - 즉, 다른 노드들이 A가 죽었다고 생각해서, 그들끼리 리더를 선출했을 수 있음.
- A 노드가 스스로를 유일한 노드라고 믿어도, 네트워크 끊겼거나 GC 중단의 이유로

- HBase 사례: 잠금을 잘못 구현해서 생긴 데이터 오염 버그
- 원인 : 잠금을 잘못 구현해서, GC 중단으로 인해서 클라1이 임차권이 유효하다고 판단
- 결과 : 쓰기 충돌, 데이터 오염
팬싱 토큰

- HBase 같은 사례의 해결 방법 : 펜싱(fencing)
- 잠금 서버가 잠금이나 임차권을 승인할 때마다 펜싱 토큰도 반환한다고 가정
- 펜싱토큰 : 잠금이 승인될 때마다 증가하는 숫자
- 메커니즘 : 자원 자체가 이미 처리된 것보다 오래된 토큰을 사용해서 쓰는 것을 거부함
- 잠금 서비스로 주키퍼를 사용하면 트랜잭션id나 노드 버전을 펜싱 토큰으로 사용할 수 있음.
🌀 4-2. 비잔틴 결함(Byzantine fault)
비잔틴 결함 & 비잔틴 장군 문제
- 비잔틴 결함 ➔ 노드가 실제로 받지 않은 특정 메시지를 받았다고 주장하는 것
- 비잔틴 장군 문제 ➔ 신뢰할 수 없는 환경에서 합의해 도달하는 문제
- 두 장군 문제를 일반화 한 것
- 거짓 메시지나 악의적 행위가 존재할 때 신뢰를 유지할 수 있는가?
비잔틴 내결함성을 지난다.
- 일부 노드에 문제가 있더라도, 시스템이 올바르게 동작하는 시스템을 일컫는 말
- 이런 환경(비행 제어 시스템, 비트코인, 피어투피어 네트워크)에서 유의미함.
웹 애플리케이션에서는 클라이언트의 행동이 임의적이고 악의적이라고 예상해야 함.
- SQL injection, cross site scripting 막아야 함.
- 근데 이걸 하기위해서 비잔틴 내결함성 프로토콜을 쓰진 않음. 그냥 서버에서 처리
약한 형태의 거짓말
- "거짓말"로 부터 보호해주는 메커니즘을 소프트웨어에 추가하는게 가치가 있을 수 있음.
- 근데 이런 보호 메커니즘이 비잔틴 내결함성을 지니진 않음. 그래도 할 가치는 있음.
- 네트워크 오염 문제
- 애플리케이션 레벨에서 별도의 체크섬 검증을 추가
- 애플리케이션 입력 검증
- 입력한 값 검증하기
- NTP
- 여러 서버를 비교하여 이상치 제거
- 네트워크 오염 문제
🌀 4-3. 시스템 모델과 현실
알고리즘 작성 방법
- 그들이 실행되는 하드웨어와 소프트웨어 설정의 세부 사항에 너무 심하게 의존하지 않는 방식으로 작성해야 함.
- 이렇게 하기 위해서는 시스템엣어 발생할 것으로 예상되는 결함의 종류를 정형화 해야 함.
타이밍 가정에 대해서 흔히 사용되는 시스템 모델
- 동기식 모델
- 네트워크 지연, 프로세스 중단, 시계 오차가 모두 제한되어 있음
- 거의 비현실적
- 이상적인 환경 가정. 현실 시스템에는 존재하지 않음
- 부분 동기식 보델
- 대부분의 시간에는 정상(동기식처럼 작동)하지만, 가끔 지연이나 중단이 발생할 수 있음
- 현실적
- 현실 분산 시스템이 가장 근사한 모델
- 비동기식 모델
- 시간의 개념이 없거나 예측 불가능 (시계가 없을 수도 있음)
- 이론적
- 설계가 가능하지만 매우 제한적
가장 널리 쓰이는 세 가지 노드용 시스템 모델
- 죽으면 중단(crash-stop)
- 노드가 한 번 죽으면 다시는 복구되지 않음
- 단순 시뮬레이션 환경, 임베디드 시스템
- 죽으면 복구(crash-recovery)
- 노드가 죽었다가 나중에 다시 살아남 (디스크 등 비휘발성 저장소는 유지)
- 대부분의 현실 시스템
- 비잔틴(임의적) 장애(Byzantine Fault)
- 노드가 거짓 정보, 오류 메시지, 잘못된 결과를 반환할 수 있음
- 악의적 공격, 하드웨어 결함, 버그 등
알고리즘의 정확성
- 알고리즘이 정확하다(correct)는 게 어떤 의미인지 정의하기 위해 알고리즘의 속성을 기술할 수 있다.
- 예를 들어 펜싱 토큰을 생성한다면...
- 유일성
- 단조 일련번호
- 가용성
- 그런데 노드가 다 죽거나, 무한 네트워크 지연이면 알고리즘도 아무것도 못함.
안전성과 활동성
➔ 안전성과 활동성 속성을 구별하면 어려운 시스템 모델을 다루는데 도움이 됨.
- 안전성
- 유일성, 단조 일련번호
- 나쁜 일이 일어나지 않는다.
- 안전성 속성이 위반되면, 그 속성이 깨진 특정 시점을 가리킬 수 있다.
- 안전성 속성이 위반된 후에는 그 위반을 취소할 수 없다. (이미 손상됨)
- 분산 알고리즘은 시스템 모델의 모든 상황에서 안전성 속성이 항상 만족되기를 기대
- 활동성
- 가용성
- 그 정의에 "결국에(eventually)" 이라는 단어를 포함하는 것
- 좋은 일은 결국 일어난다
- 안전성과 반대로 동작(특정 시점 못찾지만, 미래에는 만족시킬 수 있음)
- 분산 알고리즘은 시스템 모델의 모든 상황에서 활동성 속성에 대해서는 경고를 하는게 허용됨.
시스템 모델을 현실 세계에 대응시키기
- 이론은 단순하지만, 현실에서는 복잡함.
- 이론적 모델만으로는 불완전하며, 예상치 못한 상황을 처리하는 “실제 코드”가 필수.
- 즉, “불가능한 일이 실제로 일어나면 어떻게 대응할지까지 설계해야 한다” 는 의미.
- 알고리즘이 올바르다고 증명됐더라도 반드시 현실 시스템에서의 구현도
언제나 올바르게 동작한다고 단정 지을 수 없음.
| 구분 | 이론적 가정 | 현실에서의 문제 |
| Crash-Recovery 모델 | 노드가 죽더라도 디스크의 데이터는 안전하게 남아 있음 | 디스크 오염, 펌웨어 버그, 하드웨어 인식 실패 등으로 데이터 손실 가능 |
| 정족수(Quorum) 알고리즘 | “기억하고 있다”는 노드의 선언을 신뢰 | 노드가 이전 데이터 잊어버릴 수 있음 → 정확성 깨짐 |
| 비잔틴이 아닌(non-Byzantine) 가정 | 노드가 악의적 행동은 하지 않음 | 실제로는 버그, 하드웨어 결함 등으로 예상치 못한 행동 가능 |
'Book > 데이터 중심 애플리케이션 설계' 카테고리의 다른 글
| Part3. 파생 데이터 (Derived Data) (0) | 2025.10.26 |
|---|---|
| 9장. 일관성과 합의 (Consistency and Consensus) (0) | 2025.10.17 |
| 7장. 트랜잭션 (0) | 2025.09.29 |
| 6장. 파티셔닝 (0) | 2025.09.20 |
| 5장. 복제 (0) | 2025.09.14 |