Skip to content
DevRecall
← Roadmap
26

Observability, Reliability & Incident Response

drafted

Logs/metrics/traces, structured logging & correlation ID, OpenTelemetry, RED/USE, SLI/SLO/error budget, alert theo triệu chứng, load testing (k6), capacity planning, debug production BE/DB/FE, incident & postmortem.

0/45 rated · mastery 0%

Bài học

12 bài · ~139 phút đọc. Học theo thứ tự, rồi làm câu hỏi.
  1. 01~14 phút· 4 câuverify

    Monitoring, observability và ba tín hiệu

    Monitoring khác observability ở đâu, logs/metrics/traces mỗi loại trả lời câu hỏi gì và tốn chi phí thế nào, cách nối chúng bằng trace_id và exemplar, và kế hoạch 90 ngày cho một team chỉ có console.log.

  2. 02~12 phút· 5 câuverify

    Structured logging, correlation ID và AsyncLocalStorage

    Log JSON với pino (level, child logger, redact), correlation ID qua HTTP header và message header, vì sao biến global gắn nhầm ID khi có request đồng thời, AsyncLocalStorage trong Node, và thiết kế logging multi-tenant không lộ PII.

  3. 03~11 phút· 4 câuverify

    Metrics, histogram, percentile và cardinality

    Counter/gauge/histogram/summary trong Prometheus, vì sao average latency và trung bình các p99 nói dối, histogram_quantile gộp đúng giữa instance, cardinality explosion khi gắn userId/url làm label, và cách đặt và đo latency target.

  4. 04~13 phút· 6 câuverify

    RED, USE, golden signals và runtime metrics của Node

    RED cho service, USE cho resource, bốn golden signals; saturation trong Node (event loop delay, ELU, connection pool, libuv); đo event loop bị block, tìm memory leak bằng heap snapshot, consumer lag của Kafka và metric cho Socket.IO.

  5. 05~12 phút· 7 câuverify

    Distributed tracing, W3C Trace Context và OpenTelemetry trong Node

    Span, trace, traceparent; các thành phần của OpenTelemetry (API, SDK, instrumentation, OTLP, Collector, semantic conventions); instrument Express đúng thứ tự load và lỗi khi load SDK muộn; propagation qua Kafka và span links; vì sao trace trông đầy đủ nhưng giấu thời gian; frontend RUM và so sánh đường cũ/mới khi tách monolith.

  6. 06~10 phút· 4 câuverify

    Sampling, OTel Collector và chi phí telemetry

    Head sampling (ParentBased TraceIdRatio) và tail sampling ở Collector, đo thật bao nhiêu trace lỗi bị mất; pipeline của Collector (receiver, processor, exporter, redaction, memory_limiter, load-balancing exporter); chọn stack self-hosted/SaaS/cloud và giữ chi phí khi traffic tăng 10x.

  7. 07~11 phút· 4 câuverify

    SLI, SLO, SLA và error budget

    SLI dạng good/total đo từ góc người dùng, SLO là mục tiêu trong cửa sổ, SLA là hợp đồng; tính error budget theo thời gian và theo request, error budget policy, chọn user journey cho nền tảng B2B2C multi-tenant, và trả lời câu hỏi latency target bằng số đo.

  8. 08~11 phút· 3 câuverify

    Alert theo triệu chứng và burn-rate alert

    Vì sao page theo triệu chứng chứ không theo nguyên nhân, burn rate là gì, multi-window multi-burn-rate theo SRE Workbook, viết recording/alerting rule Prometheus và unit test bằng promtool (đo thật thời điểm alert bắn và tắt), sửa một rule set tệ, và giảm alert fatigue.

  9. 09~10 phút· 5 câuverify

    Load testing với k6: open vs closed model

    Các loại test (smoke, average-load, stress, spike, soak, breakpoint), closed model và coordinated omission, executor constant-arrival-rate và thresholds trong k6, đo thật cùng một server bằng hai mô hình, đo gì ngoài response time, và những cách kết quả load test đánh lừa bạn.

  10. 10~11 phút· 4 câuverify

    Capacity planning, Little's Law và flash sale

    Capacity planning dựa trên số đo, Little's Law (L = λ × W) để tính concurrency, pool và số instance, knee của đường latency theo throughput (đo thật bằng k6), headroom và giới hạn dùng chung (DB, third-party), chiến lược load test và chuẩn bị cho flash sale 20x, và kiểm chứng hiệu năng khi tách monolith.

  11. 11~13 phút· 6 câuverify

    Phương pháp debug sự cố production (BE, DB, FE)

    Một phương pháp có cấu trúc: xác nhận tác động, tìm thay đổi gần đây, khoanh vùng theo chiều và theo tầng, giả thuyết và bằng chứng. Áp dụng cho p99 tăng mà p50 không đổi, lỗi 500 ngẫu nhiên 1/200 (tái hiện thật ECONNRESET do keep-alive), query 20 ms thành 8 s (tái hiện lock blocking trong Postgres), dashboard xanh mà một region kêu hỏng, và cách kể câu chuyện debug trong phỏng vấn.

  12. 12~11 phút· 5 câuverify

    Incident response, on-call và postmortem blameless

    Vai trò trong incident (Incident Commander, Ops/SME, Communications, scribe), 15 phút đầu, mức độ SEV, mitigate trước root cause, cập nhật định kỳ; postmortem blameless gồm gì, contributing factors, action item có owner và deadline; đo MTTD/MTTR và budget đã tiêu; văn hoá on-call bền vững và cách kể một incident trong phỏng vấn.

Tóm tắt & cheat sheet của track

TL;DR

  • Monitoring trả lời "có hỏng không?" (câu hỏi biết trước); observability trả lời "tại sao hỏng?" cho cả câu hỏi chưa biết trước — nhờ telemetry giàu ngữ cảnh (high-cardinality, liên kết được với nhau).
  • Ba tín hiệu: metrics (rẻ, tổng hợp, để alert), logs (chi tiết từng sự kiện), traces (đường đi của một request qua nhiều service). Chìa khoá là nối chúng bằng trace_id / correlation ID.
  • OpenTelemetry là chuẩn vendor-neutral để instrument (API + SDK + Collector + OTLP) — instrument một lần, gửi tới backend nào cũng được.
  • Reliability đo bằng SLI → SLO → error budget; alert theo triệu chứng người dùng thấy (burn rate), không theo mọi nguyên nhân (CPU 80%).
  • Senior interview hay hỏi: "Kể sự cố khó nhất bạn debug" → cần phương pháp (khoanh vùng, giả thuyết, bằng chứng), không phải may mắn. Kết thúc bằng postmortem blameless có action item.

Khái niệm cốt lõi

Khái niệmMột câuVí dụ ngắn
Structured loggingLog là JSON có field cố định, query được{"level":"error","trace_id":"4bf9…","tenant_id":"t_42","msg":"payment failed"}
Correlation IDID đi theo request qua mọi service/logHeader traceparent / x-request-id → AsyncLocalStorage → mọi log line
Span / traceSpan = một đơn vị công việc có start/end + attributes; trace = cây span của một requestGET /checkout → span SELECT orders 120 ms → span POST stripe 800 ms
CardinalitySố giá trị khác nhau của một labelLabel user_id trên metric → hàng triệu time series → backend nổ
REDRate, Errors, Duration — cho service (request-driven)API: 1.2k rps, 0.3% 5xx, p99 450 ms
USEUtilization, Saturation, Errors — cho resourceDB CPU 85%, 40 connection chờ, 0 disk error
Golden signalsLatency, Traffic, Errors, Saturation (Google SRE)Dashboard đầu tiên của mọi service
SLITỉ lệ sự kiện tốt / tổng sự kiệnrequests < 300ms và không 5xx / total requests
SLOMục tiêu cho SLI trong cửa sổ thời gian99.9% trong 30 ngày
Error budget1 − SLO — lượng "được phép hỏng"99.9%/30 ngày ≈ 43 phút downtime tương đương
Burn rateTốc độ tiêu budget so với mức "vừa đủ hết đúng hạn"Burn rate 14.4 trong 1h = tiêu 2% budget tháng trong 1 giờ
Percentilep50/p95/p99 — không bao giờ lấy trung bình của percentilep99 = 1% request chậm hơn giá trị này

Cơ chế hoạt động

Telemetry pipeline với OpenTelemetry:

Phương pháp debug sự cố production (BE / DB / FE):

Trade-offs

Tín hiệuMạnhYếuChi phí
MetricsRẻ, lưu lâu, alert, xu hướngMất chi tiết; high-cardinality đắtTheo số time series
LogsChi tiết đầy đủ, ngữ cảnhĐắt khi volume lớn, khó tổng hợp nếu không structuredTheo GB ingest + retention
TracesThấy latency qua nhiều service, critical pathCần propagation đúng; phải samplingTheo span; sampling quyết định
Head samplingĐơn giản, rẻ, quyết định ở đầu requestCó thể bỏ mất trace lỗi/chậm hiếmThấp
Tail samplingGiữ trace lỗi/chậm, bỏ trace bình thườngCollector phải buffer toàn bộ trace, phức tạpCao hơn
Load test typeMục đíchHình dạng tải
SmokeScript chạy đúng, baselineRất ít VU, ngắn
Average-loadHành vi ở tải bình thườngRamp tới mức trung bình, giữ
StressHành vi trên mức bình thườngTải cao hơn peak
SpikeTăng đột ngột (flash sale)Nhảy vọt trong vài giây
Soak / enduranceLeak, degrade theo thời gianTải vừa trong nhiều giờ
BreakpointTìm giới hạnTăng dần tới khi vỡ

Pitfalls

  • Log text tự do, không có trace_id/tenant_id → không nối được log giữa các service.
  • Log PII/secret (token, password, số thẻ) → sự cố bảo mật + compliance.
  • Label metric high-cardinality (user_id, URL có ID) → chi phí và backend quá tải.
  • Dùng average latency hoặc lấy trung bình của p99 giữa các instance.
  • Alert theo nguyên nhân (CPU, memory) thay vì triệu chứng → alert fatigue, on-call bỏ qua alert thật.
  • SLO 100% hoặc SLO không ai dùng để ra quyết định.
  • Load test từ laptop, closed model (VU chờ response) → coordinated omission, số đẹp giả tạo.
  • Postmortem tìm "người có lỗi" → mọi người giấu thông tin lần sau.
  • OTel SDK khởi tạo sau khi đã import express/pg → auto-instrumentation không patch được.

Cheat sheet

  • Log: JSON, level đúng, trace_id, span_id, request_id, tenant_id, service, version; không PII; ra stdout.
  • Node: AsyncLocalStorage giữ context request; pino (nhanh) + OTel log correlation.
  • W3C Trace Context: traceparent: 00-<trace-id 32 hex>-<span-id 16 hex>-<flags>.
  • RED cho service, USE cho resource; bốn golden signals cho dashboard mặc định.
  • 99.9% / 30 ngày ≈ 43.2 phút · 99.95% ≈ 21.6 phút · 99.99% ≈ 4.3 phút.
  • Alert: multi-window multi-burn-rate (ví dụ page khi 2% budget cháy trong 1h, ticket khi 10% cháy trong 3 ngày).
  • Load test: open model (arrival-rate) khi mô phỏng user thật; đo p95/p99, error rate, throughput, và saturation của DB/pool.
  • Little's Law: concurrency = throughput × latency.
  • Incident: phân vai (incident commander, comms, ops), mitigate trước, root cause sau, timeline, postmortem blameless trong vài ngày.

Personal notes (Notion)

Ghi chú cá nhân — có thể sai hoặc lỗi thời, dùng để tham khảo.

Interview Questions

Showing 45 / 45

import pino from "pino";
export const logger = pino({
  redact: ["req.headers.authorization", "*.password", "*.cardNumber"],
  base: { service: "order-api", version: process.env.GIT_SHA },
});
logger.info({ orderId, tenantId, durationMs }, "order created");
app.use((req, _res, next) => {
  (global as any).requestId = req.headers["x-request-id"] ?? crypto.randomUUID();
  next();
});

export function log(msg: string) {
  console.log(`${new Date().toISOString()} [${(global as any).requestId}] ${msg}`);
}
// tracing.ts — load with: node --import ./dist/tracing.js dist/server.js
import { NodeSDK } from "@opentelemetry/sdk-node";
import { getNodeAutoInstrumentations } from "@opentelemetry/auto-instrumentations-node";
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";

const sdk = new NodeSDK({
  serviceName: "order-api",
  traceExporter: new OTLPTraceExporter(),
  instrumentations: [getNodeAutoInstrumentations()],
});
sdk.start();
process.on("SIGTERM", () => sdk.shutdown());
import http from "k6/http";
import { sleep } from "k6";

export const options = { vus: 500, duration: "5m" };

export default function () {
  http.get("https://staging.example.com/api/products");
  sleep(1);
}
- alert: HighCPU
  expr: avg(rate(process_cpu_seconds_total[1m])) > 0.8
  for: 0m
  labels: { severity: page }
- alert: AnyError
  expr: increase(http_requests_total{status=~"5.."}[1m]) > 0
  labels: { severity: page }
- alert: SlowRequests
  expr: avg(http_request_duration_seconds_sum / http_request_duration_seconds_count) > 0.5
  labels: { severity: page }