Workspace IndexAlgorithms › Day 50

Chaos Engineering and Failure-Injection Design TODO

Algorithms · Day 50 / 100 · C. Concurrency & Performance Engineering (Day 36-51)

Concept

Chaos engineering is a methodology that deliberately injects controlled failures into a production-like environment to test, by experiment, the hypothesis that a system keeps behaving normally. The procedure is: define a steady state using observable metrics, form a hypothesis that this metric holds even under a given failure, inject an actual failure (instance termination, added latency, packet loss, an error response from a dependency), and observe whether the hypothesis breaks. The core principles are to start with a small blast radius and widen it gradually, and to define abort conditions in advance that stop the experiment immediately. The goal isn't to create failures — it's to surface latent defects that were already there (missing timeouts, retry storms, circular dependencies, bad fallbacks) within a controlled window.

Real failures in distributed systems come less from individual components than from the combination of timeouts, retries, and fallbacks between them, and unit tests never catch that kind of interaction.

Code & Formula

# 카오스 엔지니어링·장애 주입 설계 — 정상 상태를 정의하고, 장애(지연 주입)를 걸어 가설이 깨지는지 관찰한다.
# 폭발 반경을 작게 시작하고, abort 조건을 넘으면 즉시 실험을 중단한다.

import random

random.seed(5)

def call_dependency(latency_ms, fail_rate=0.0):
    """외부 의존(RPC/DB) 호출을 흉내: 지연과 실패율을 파라미터로 받음"""
    ok = random.random() > fail_rate
    return ok, latency_ms + random.uniform(-2, 2)

def measure_steady_state(n_calls, injected_latency_ms=0, injected_fail_rate=0.0):
    latencies, errors = [], 0
    for _ in range(n_calls):
        ok, lat = call_dependency(10 + injected_latency_ms, injected_fail_rate)
        latencies.append(lat)
        if not ok:
            errors += 1
    error_rate = errors / n_calls
    avg_latency = sum(latencies) / len(latencies)
    return avg_latency, error_rate

# 1. 정상 상태(steady state) 정의: 평균 지연 < 20ms, 에러율 < 1%
baseline_latency, baseline_error = measure_steady_state(200)
print(f"[정상 상태] 평균 지연 {baseline_latency:.1f}ms, 에러율 {baseline_error*100:.1f}%")

# 2. 가설: "RPC 노드에 100ms 지연이 추가돼도 평균 지연은 150ms 미만, 에러율은 5% 미만이다"
def run_experiment(injected_latency_ms, injected_fail_rate, blast_radius_calls):
    ABORT_ERROR_RATE = 0.20  # 폭발 반경을 넘는 피해가 감지되면 즉시 중단
    latency, error_rate = measure_steady_state(
        blast_radius_calls, injected_latency_ms, injected_fail_rate
    )
    aborted = error_rate > ABORT_ERROR_RATE
    return latency, error_rate, aborted

for label, inj_latency, inj_fail in [
    ("작은 폭발 반경: RPC 지연 +100ms", 100, 0.02),
    ("의존 서비스 오류 응답 20%", 0, 0.20),
]:
    latency, error_rate, aborted = run_experiment(inj_latency, inj_fail, blast_radius_calls=50)
    hypothesis_holds = latency < 150 and error_rate < 0.05
    status = "ABORT (폭발 반경 초과)" if aborted else (
        "가설 유지" if hypothesis_holds else "가설 깨짐 -> 결함 발견"
    )
    print(f"[{label}] 지연 {latency:.1f}ms, 에러율 {error_rate*100:.1f}% -> {status}")

Exercise

In staging, inject artificial latency and intermittent errors into one external dependency (an RPC node or a database), record how the error rate and latency metrics change, then fix the timeout and retry policy and repeat the same experiment to confirm the improvement numerically.

Practical Connection

A prediction-market service depends on chain RPC, an oracle, and an indexer all at once, so experimenting in advance with whether RPC or oracle latency halts the entire settlement pipeline can substantially cut real operational risk.

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 50 / 100 · C. 동시성·성능 엔지니어링 (Day 36–51)

개념

카오스 엔지니어링은 운영과 유사한 환경에 통제된 장애를 의도적으로 주입해, 시스템이 정상 동작을 유지한다는 가설을 실험으로 검증하는 방법론이다. 절차는 관측 가능한 지표로 정상 상태(steady state)를 정의하고, 특정 장애 하에서도 그 지표가 유지된다는 가설을 세우고, 실제 장애(인스턴스 종료, 지연 추가, 패킷 손실, 의존 서비스 오류 응답)를 주입한 뒤 가설이 깨지는지 관찰하는 순서다. 핵심 원칙은 폭발 반경을 작게 시작해 점진적으로 넓히고, 실험을 즉시 중단할 abort 조건을 미리 정해두는 것이다. 목적은 장애를 만드는 것이 아니라 이미 잠재해 있던 결함(타임아웃 미설정, 재시도 폭주, 순환 의존, 잘못된 폴백)을 통제된 시간에 드러내는 데 있다.

분산 시스템의 실제 장애는 개별 컴포넌트보다 그 사이의 타임아웃·재시도·폴백 조합에서 나오고, 이런 상호작용은 단위 테스트로 절대 잡히지 않는다.

코드 · 수식

# 카오스 엔지니어링·장애 주입 설계 — 정상 상태를 정의하고, 장애(지연 주입)를 걸어 가설이 깨지는지 관찰한다.
# 폭발 반경을 작게 시작하고, abort 조건을 넘으면 즉시 실험을 중단한다.

import random

random.seed(5)

def call_dependency(latency_ms, fail_rate=0.0):
    """외부 의존(RPC/DB) 호출을 흉내: 지연과 실패율을 파라미터로 받음"""
    ok = random.random() > fail_rate
    return ok, latency_ms + random.uniform(-2, 2)

def measure_steady_state(n_calls, injected_latency_ms=0, injected_fail_rate=0.0):
    latencies, errors = [], 0
    for _ in range(n_calls):
        ok, lat = call_dependency(10 + injected_latency_ms, injected_fail_rate)
        latencies.append(lat)
        if not ok:
            errors += 1
    error_rate = errors / n_calls
    avg_latency = sum(latencies) / len(latencies)
    return avg_latency, error_rate

# 1. 정상 상태(steady state) 정의: 평균 지연 < 20ms, 에러율 < 1%
baseline_latency, baseline_error = measure_steady_state(200)
print(f"[정상 상태] 평균 지연 {baseline_latency:.1f}ms, 에러율 {baseline_error*100:.1f}%")

# 2. 가설: "RPC 노드에 100ms 지연이 추가돼도 평균 지연은 150ms 미만, 에러율은 5% 미만이다"
def run_experiment(injected_latency_ms, injected_fail_rate, blast_radius_calls):
    ABORT_ERROR_RATE = 0.20  # 폭발 반경을 넘는 피해가 감지되면 즉시 중단
    latency, error_rate = measure_steady_state(
        blast_radius_calls, injected_latency_ms, injected_fail_rate
    )
    aborted = error_rate > ABORT_ERROR_RATE
    return latency, error_rate, aborted

for label, inj_latency, inj_fail in [
    ("작은 폭발 반경: RPC 지연 +100ms", 100, 0.02),
    ("의존 서비스 오류 응답 20%", 0, 0.20),
]:
    latency, error_rate, aborted = run_experiment(inj_latency, inj_fail, blast_radius_calls=50)
    hypothesis_holds = latency < 150 and error_rate < 0.05
    status = "ABORT (폭발 반경 초과)" if aborted else (
        "가설 유지" if hypothesis_holds else "가설 깨짐 -> 결함 발견"
    )
    print(f"[{label}] 지연 {latency:.1f}ms, 에러율 {error_rate*100:.1f}% -> {status}")

연습

스테이징에서 외부 의존 하나(RPC 노드나 DB)에 인위적 지연과 간헐적 오류를 주입하고 에러율과 지연 지표 변화를 기록한 뒤, 타임아웃과 재시도 정책을 고쳐 같은 실험을 반복해 개선을 수치로 확인하라.

실무 · Verex 연결

예측시장 서비스는 체인 RPC, 오라클, 인덱서에 동시에 의존하므로, RPC 지연이나 오라클 응답 지연이 정산 파이프라인 전체를 멈추는지 미리 실험해 두면 실제 운영 리스크를 크게 줄일 수 있다.

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

← 49. 용량 계획·SLO와 에러 예산51. [복습] 성능 예산 문서 쓰기 →