Skip to content

บทที่ 4 — Reliability และ Resilience

← บทที่ 3 | สารบัญ | บทที่ 5 →


ก่อนอ่าน — ต้องรู้อะไรมาก่อน?

บทนี้ต่อจาก บทที่ 1-3 — ควรเข้าใจ:

  • Sync vs Async (บทที่ 3)
  • Replication, Multi-region (บทที่ 1-2)
  • Queue, Pub-Sub (บทที่ 3)
  • คำว่า "fail", "downtime", "recovery"

หลังจบบท คุณจะ:

  • ออกแบบ retry / timeout / circuit breaker ที่ถูก
  • เข้าใจ idempotency + at-least-once delivery
  • กำหนด SLI (Service Level Indicator — ตัวชี้วัด เช่น % availability), SLO (Service Level Objective — เป้าภายในของทีม), SLA (Service Level Agreement — สัญญากับลูกค้า มีบทลงโทษถ้าไม่ถึง) + error budget (งบความผิดพลาดที่ยอมให้เกิดได้)
  • จัดการ disaster + chaos engineering

1. ปรัชญา — "Things will fail. Design for failure."

คำแปล: "ทุกอย่างพัง — ออกแบบให้พร้อมพัง" (reliability = รี-ไล-อะ-บิ-ลิ-ตี้ คือความน่าเชื่อถือของระบบ)

ในระบบเล็ก ๆ — failure เป็น "exception"
ในระบบใหญ่ — failure เป็น "norm"

1.1 ความจริงที่ engineer มักลืม

- Hard disk fail rate: ประมาณไม่กี่ % ต่อปี ขึ้นกับรุ่น/อายุ
  (Backblaze = บริษัท backup ที่เปิดเผยสถิติ disk failure รายปีให้สาธารณะ. Backblaze Drive Stats Q1 2024 รายงาน annualized failure rate (AFR) ~1.4% สำหรับ HDD แบบ mix และ ~0.65% สำหรับ SSD — ตัวเลขล่าสุดที่ blog ของ Backblaze)
  *(SSD/NVMe มี failure mode ต่างจาก HDD: SSD "ค่อย ๆ สึก" จาก P/E cycles ตามจำนวน write ไม่ใช่ mechanical fail แบบสุ่ม — NVMe เปลี่ยน profile อีกชั้น ไม่ควรเหมารวม)*
- Network partition เกิดขึ้นเป็นประจำใน data center ใหญ่ (ความถี่ที่แท้จริงต่างกันตามผู้ให้บริการ — Google Jupiter, Microsoft, AWS ต่างเคยรายงาน partition หลายระดับ)
- Bug ใน code: หลีกเลี่ยงไม่ได้
- Configuration mistake: เกิดบ่อยกว่าที่คิด
- Cloud provider outage: AWS us-east-1 ดาวน์ปีละหลายครั้ง
- DDoS attack: ทุกระบบเสี่ยง

Goal: เมื่อ failure เกิด — degrade gracefully + recover automatically, ไม่ใช่ "crash + alert at 3 AM"

1.2 Fallacies of Distributed Computing — 8 ข้อ

ทีม Sun Microsystems รวบรวมไว้แบบค่อย ๆ ต่อยอด — Bill Joy + Tom Lyon (~1991, สี่ข้อแรก), Peter Deutsch (~1994, อีกสามข้อ), James Gosling (~1997, ข้อ 8) — engineer ใหม่ assume สิ่งเหล่านี้ ผิดทั้งหมด (ดู บทที่ 0 distributed-systems สำหรับประวัติเต็ม):

1. The network is reliable        ← FALSE — packet drop เกิดเสมอ
2. Latency is zero                 ← FALSE — มี latency เสมอ
3. Bandwidth is infinite           ← FALSE — bandwidth จำกัด
4. The network is secure           ← FALSE — ทุก hop เสี่ยง
5. Topology doesn't change         ← FALSE — server มา/ไป ตลอด
6. There is one administrator      ← FALSE — หลายคน, หลายทีม
7. Transport cost is zero          ← FALSE — egress แพง
8. The network is homogeneous      ← FALSE — มี firewall, NAT, proxy

Plan for all to be FALSE


2. Failure Modes — รู้จักศัตรู

2.1 Crash Failure

Service หยุดตอบ — process ตาย

✅ ดี: ตรวจจับง่าย (health check fail)
✅ Recovery: restart

2.2 Performance Failure ⭐ ร้ายแรงสุด

Service ช้า แต่ยังตอบ

❌ ยากตรวจจับ — "ช้าหรือเปล่า? หรือแค่ busy?"
❌ บ่อยครั้งร้ายแรงกว่า crash
   เพราะ thread block + resource exhausted + cascade

Insight: "Slow is the new down" — สำนวนอเมริกัน "X is the new Y" หมายถึง "X = ของใหม่ที่มาแทน Y" → แปลว่า "ช้า = ตายแบบใหม่" คือ service ช้ามีผลร้ายแรงพอ ๆ กับ service ตาย เพราะระบบไม่รู้จะ failover (health check บอกว่ายัง up อยู่)

2.3 Byzantine Failure

Byzantine (อ่าน "ไบแซนไทน์") = ความล้มเหลวแบบ "โกหก" — service ไม่ได้ตายเฉย ๆ แต่ยังตอบอยู่ ทว่าตอบ "ค่าผิด" ออกมา (ตรวจจับยากที่สุด เพราะดูเหมือนทำงานปกติ) ชื่อมาจากปัญหาคลาสสิก "Byzantine Generals" (ปัญหาทหารไบแซนไทน์ — โจทย์ CS คลาสสิกปี 1982 ของ Lamport/Shostak/Pease ดู บทที่ 0 distributed-systems สำหรับคำอธิบายเต็ม)

Service return ค่า "ผิด" / "corrupted"

❌ Rare ใน well-designed system
❌ Hard to handle — ต้อง checksum, multi-source verification

2.4 Network Partition

Server ติดต่อกันไม่ได้
"Split brain" — แต่ละฝั่งคิดว่าอีกฝั่งตาย

CAP theorem in action — เลือก C หรือ A

3. Timeout — Always Set Timeout!

กฎข้อแรกของ reliability — ทุก network call ต้องมี timeout เสมอ เพราะถ้าไม่ตั้ง dependency ที่ช้าเพียงตัวเดียวจะทำให้ thread ค้างรอจนหมด แล้วทั้งแอปล่ม (cascade) ส่วนนี้บอกค่า timeout ที่เหมาะกับงานแต่ละแบบและวิธี implement ในหลายภาษา:

3.1 ปัญหา — Default Infinite Timeout

❌ ไม่ set timeout:
- 1 slow dependency → cascade failure
- ทุก thread stuck waiting
- App ตายในที่สุด (resource exhausted)

3.2 ทางแก้ — Explicit Timeout

Recommendation (rough):
- DB query: 1-5 seconds
- HTTP call to internal service: 3-10 seconds
- HTTP call to external service: 5-15 seconds (default ของ Stripe/AWS SDK ยุคใหม่ — ใช้คู่กับ retry+backoff); 10-30 seconds เฉพาะ batch/slow API ที่รู้ว่าช้าจริง
- User-facing endpoint: < 30 seconds total

3.3 Implementation

typescript
// Axios with timeout
const response = await axios.get('/api/data', { timeout: 5000 });

// Fetch with AbortController
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 5000);

try {
    const res = await fetch('/api/data', { signal: controller.signal });
    clearTimeout(timeoutId);
} catch (err) {
    if (err.name === 'AbortError') {
        // timeout
    }
}
java
// Spring WebClient
WebClient client = WebClient.builder()
    .baseUrl("https://api.example.com")
    .build();

Mono<Data> result = client.get()
    .uri("/data")
    .retrieve()
    .bodyToMono(Data.class)
    .timeout(Duration.ofSeconds(5));

กฎทอง #1: NEVER call external service without explicit timeout


4. Retry with Exponential Backoff

ความล้มเหลวชั่วคราว (timeout, 503) มักหายเองถ้าลองใหม่ แต่ retry แบบ naive (ทุก client ยิงพร้อมกันทันที) จะถล่ม service ที่กำลังจะฟื้น — exponential backoff + jitter แก้ด้วยการเว้นนานขึ้นเรื่อย ๆ บวกสุ่มเล็กน้อยเพื่อกระจายเวลา retry ของ client ออกจากกัน:

4.1 ปัญหา — Naive Retry

Service ตาย → retry ทันที → ทุก client retry พร้อมกัน
→ "Thundering herd" → overload service มากกว่าเดิม

4.2 Solution — Exponential Backoff + Jitter

Pattern:
- Wait ระหว่าง retries
- Increase wait แบบ exponential
- Add jitter (random delay) — กระจาย client
- Limit max attempts

4.3 Implementation

typescript
interface RetryConfig {
    maxAttempts?: number;
    baseDelay?: number;
    maxDelay?: number;
    jitter?: boolean;
}

async function retry<T>(
    fn: () => Promise<T>,
    config: RetryConfig = {}
): Promise<T> {
    const { 
        maxAttempts = 3, 
        baseDelay = 100, 
        maxDelay = 30000, 
        jitter = true 
    } = config;
    
    let lastErr: any;
    
    for (let i = 0; i < maxAttempts; i++) {
        try {
            return await fn();   // ลองเรียก fn() — ถ้าสำเร็จ return ทันที
        } catch (err) {
            lastErr = err;
            
            // ถ้าเป็น client error (4xx) — ไม่ retry เพราะ retry ไปก็ fail เหมือนเดิม
            if (isClientError(err)) throw err;
            
            // Exponential backoff:
            //   Math.pow(2, i) = 2^i (i=0→1, i=1→2, i=2→4, ...) ทำให้รอนานขึ้นเรื่อย ๆ
            //   Math.min(..., maxDelay) = clamp ไม่ให้รอเกิน maxDelay (เช่น 30s)
            let delay = Math.min(baseDelay * Math.pow(2, i), maxDelay);
            
            // เพิ่ม jitter (สุ่มเวลาเล็กน้อย 0-50%) เพื่อกระจาย retry ของ client ออกจากกัน
            // หมายเหตุ: นี่คือ "equal jitter" (delay × 0-50%) — AWS Architecture Blog
            //   (Marc Brooker 2015) เสนอ "full jitter" คือสุ่ม [0, delay] เต็มช่วง
            //   พบว่าให้ผลดีกว่าในการกระจาย load จริง — ดูอ้างอิงท้ายส่วน
            if (jitter) {
                delay += Math.random() * delay * 0.5;
            }
            
            await sleep(delay);   // sleep() = helper รอ delay ms ก่อน loop รอบถัดไป
        }
    }
    
    throw lastErr;
}

📌 Jitter types: "equal jitter" (โค้ดข้างบน) vs "full jitter" (delay = Math.random() * cap) — สำหรับ production แนะนำ full jitter ตามที่ AWS แนะนำ (Exponential Backoff And Jitter — AWS Architecture Blog, 2015)

4.4 เมื่อไหร่ NOT to Retry

4xx Client error (400, 401, 403, 404):
- Won't succeed on retry (it's YOUR fault)
- Don't retry

5xx Server error:
- May recover, retry OK

429 Too Many Requests:
- Server says "back off"
- Retry with longer delay (use Retry-After header)

408 Request Timeout, 503 Service Unavailable:
- Retry-friendly
- Server temporarily busy

4.5 Idempotency Required

Retry safe only ถ้า operation idempotent

GET: safe ✅
PUT: safe ✅ (set X to Y)
DELETE: safe ✅ (delete X)
POST: UNSAFE ❌ (creates new each time)

For POST: ใช้ idempotency key (ดู section ถัดไป)

5. Idempotency — Safe to Retry

5.1 นิยาม

Idempotent = doing same thing N times = doing 1 time

Examples:
- "Set balance to $100"           ✅ idempotent
- "Add $100 to balance"            ❌ not (4 retries = $400 added!)
- "Delete user 42"                  ✅ idempotent
- "Append to log"                   ❌ not

5.2 Idempotency Key Pattern (Stripe)

Client generates UUID per request:

POST /charges
Idempotency-Key: 7e8f9-abc-def-123
{ amount: 100 }

Server:
1. Check if key exists in cache/DB
2. If exists → return cached response (don't process)
3. If new → process + cache result (TTL 24h)

5.3 Implementation

java
@PostMapping("/charges")
public Charge create(
    @RequestHeader("Idempotency-Key") String key,
    @RequestBody ChargeRequest req
) {
    // Check cache
    Optional<Charge> cached = idempotencyService.find(key);
    if (cached.isPresent()) {
        return cached.get();
    }
    
    // Process
    Charge charge = paymentService.charge(req);
    
    // Cache (TTL 24h)
    idempotencyService.store(key, charge, Duration.ofHours(24));
    
    return charge;
}

5.4 Use Cases ที่ใช้กันจริง

- Stripe payment API
- GitHub API
- Square API
- AWS APIs (using ClientRequestToken)
- ทุก payment provider

รายชื่อข้างบนเป็น payment / critical API ที่ "ห้าม double charge เด็ดขาด" — idempotency จึงเป็นข้อบังคับ ไม่ใช่ทางเลือก

Insight: Idempotency = ป้องกัน "double charge" ที่ payment provider กลัวที่สุด


6. Circuit Breaker — กัน Cascade Failure

เมื่อ service ปลายทางช้าหรือล่ม การพยายามเรียกต่อไปทำให้ thread/resource ของฝั่งเราหมด แล้วล่มตามเป็นลูกโซ่ — circuit breaker ทำงานเหมือนเบรกเกอร์ไฟ: เมื่อ fail บ่อยก็ "ตัดวงจร" หยุดเรียกชั่วคราวคืน error ทันที พอครบเวลาค่อยลองทีละครั้ง (half-open) ก่อนกลับสู่ปกติ:

6.1 ปัญหา

Service A calls Service B
B ช้า/ตาย
→ A's threads ติด wait
→ A's resources exhausted
→ A ตาย → C ตาย → cascade

6.2 Solution — Circuit Breaker

Track failure rate ของ B
→ ถ้า failure rate สูง → "OPEN" — หยุดเรียก B
→ Return error ทันที (no actual call)
→ หลัง timeout → "HALF-OPEN" → ลอง 1 call
→ Success → "CLOSED" (resume normal)

6.3 States

6.4 Implementation

typescript
class CircuitBreaker {
    private state: 'closed' | 'open' | 'half-open' = 'closed';
    private failures = 0;
    private nextAttempt = 0;
    
    constructor(
        private threshold = 5,
        private timeoutMs = 30_000
    ) {}
    
    async call<T>(fn: () => Promise<T>): Promise<T> {
        if (this.state === 'open') {
            if (Date.now() < this.nextAttempt) {
                throw new Error('Circuit open');
            }
            this.state = 'half-open';
        }
        
        try {
            const result = await fn();
            this.onSuccess();
            return result;
        } catch (err) {
            this.onFailure();
            throw err;
        }
    }
    
    private onSuccess() {
        this.failures = 0;
        this.state = 'closed';
    }
    
    private onFailure() {
        this.failures++;
        if (this.failures >= this.threshold) {
            this.state = 'open';
            this.nextAttempt = Date.now() + this.timeoutMs;
        }
    }
}

6.5 Libraries

LanguageLibrary
JavaResilience4j ⭐, Hystrix (deprecated)
.NETPolly
Node.jsopossum
Pythonpybreaker
Gogobreaker

6.6 Spring Boot — Resilience4j config

yaml
resilience4j:
  circuitbreaker:
    instances:
      paymentService:
        slidingWindowSize: 10
        failureRateThreshold: 50         # > 50% → open
        waitDurationInOpenState: 30s     # wait 30s before half-open
        permittedNumberOfCallsInHalfOpenState: 3
        minimumNumberOfCalls: 10
java
@CircuitBreaker(name = "paymentService", fallbackMethod = "fallback")
public Payment charge(ChargeRequest req) {
    return stripeClient.charge(req);
}

public Payment fallback(ChargeRequest req, Exception ex) {
    // Queue for retry later
    queue.enqueue(req);
    return Payment.pending();
}

7. Bulkhead — Isolate Resources

คำอ่าน: bulkhead = "บัลค์-เฮด" (ผนังกั้นในเรือ) · hedged request = "เฮดจ์ด-รีเควสต์" (ยิงซ้ำเผื่อ — ดูส่วนถัดไป)

ชื่อ bulkhead มาจากผนังกั้นห้องในเรือเดินสมุทร — ถ้ารูรั่วถูกจำกัดอยู่ห้องเดียว เรือก็ไม่จม หลักเดียวกันใช้กับซอฟต์แวร์: แยก resource pool ต่อ dependency เพื่อให้ปัญหาของ service หนึ่งไม่ลามไปกินทรัพยากรทั้งหมดจนระบบล่มทั้งก้อน:

7.1 Ship Metaphor

ใน เรือเดินสมุทร:
- 1 รูในตัวเรือ
- ไม่มี bulkhead → ทั้งเรือจม
- มี bulkhead (ผนังกั้น) → น้ำติดในห้องเดียว เรือยังลอย

7.2 Code Analogy

App มี 1 thread pool (100 threads)
1 slow downstream กิน 100 threads
→ ทุก request fail

Solution: separate thread pool per dependency
- 30 threads for Service A
- 30 threads for Service B
- 40 threads for Service C

A ตาย → only 30 threads ติด
B + C ยังทำงาน

7.3 Implementation

typescript
class Bulkhead {
    private queue: Array<() => void> = [];
    private active = 0;
    
    constructor(private maxConcurrent = 10) {}
    
    async run<T>(fn: () => Promise<T>): Promise<T> {
        await this.acquire();
        try {
            return await fn();
        } finally {
            this.release();
        }
    }
    
    private acquire(): Promise<void> {
        return new Promise(resolve => {
            if (this.active < this.maxConcurrent) {
                this.active++;
                resolve();
            } else {
                this.queue.push(() => {
                    this.active++;
                    resolve();
                });
            }
        });
    }
    
    private release() {
        this.active--;
        const next = this.queue.shift();
        if (next) next();
    }
}

// Use
const paymentBulkhead = new Bulkhead(30);
await paymentBulkhead.run(() => paymentService.charge());

8. Combined Pattern — Timeout + Retry + Circuit Breaker + Bulkhead

ในจริง — รวมทุก pattern เข้าด้วยกัน:

typescript
async function safeCall<T>(
    fn: () => Promise<T>,
    config: {
        timeoutMs: number;
        retries: number;
        circuit: CircuitBreaker;
        bulkhead: Bulkhead;
    }
): Promise<T> {
    return config.bulkhead.run(async () => {
        return config.circuit.call(async () => {
            return retry(
                () => withTimeout(fn(), config.timeoutMs),
                { maxAttempts: config.retries }
            );
        });
    });
}

Defense in depth — หลายชั้นกัน


9. Failover — Switch to Backup

failover คือการสลับไปใช้ตัวสำรองเมื่อตัวหลักล่ม — มีสองรูปแบบ: active-passive (สำรองรอ standby แล้ว promote เมื่อล่ม) กับ active-active (ทุกตัวรับ traffic อยู่แล้ว ตัวหนึ่งล่มก็ไม่ต้องสลับ) ส่วนนี้เทียบทั้งสองและยกตัวอย่าง DB failover ด้วย Patroni:

9.1 Active-Passive

Primary serves traffic (100%)
Backup standby, syncing data
On failure: promote backup → manual หรือ auto

9.2 Active-Active

Both serve traffic (load balanced)
On 1 failure: other handles all traffic
No "failover" — already serving

9.3 Database Failover Example — Patroni

PostgreSQL with Patroni:

[Primary] ←──streaming replication──→ [Replica 1] ──→ [Replica 2]

Patroni monitors via DCS (Distributed Config Store เช่น etcd/Consul/ZooKeeper):
- Primary down → promote replica ที่ LSN สูงสุด
  (LSN = Log Sequence Number = ตำแหน่งใน WAL ที่บอกว่า replica apply ไปถึงไหนแล้ว)
- Update connection string ผ่าน DCS / HAProxy / DNS
- Failover time ขึ้นกับ ttl, loop_wait, retry_timeout (default รวมแล้วประมาณหลัก 10s)

⚠️ Senior caveats ที่ตัวอย่างย่อข้างบนตัดทิ้ง:

  1. Patroni default ใช้ async streaming replication ไม่ใช่ sync — ถ้าอยาก sync จริง ๆ ต้องตั้ง synchronous_standby_names ใน PostgreSQL และยอมแลกกับ write latency ที่เพิ่มขึ้น (write ต้องรอ replica acknowledge)
  2. Split-brain protection ต้องอาศัย DCS + watchdog (เช่น softdog) + fencing — ถ้า primary ยังมี client เขียนอยู่แต่ DCS คิดว่า dead จะเกิด split-brain ได้
  3. Auto failback ไม่ทำให้ทันที — primary เก่าที่กลับมาต้อง re-init จาก new primary (pg_rewind หรือ basebackup) ขั้นตอนนี้มัก manual
  4. เวลา 10-30 วินาที เป็น "best case" ของ default config — ขึ้นกับ DCS health, network และ application-level connection pool ด้วย

(อ่านต่อ: Patroni docs — Configuration, DCS, Watchdog sections)

9.4 Multi-Region Failover

Region A (primary) ←─async──→ Region B (standby)
   100% traffic                    0% traffic

Region A down:
- DNS update → Region B
- Re-route traffic
- Promote B as primary

RPO: data since last replication (usually 1s lag)
RTO: time to failover (5-15 min typical)

10. Health Check — รู้ว่าใครพร้อม

10.1 3 Types of Health Check

1. Liveness — "Am I running?"
   - Process alive
   - Basic — just respond 200
   - If fail → restart container

2. Readiness — "Can I serve traffic?"
   - DB connected
   - Cache reachable
   - Dependencies OK
   - If fail → LB ลบจาก rotation (ไม่ restart)

3. Startup — "Done starting up?"
   - สำหรับ slow-start apps (load model, warm cache)
   - K8s won't kill ระหว่าง startup

10.2 Spring Boot — Actuator

http
GET /actuator/health
{
    "status": "UP",
    "components": {
        "db": { "status": "UP" },
        "redis": { "status": "UP" },
        "diskSpace": { "status": "UP", "details": { "free": "100GB" } }
    }
}

10.3 Kubernetes Probe Config

yaml
livenessProbe:
    httpGet:
        path: /actuator/health/liveness
        port: 8080
    initialDelaySeconds: 30
    periodSeconds: 10
    failureThreshold: 3

readinessProbe:
    httpGet:
        path: /actuator/health/readiness
        port: 8080
    periodSeconds: 5
    failureThreshold: 1

กฎ: liveness ตรวจแค่ "process alive" — readiness ตรวจ "ready to serve"
ผิดบ่อย: ใช้ liveness check DB → DB ช้า → K8s restart pod เปล่า ๆ


11. Graceful Shutdown — Clean Exit

ทุกครั้งที่ deploy หรือ scale down แอปจะได้รับสัญญาณ SIGTERM — ถ้าตายทันทีจะทำ request ที่ค้างอยู่หาย graceful shutdown แก้ด้วยการหยุดรับ request ใหม่ → รอ request ที่ค้างเสร็จ → ปิด connection → ค่อย exit ทำให้ deploy โดยไม่มี request ตกหล่น:

11.1 Pattern

App receives SIGTERM (deploy, K8s scaling):

1. Stop accepting new requests
2. Drain in-flight requests (wait up to N seconds)
3. Close connections (DB, cache, queue)
4. Exit cleanly

→ No request lost
→ K8s default grace period: 30 seconds

11.2 Implementation

typescript
// Node.js
import express from 'express';

const app = express();
const server = app.listen(3000);

process.on('SIGTERM', async () => {
    console.log('SIGTERM received, shutting down gracefully');
    
    // 1. Stop new connections
    server.close(() => {
        console.log('HTTP server closed');
    });
    
    // 2. Close dependencies
    await db.close();
    await redis.quit();
    await queue.disconnect();
    
    // 3. Exit
    process.exit(0);
});
yaml
# Spring Boot — application.yml
server:
    shutdown: graceful
spring:
    lifecycle:
        timeout-per-shutdown-phase: 30s
yaml
# K8s — pod spec
spec:
  terminationGracePeriodSeconds: 60   # ให้เวลา drain

12. Backpressure — Slow Down Producer

ถ้า producer ผลิตเร็วกว่า consumer ประมวลผล queue จะโตไม่หยุดจน OOM — backpressure คือกลไกส่งสัญญาณ "ช้าลงหน่อย" กลับไปหา producer ทำได้หลายวิธี: bounded queue (บล็อกเมื่อเต็ม), drop strategy หรือ throttle ส่วนนี้อธิบายแต่ละแบบพร้อมตัวอย่าง:

12.1 ปัญหา

Producer faster than consumer
→ Queue grows unbounded
→ Eventually: OOM, dropped messages, system crash

12.2 Backpressure = Signal "Slow Down" to Producer

12.3 Methods

1. Bounded queue
   - Block producer when queue full
   - Simple, effective

2. Drop strategy
   - Drop oldest (LIFO)
   - Drop newest (FIFO)
   - Drop random
   - Sample (every Nth — for metrics)

3. Throttle producer
   - Token bucket
   - Adaptive rate (TCP-like)

12.4 Bounded Queue Implementation

⚠️ ตัวอย่าง backpressure แบบ busy-wait ที่เคยมีตรงนี้รอ rewrite — โค้ดเดิมเป็น while (queue.length >= maxSize) await sleep(10) ซึ่ง ไม่ใช่ backpressure จริง: มันเป็นแค่ poll-loop ที่กิน CPU/event loop และไม่ส่งสัญญาณกลับไปให้ producer ช้าลง อาจทำให้ระบบ production พังในรูปแบบที่หาไม่เจอ

Backpressure จริง ๆ ทำงานยังไง (เชิงคุณภาพ):

  1. Reactive Streams request(n) — consumer บอก upstream ว่ารับได้กี่ item ถ้าไม่ขอ upstream ก็ไม่ส่ง (pull-based)
  2. Promise-based wait queuepush() คืน Promise ที่ resolve ตอน pop() ทำให้มีที่ว่าง (ไม่ poll)
  3. Semaphore / counting lock — ใช้ primitive ของ concurrency lib (เช่น async-sema ใน Node, Semaphore ใน Java)

ใน production ให้ใช้ library ที่ทำ backpressure ถูกต้องอยู่แล้ว:

  • Node/TS: RxJS (onBackpressureBuffer, onBackpressureDrop), หรือ Node stream ที่มี highWaterMark
  • Java: Project Reactor / RxJava (Flux/Flowable มี onBackpressureBuffer, onBackpressureLatest)
  • JVM general: Akka Streams
  • Kafka consumer: ใช้ max.poll.records + manual commit เพื่อ control rate

อย่า roll your own queue ใน production — backpressure ที่ถูกต้องต้องคิดทั้งฝั่ง producer/consumer และ error path ครบ


13. SLI / SLO / SLA — Quantify Reliability

"ระบบเชื่อถือได้แค่ไหน" ต้องวัดเป็นตัวเลข ไม่ใช่ความรู้สึก — SLI คือสิ่งที่วัด (เช่น % availability), SLO คือเป้าภายใน (เช่น 99.9%), SLA คือสัญญากับลูกค้า (มีบทลงโทษถ้าไม่ถึง) ส่วนนี้แยกสามคำที่สับสนกันบ่อยและให้ตัวเลข SLO ที่เหมาะกับแต่ละประเภทแอป:

13.1 Definitions

SLI (Service Level Indicator):
- "What we measure"
- e.g., availability = success / total × 100

SLO (Service Level Objective):
- "Internal target"
- e.g., 99.9% availability over 30 days

SLA (Service Level Agreement):
- "Customer contract" (legal)
- e.g., 99.5% — refund if not met

13.2 Rule of Thumb

SLA < SLO (buffer)
- SLO = "team's target"
- SLA = "what we promise customer" (less aggressive)

13.3 Common SLO Targets

App TypeSLODowntime/month
Public web app99.9%43 min
Internal API99.5%3.6 hours
Background job95%1.5 days
Banking core99.99%4 min
Status page (ironic)99%7 hours

14. Error Budget — Reliability ≠ "Always Up"

Error budget = 100% - SLO

SLO 99.9% → budget 0.1% = 43 min/month downtime "allowed"

Use budget for:
- Deploy (controlled risk)
- Maintenance
- Real incidents

If budget exhausted (downtime > 43 min):
- Freeze feature deploys
- Focus on reliability investment
- Postmortem + remediation

Insight: 100% reliability ไม่มีในโลก — มี budget = engineer ตัดสินใจ risk ได้

ดู Observability บทที่ 6 สำหรับลึก


15. Chaos Engineering — Find Weakness Intentionally

แทนที่จะรอให้ระบบพังเองตอน production แล้วค่อยรู้จุดอ่อน chaos engineering จงใจ "ฉีดความล้มเหลว" ในสภาพควบคุม (kill server, ตัด network) เพื่อพิสูจน์ว่าระบบทนได้จริงตามที่ออกแบบ — Netflix บุกเบิกด้วย Chaos Monkey ส่วนนี้สอนหลักการและวิธีทำอย่างปลอดภัย:

15.1 หลักการ

Netflix Chaos Monkey:
- Randomly kill production servers
- Force teams to design for failure
- "หา weakness ก่อนมัน หามาเอง"

15.2 Game Day

Planned exercise:
- Inject failure (kill DB, partition network)
- Test response process
- Find unknown unknowns
- Practice runbook execution

Frequency: quarterly ขึ้นไป

15.3 Tools

Toolจุดเด่น
Chaos Monkey (Netflix)Kill EC2 instances
Chaos MeshKubernetes-native
LitmusChaosK8s, CNCF project
GremlinCommercial, broad scenarios
AWS Fault Injection SimulatorAWS-native
PumbaDocker chaos

15.4 Scenarios

- Kill random pod / instance
- Drop network packets (10-50%)
- Increase CPU/memory pressure
- Simulate disk full
- Delay responses (add 500ms latency)
- Region failover drill
- DNS resolution fail
- Certificate expiration

16. Graceful Degradation — Fail Partially, Not Totally

แทนที่ระบบจะ "ล่มทั้งหมด" เมื่อบางส่วนพัง graceful degradation ทำให้มัน "ใช้งานได้บางส่วน" — เช่น search ล่มก็ปิดปุ่ม search แต่ feed ยังดูได้, ML รวนก็ใช้ feed เรียงตามเวลาแทน เป้าหมายคือผู้ใช้รู้สึกว่า "ช้า/ฟีเจอร์น้อยลง" ไม่ใช่ "ใช้ไม่ได้เลย":

16.1 หลักการ

เมื่อบางส่วนของระบบ fail — user ยังใช้งานอะไรได้?

16.2 ตัวอย่าง — Twitter Timeline

Normal:
- Database → tweets
- Search → results
- ML → recommendations
- CDN → images

Degraded scenarios:
- Database slow → show cached old tweets (5 min stale)
- Search down → disable search button + message
- Image service down → show text-only post
- ML recommendation down → show chronological feed

→ User experience degrades, ไม่ใช่ catastrophic failure

16.3 Patterns

Feature flags:
- Disable heavy feature เมื่อ load สูง
- "Black Friday mode" — disable wishlist, ratings

Fallback:
- ML rec fail → use rule-based recommendation
- Cache fail → query DB (slower but works)
- External API fail → use stale data + warn

Progressive enhancement:
- Page works without JS (basic features)
- JS adds interactivity (enhanced)
- App usable even when API slow

17. Disaster Recovery (DR)

disaster recovery คือแผนรับมือเมื่อเกิดหายนะใหญ่ (region ล่ม, ข้อมูลเสียหาย) วัดด้วยสองตัวเลข: RPO (ยอมเสียข้อมูลได้กี่ชั่วโมง) และ RTO (ยอม down ได้กี่ชั่วโมง) — ยิ่ง RPO/RTO ต่ำยิ่งแพง ส่วนนี้เทียบ strategy 4 ระดับ (backup, pilot light, warm standby, active-active) และย้ำว่าต้อง "ทดสอบ restore" จริง:

17.1 Recovery Objectives — RPO + RTO

RPO (Recovery Point Objective):
- Max acceptable data loss
- "เรา accept loss 1 hour of data" → RPO = 1h

RTO (Recovery Time Objective):
- Max acceptable downtime
- "เรา accept down 4 hours" → RTO = 4h

17.2 Strategy Tiers — Cost vs Recovery

StrategyRPORTOCost
Backup + Restore24h1-4hLowest
Pilot Light1h30 minLow-medium
Warm Standbyminutes5-15 minMedium
Active-Active0-seconds0 (auto)Highest

17.3 Tier Details

Backup + Restore:
- Daily backup to S3
- Restore on disaster
- Cheap แต่ช้า

Pilot Light:
- Critical infra always running in DR region
- Data replicating
- Scale up other components on DR event

Warm Standby:
- Full env in DR region (smaller scale)
- Data sync
- Promote on DR

Active-Active (Multi-Region):
- Both regions serve traffic
- No "failover" — already serving
- RPO: 0 (sync) หรือ seconds (async)
- RTO: 0 (auto-failover)

17.4 DR Practice

✅ Regular DR drill (quarterly)
✅ Test restoration (ไม่ใช่แค่ backup!)
✅ Document runbook
✅ Multiple offsite backups
✅ Encrypt backups
✅ Off-cloud copy (ransomware protection)
✅ Test failover automation

GitLab incident 2017: มี backup 5 ระบบ — ไม่มี backup ไหน restore ได้! → lesson: test restoration


18. Multi-Region Considerations

การกระจายระบบหลาย region ให้ทั้ง latency ต่ำสำหรับผู้ใช้ทั่วโลก, DR, compliance และ availability สูง — แต่แลกมากับความซับซ้อน (data sync, consistency ข้าม region, ต้นทุน) ส่วนนี้ชั่งน้ำหนักว่าเมื่อไหร่คุ้มที่จะทำและ challenge ที่ต้องเตรียมรับมือ:

18.1 ทำไม Multi-Region

✅ Lower latency for global users
✅ Disaster recovery
✅ Compliance (data residency — EU data in EU)
✅ Higher availability (99.99% เป็นไปได้)

18.2 Challenges

❌ Data sync (CAP theorem)
❌ Higher cost (2-3x infrastructure)
❌ Complex operations
❌ Network cost (egress ระหว่าง region)
❌ Latency ระหว่าง region (US-EU ~100ms)

18.3 Data Strategy

1. Single primary (other regions read-only)
   - All writes → 1 region
   - Reads served local
   - Simple, but writes ช้าสำหรับ user ไกล

2. Multi-master (active-active)
   - Writes anywhere
   - Sync ระหว่าง region (async)
   - Conflict resolution needed
   - Complex แต่ low latency

3. Sharded by region
   - User from Asia → Asia DB
   - User from EU → EU DB
   - No cross-region for user data
   - GDPR friendly

19. Monitoring + Alerting

19.1 ต้อง monitor อะไรบ้าง

✅ Health metric — uptime, error rate, latency
✅ Resource — CPU, memory, disk, network
✅ Business — orders/sec, signup/min, revenue
✅ Custom — queue depth, cache hit rate

19.2 Alert เมื่อไหร่

- Error rate > threshold
- Latency p99 > SLO target
- Resource > 80%
- Queue growing unbounded
- Anomaly (sudden change)

19.3 Alert ที่ดี

✅ Actionable — engineer รู้ทำอะไร
✅ Urgent — ต้องตอบเลย (ไม่ใช่ "informational")
✅ Specific — รู้ว่า component ไหนพัง
✅ มี runbook link

❌ Alert spam — ignore ในที่สุด
❌ False positive บ่อย — alert fatigue

ดู Observability book สำหรับลึก

19.4 Observability ลึก — OpenTelemetry + 3 pillars

text
Observability ≠ Monitoring
- Monitoring: "ระบบยังทำงานไหม" (รู้สิ่งที่ตั้งเป็น metric ไว้ล่วงหน้า)
- Observability: "ทำไมระบบทำงานแบบนี้" (ตอบ unknown unknowns ได้)

3 Pillars (จำง่าย: LMT):
1. Logs   — event records (structured > unstructured)
2. Metrics — time-series numbers (low cardinality)
3. Traces — request flow ข้าม services

OpenTelemetry (CNCF, Graduated 2024):
- Vendor-neutral observability framework
- Replaces OpenTracing + OpenCensus
- Native support: AWS X-Ray, Datadog, Honeycomb, Jaeger, Tempo, Grafana
- Auto-instrumentation libraries: Java, Python, Go, Node.js, Ruby, .NET

Structured Logging (best practice):
- JSON format → queryable in Elasticsearch / Loki / DataDog
- Include: timestamp, level, service, trace_id, span_id, message, context
- Never: PII in logs (PCI/GDPR compliance)

Trace Sampling:
- Head sampling — decide at request start (cheap, biased)
- Tail sampling — buffer all, decide at end (expensive, better)
- Production: 1% baseline + 100% errors + 100% slow

Cardinality Explosion (Prometheus pitfall):
- ห้าม use high-cardinality labels (user_id, session_id) ใน metrics
- 1M users × 10 metrics = 10M time series → Prometheus OOM
- Use logs/traces for high-cardinality data

Prometheus histograms — update 2026:
- ปัญหา histogram แบบเดิม (classic): ต้อง pre-define bucket boundaries ซึ่งเลือกผิดทำให้ p99 ไม่แม่น และ label cardinality สูง
- ตั้งแต่ Prometheus 2.40 (พ.ย. 2022) มี "native histograms" (sparse, exponential buckets) ที่ปรับเองตามข้อมูล แม่นกว่าและประหยัด memory — GA ใน Prometheus 3.x
- ของใหม่: ใช้ native histograms กับ workload ที่ละเอียดต่อ latency (เช่น p99.9) แทน classic ที่จำกัด bucket

📚 เรียนต่อ: Honeycomb's "Observability Engineering" (Charity Majors, free chapters), OpenTelemetry docs


20. Reliability Patterns Summary

เรียน pattern เรื่อง reliability มาหลายตัว ตารางนี้สรุปทั้งหมดในที่เดียว — แต่ละ pattern แก้ปัญหาคนละมุม (timeout กันรอค้าง, circuit breaker กัน cascade, bulkhead แยกความเสียหาย ฯลฯ) ในระบบจริงมักใช้หลาย pattern ซ้อนกัน ใช้เป็น checklist ตอนออกแบบ:

PatternPurpose
TimeoutPrevent indefinite waiting
Retry + BackoffRecover from transient failure
IdempotencySafe to retry
Circuit BreakerStop calling failing service
BulkheadIsolate failure to subset
FallbackUse cached/default when fail
Throttle / Rate LimitProtect from overload
Health CheckDetect + remove unhealthy
Graceful ShutdownClean exit on deploy
BackpressureSlow producer when consumer behind
ReplicationSurvive single-node failure
FailoverSwitch to backup
DRMulti-region disaster recovery
Chaos EngineeringFind weakness intentionally

21. Real Example — Resilient Payment Flow

มาดูว่า pattern ทั้งหมดประกอบกันในโค้ดจริงยังไง — payment flow ที่ทนทานซ้อนหลาย pattern เข้าด้วยกัน: idempotency (กัน double charge), bulkhead, circuit breaker, retry และ timeout ตัวอย่างนี้แสดงว่าระบบที่ critical จริงต้องใช้ defense หลายชั้น:

⚠️ โค้ดด้านล่างเป็น pseudocode สไตล์ TypeScript เพื่อสื่อ pattern เท่านั้น ไม่ใช่โค้ดที่ copy ไปรันได้จริง — โค้ดเดิมเคยใส่ @Service ซึ่งเป็น Java/Spring annotation (ไม่ใช่ TS) ปนเข้ามา ถ้าจะใช้ใน NestJS ให้เปลี่ยนเป็น @Injectable() จาก @nestjs/common; ถ้าจะใช้ Spring Boot จริง ดูตัวอย่าง Resilience4j ที่ section ก่อนหน้า (Circuit Breaker / Bulkhead)

typescript
// NestJS style: ใช้ @Injectable() จาก @nestjs/common
// (Spring/Java style: @Service จาก org.springframework.stereotype)
@Injectable()
export class PaymentService {
    private paymentCircuit = new CircuitBreaker({
        threshold: 5,
        timeoutMs: 30_000
    });
    
    private bulkhead = new Bulkhead(20);  // max 20 concurrent calls
    
    async charge(req: ChargeRequest): Promise<Payment> {
        // 1. Idempotency check
        const cached = await this.idempotencyStore.find(req.idempotencyKey);
        if (cached) return cached;
        
        // 2. Process with reliability patterns
        const payment = await this.bulkhead.run(() =>
            this.paymentCircuit.call(() =>
                retry(
                    () => this.callStripeWithTimeout(req),
                    { maxAttempts: 3, baseDelay: 200 }
                )
            )
        );
        
        // 3. Cache result (24h)
        await this.idempotencyStore.store(req.idempotencyKey, payment, '24h');
        
        // 4. Audit log
        await this.audit.record(payment);
        
        return payment;
    }
    
    private async callStripeWithTimeout(req: ChargeRequest): Promise<Payment> {
        return withTimeout(
            this.stripeClient.create(req),
            10_000  // 10 sec timeout
        );
    }
}

Stack of patterns:

  1. Idempotency key (prevent double charge)
  2. Bulkhead (isolate Stripe calls)
  3. Circuit breaker (stop on cascading fail)
  4. Retry with backoff (handle transient)
  5. Timeout (prevent infinite wait)
  6. Audit log (compliance + forensic)

22. Capacity Planning for Failure — N+M Redundancy

ระบบที่ทนการล่มต้องมี capacity เผื่อไว้ — N+M redundancy หมายถึง "ต้องการ N เครื่อง แต่เตรียม N+M" เพื่อให้ M เครื่องล่มได้โดยยังให้บริการได้ ส่วนนี้สอนวิธีคำนวณ capacity ที่รวม buffer สำหรับ failure (ไม่ใช่แค่ peak load):

N+1 redundancy:
- Need 1 → have 2
- 1 fails → still works

N+2:
- Need 3 → have 5
- 2 can fail → still works

Calculate:
- Peak load → required capacity
- Add redundancy buffer
- Plan for region failure (spare in another region)

Example:
- App needs 10 servers at peak
- Plan: 15 (N+5)
- 5 can fail → still serving

Cost vs reliability trade-off — เลือกตาม business value


23. Cost of Outage — Why Reliability Matters $$$

ตัวเลขจริงในอุตสาหกรรม:

1 minute downtime cost:
- Amazon retail: ~$220K/min ($1B/year หาย)
- Stripe: ~$10K/min
- Average B2B SaaS: $5-50K/min
- Trading firms: $millions/min

Calculate:
- Revenue per minute
- × downtime minutes
- + customer churn (10% leave permanently)
- + reputation damage
- + legal (if SLA breached)
- = full cost

Insight: ใช้ตัวเลขนี้ justify reliability investment ให้ business


24. Reliability Anti-Patterns

รวมความผิดพลาดเรื่อง reliability ที่เจอบ่อยและทำให้ระบบเปราะ — ไม่ตั้ง timeout, retry ไม่จำกัด, sync ทุกอย่าง, shared fate (ทุกอย่างล่มพร้อมกัน) แต่ละข้อมาคู่กับวิธีแก้ ดูไว้เพื่อหลีกเลี่ยงตั้งแต่ออกแบบ:

24.1 ❌ No Timeout

Service A รอ B forever → cascade failure

Fix: Always set timeout

24.2 ❌ Unbounded Retry

Fail → retry forever → amplify load on broken service

Fix: Max attempts + backoff + circuit breaker

24.3 ❌ Synchronous Everything

User รอ 10 service calls ติดต่อกัน
1 ช้า → ทั้งหมดช้า

Fix: Async where possible, parallel where applicable

24.4 ❌ Shared Fate

Many features on same server
1 feature crash → kill server → all features down

Fix: Bulkhead / separate services

24.5 ❌ No Graceful Degradation

1 service down → app unusable

Fix: Fallback / progressive enhancement

24.6 ❌ No Monitoring

"Find out from customer ticket"

Fix: Health check + alerting + on-call rotation

24.7 ❌ Manual DR

Disaster → engineer runs runbook manually

Fix: Automate (PagerDuty + scripts)

24.8 ❌ No Game Day

Never test failure → unknown unknowns

Fix: Quarterly chaos exercise

24.9 ❌ Single Region

1 region down → 100% out

Fix: Multi-region (if critical)

24.10 ❌ No Idempotency

Retry causes duplicate

Fix: Idempotent operations + idempotency key


25. Real Outage Cases — Learn From Disasters

25.1 AWS S3 — Feb 2017

Cause: Typo ใน command — engineer accidentally removed servers
Result: S3 down ~4 hours in us-east-1
Impact: ทุกเว็บใหญ่ที่ใช้ S3 ดาวน์
Lesson:
- Limit blast radius (จำกัด "รัศมีความเสียหาย" — ออกแบบให้พลาด 1 จุดกระทบวงแคบ ไม่ลามทั้งระบบ เช่น ไม่ allow mass removal = สั่งลบทีเดียวเยอะ ๆ ไม่ได้)
- Test changes in staging
- Better tooling (preview before execute)

25.2 Cloudflare — June 2022 BGP

Cause: BGP misconfiguration ใน Cloudflare's network
Result: Many sites down briefly
Lesson:
- Test BGP changes carefully
- Multiple control planes
- Quick rollback capability

25.3 Facebook (Meta) — Oct 2021

Cause: BGP misconfiguration → entire FB infrastructure unreachable
Result: 6+ hours down (FB, IG, WhatsApp)
Impact: ~$60M revenue loss
        + access to internal tools (engineers ไม่สามารถ badge เข้า office!)
Lesson:
- Multiple control plane regions
- Out-of-band access for emergency
- BGP change validation

25.4 GitLab — Jan 2017

Cause: Engineer typed "rm -rf" on wrong server (primary แทน secondary)
Result: ~6 hours of data loss for ~700 projects
Lesson:
- Backups (5 different methods — NONE worked!)
- Test restoration regularly
- Separate roles (no human access to production storage)

25.5 CrowdStrike — July 2024

Cause: Bad update pushed to Windows kernel driver
Result: 8.5M+ Windows machines BSOD globally
Impact: Airlines, hospitals, banks down — estimated $5B+
Lesson:
- Staged rollout (canary first)
- Kernel-level changes need extra caution
- Customer rollback capability

เรียนจากความล้มเหลวของคนอื่น — ราคาถูกกว่าเรียนเอง


26. Checkpoint — ฝึกทำเอง

ลงมือทำเพื่อให้ pattern เรื่อง reliability ติดมือ — แบบฝึกหัดนี้ให้คุณสร้าง resilient HTTP client (timeout + retry + circuit breaker), idempotency key, health check และทดสอบกับเซิร์ฟเวอร์ที่ไม่เสถียร ทำครบจะออกแบบระบบที่ทนต่อความล้มเหลวได้จริง:

🛠️ Checkpoint 4.1 — Resilient HTTP Client
Build wrapper around fetch:

  • Timeout (5s default)
  • Retry 3x with exponential backoff
  • Jitter
  • Circuit breaker
  • Test กับ unstable server

🛠️ Checkpoint 4.2 — Idempotency Key
Implement:

  • API accept Idempotency-Key header
  • Cache result by key (24h TTL)
  • Return cached on retry
  • Test ด้วย duplicate request

🛠️ Checkpoint 4.3 — Health Check
Spring Boot หรือ Node.js:

  • /health/live (process alive)
  • /health/ready (DB + cache OK)
  • K8s probe config

🛠️ Checkpoint 4.4 — Graceful Shutdown

  • Setup SIGTERM handler
  • Stop accepting new requests
  • Drain in-flight
  • Close connections
  • Verify ด้วย docker stop

🛠️ Checkpoint 4.5 — Chaos Test

  • Run app in staging
  • Kill random pod
  • Verify auto-restart
  • Verify no errors during chaos

27. สรุปบท

ทบทวนแก่นของบทนี้ — reliability คือการ "ออกแบบโดยสมมติว่าทุกอย่างจะพัง" แล้วใส่ pattern ป้องกันไว้ทุกชั้น: timeout, retry, idempotency, circuit breaker, bulkhead, graceful degradation, SLO/error budget และ DR เช็กลิสต์นี้คือสิ่งที่ทำให้ระบบอยู่รอดในโลกจริง:

Plan for failure — distributed systems จะพังเสมอ
Timeout every external call — never indefinite
Retry with exponential backoff + jitter (idempotent only)
Idempotency-Key สำหรับ safe POST retry
Circuit breaker — stop calling failing service
Bulkhead — isolate failure to subset
Fallback / graceful degradation — degrade not crash
Health check: liveness + readiness + startup
Graceful shutdown — drain on SIGTERM
SLI/SLO/SLA + error budget — quantify reliability
Chaos engineering — find weakness intentionally
Multi-region DR — RPO/RTO based on cost-benefit
Cost of outage = $$$/min — justify reliability investment
Learn from disasters — AWS, Facebook, GitLab, CrowdStrike


28. คำศัพท์เพิ่ม

คำศัพท์ความหมาย
Reliabilityระบบทำงานถูกต้อง / ใช้ได้
Availability% time ระบบใช้ได้
Fault toleranceทนต่อ failure ได้
Resiliencerecover จาก failure
Failoverswitch ไป backup
High Availability (HA)99.9%+ availability
SPOFSingle Point of Failure
Cascade failure1 fail → ทำให้อื่น fail
Thundering herdทุก client retry พร้อมกัน
Timeoutจำกัดเวลา wait
Retryลองใหม่
Exponential backoffwait เพิ่มขึ้นแบบ exponential
Jitterrandom delay กระจาย
Idempotencyทำซ้ำได้ผลเดิม
Circuit breakerstop calling fail service
Bulkheadisolate resources
Fallbackuse default when fail
Backpressuresignal slow down
Liveness probe"process alive?"
Readiness probe"ready to serve?"
Graceful shutdownclean exit
SLIService Level Indicator
SLOService Level Objective
SLAService Level Agreement
Error budget100% - SLO
RPORecovery Point Objective (data loss)
RTORecovery Time Objective (downtime)
DRDisaster Recovery
Chaos engineeringintentional failure injection
Game dayplanned failure exercise
Postmortemanalysis after incident
Runbookdocument procedure for incident

← บทที่ 3 | บทที่ 5 → Worked Examples


🔤 Glossary · 📋 Style guide · 📅 last_verified: 2026-06-03