Workspace IndexAlgorithms › Day 68

[Review] The Habit of Writing Down Failure Model and Trust Assumptions First TODO

Algorithms · Day 68 / 100 · D. Distributed Systems & Consensus (Day 52-68)

Concept

In distributed systems design, what any given algorithm guarantees is always a function of its assumptions, so the first line of a design doc should be its failure model and trust assumptions. Failure models range from crash-stop (a node halts and stays halted), to crash-recovery (it halts and later comes back), to omission (it drops messages), to Byzantine (it can lie arbitrarily) — and the required quorum size and cost both grow as you move further down that list. Timing models split into synchronous, partially synchronous, and asynchronous; it's a known result that deterministic consensus is impossible in a fully asynchronous model with even a single crash failure. Trust assumptions cover things like the fraction of honest nodes, the existence of authenticated channels and signatures, bounds on clock skew, and which parties are considered trustworthy at all. Without stating these explicitly, there's no way to discuss what safety or liveness gets sacrificed and when, and no way to attribute an incident's cause to a violated assumption after the fact.

Most real outages aren't code bugs — they're an undocumented assumption quietly breaking. If the assumption was never written down, there was never a way for review to catch its violation in the first place.

Code & Formula

# [복습] 장애 모델과 신뢰 가정을 먼저 쓰는 습관 — 컴포넌트별 장애 모델·타이밍 모델·정족수를 명시하고 위반 시 무엇이 무너지는지 판정한다.
# 가정을 표로 적어두면 "안전성 vs 활성 중 무엇을 먼저 잃는가"를 코드 없이도 기계적으로 도출할 수 있다.

components = [
    {"name": "체인 합의", "failure_model": "byzantine", "timing": "partial-sync", "quorum_desc": "2f+1 of 3f+1"},
    {"name": "오라클", "failure_model": "crash-recovery", "timing": "async", "quorum_desc": "1-of-N 정직한 리포터"},
    {"name": "시퀀서", "failure_model": "crash-stop", "timing": "sync", "quorum_desc": "단일 운영자(정족수 없음)"},
]

def assess(c):
    if "단일" in c["quorum_desc"]:
        return "활성 취약: 운영자 장애 시 서비스 정지 / 안전성은 유지"
    if c["failure_model"] == "byzantine":
        return "안전성: 악의 노드 < 1/3이면 유지 / 활성: partial-sync 가정이 깨지면 정지"
    if c["timing"] == "async":
        return "안전성 유지 가능 / 활성: 메시지 지연이 무한하면 정지 보장 불가"
    return "안전성: 장애 수 < 정족수면 유지 / 활성: 정족수 확보 시 유지"

for c in components:
    print(f"[{c['name']}] 장애모델={c['failure_model']}, 타이밍모델={c['timing']}, 정족수={c['quorum_desc']}")
    print(f"  -> 판정: {assess(c)}")

Exercise

Pick one component of the system you're currently working on and write one line each for its failure model, timing model, trusted parties, and quorum assumptions, then table out which of safety or liveness breaks first when each assumption is violated.

Practical Connection

A prediction market has the chain, the oracle, the sequencer, and its own backend each carrying a different failure model and trust level, so writing this out on one page makes it immediately clear what needs defending during a settlement dispute or an oracle delay.

If you study this on a given day, add a note link and a ✅ to this line in the source curriculum (docs/knowledge/dev-100-curriculum.md) and this spot will lead straight to the note body. You can also write directly on this page — but regenerating overwrites it, so it's safer to keep anything you want to save as markdown under docs/algorithms/.


한국어

[복습] 장애 모델과 신뢰 가정을 먼저 쓰는 습관 TODO

Algorithms · Day 68 / 100 · D. 분산시스템·합의 (Day 52–68)

개념

분산 시스템 설계에서 어떤 알고리즘이 무엇을 보장하는지는 항상 가정의 함수이므로, 설계 문서의 첫 줄은 장애 모델과 신뢰 가정이어야 한다. 장애 모델은 노드가 멈추고 끝나는 crash-stop, 멈췄다 복구되는 crash-recovery, 메시지를 흘리는 omission, 임의로 거짓말하는 Byzantine 등으로 구분되며 뒤로 갈수록 필요한 정족수와 비용이 커진다. 타이밍 모델은 동기, 부분 동기, 비동기로 나뉘고, 완전 비동기에서는 하나의 크래시만 있어도 결정론적 합의가 불가능하다는 것이 알려져 있다. 신뢰 가정에는 정직한 노드 비율, 인증된 채널과 서명의 존재, 시계 오차 한계, 그리고 어떤 주체를 신뢰할 수 있다고 보는지가 들어간다. 이 가정들을 명시하지 않으면 안전성과 활성 중 무엇을 언제 포기하는지 논의할 수 없고, 사고 시 원인을 가정 위반으로 귀속시킬 수도 없다.

실제 장애는 대부분 코드 버그가 아니라 문서화되지 않은 가정이 조용히 깨질 때 발생하고, 가정이 적혀 있지 않으면 리뷰에서 그 위반을 지적할 방법 자체가 없다.

코드 · 수식

# [복습] 장애 모델과 신뢰 가정을 먼저 쓰는 습관 — 컴포넌트별 장애 모델·타이밍 모델·정족수를 명시하고 위반 시 무엇이 무너지는지 판정한다.
# 가정을 표로 적어두면 "안전성 vs 활성 중 무엇을 먼저 잃는가"를 코드 없이도 기계적으로 도출할 수 있다.

components = [
    {"name": "체인 합의", "failure_model": "byzantine", "timing": "partial-sync", "quorum_desc": "2f+1 of 3f+1"},
    {"name": "오라클", "failure_model": "crash-recovery", "timing": "async", "quorum_desc": "1-of-N 정직한 리포터"},
    {"name": "시퀀서", "failure_model": "crash-stop", "timing": "sync", "quorum_desc": "단일 운영자(정족수 없음)"},
]

def assess(c):
    if "단일" in c["quorum_desc"]:
        return "활성 취약: 운영자 장애 시 서비스 정지 / 안전성은 유지"
    if c["failure_model"] == "byzantine":
        return "안전성: 악의 노드 < 1/3이면 유지 / 활성: partial-sync 가정이 깨지면 정지"
    if c["timing"] == "async":
        return "안전성 유지 가능 / 활성: 메시지 지연이 무한하면 정지 보장 불가"
    return "안전성: 장애 수 < 정족수면 유지 / 활성: 정족수 확보 시 유지"

for c in components:
    print(f"[{c['name']}] 장애모델={c['failure_model']}, 타이밍모델={c['timing']}, 정족수={c['quorum_desc']}")
    print(f"  -> 판정: {assess(c)}")

연습

지금 다루는 시스템의 컴포넌트 하나를 골라 장애 모델, 타이밍 모델, 신뢰 주체, 정족수 가정을 각각 한 줄로 적고, 각 가정이 깨졌을 때 안전성과 활성 중 무엇이 먼저 무너지는지 표로 정리하라.

실무 · Verex 연결

예측시장은 체인, 오라클, 시퀀서, 자체 백엔드가 각기 다른 장애 모델과 신뢰 수준을 가지므로 이를 한 장에 명시해 두면 정산 분쟁이나 오라클 지연 상황에서 어디를 방어해야 하는지가 즉시 드러난다.

공부한 날 원본 커리큘럼(docs/knowledge/dev-100-curriculum.md)의 이 줄에 노트 링크와 ✅ 를 붙이면, 이 자리는 노트 본문으로 바로 이어집니다. 노트 없이 이 페이지에 바로 적어도 됩니다 — 다만 다시 생성하면 덮어쓰이므로, 남길 글은 docs/algorithms/ 의 마크다운으로 쓰는 편이 안전합니다.

← 67. 멱등성과 "정확히 한 번"69. MVCC 내부와 스냅샷 격리의 이상현상(write skew) →