System Design Concepts

No fluff — visual, concise, interview-ready

📊 13 · OBSERVABILITY

Logging

Structured JSON logs with correlation IDs. Levels: DEBUG → INFO → WARN → ERROR → FATAL. The foundation of observability — immutable forensic records of system behavior.

Log Pipeline Architecture
Log Pipeline Architecture: App → Shipper → Buffer → Storage → Visualization Applications Service A (Java) Service B (Node) Service C (Go) stdout/file Log Shipper Fluentd Filebeat Parse · Enrich · Filter forward Kafka Buffer topic: logs.* Decouple · Backpressure consume Elasticsearch Index · Search · Retain Hot/Warm/Cold tiers query Kibana Dashboards · Alerts Visualize · Explore ELK Stack / EFK Stack — handles 100K+ logs/sec with Kafka buffering
Guarantees: Immutability (forensics, compliance). Searchability. Correlation IDs trace flow across services. Never log passwords/PII. Tools: ELK, Splunk, Loki, CloudWatch. Sample: 100% errors, 1-10% normal.
Structured Logging Format (JSON)
{
  "timestamp": "2024-03-15T10:23:45.123Z",
  "level": "ERROR",
  "service": "payment-service",
  "version": "2.4.1",
  "trace_id": "abc123def456",
  "span_id": "span-789",
  "correlation_id": "order-98765",
  "message": "Payment processing failed",
  "metadata": {
    "user_id": "u-12345",
    "amount": 99.99,
    "currency": "USD",
    "error_code": "GATEWAY_TIMEOUT",
    "retry_count": 2
  },
  "context": {
    "host": "pod-payment-7b4f9",
    "region": "us-east-1",
    "environment": "production"
  }
}
Log Levels Decision Guide
LevelWhen to UseExampleAlert?
FATALSystem cannot continue — process will exitCannot bind to port, OOM killerPage immediately
ERROROperation failed — needs attentionPayment gateway timeout, DB connection lostAlert if rate > threshold
WARNUnexpected but recoverable — degraded stateRetry succeeded, cache miss fallback, deprecated API callMonitor trend
INFONormal business events — audit trailOrder placed, user login, deployment startedNo
DEBUGDeveloper troubleshooting — verboseSQL query, request/response body, cache keyNo — never in prod
TRACEExtremely detailed — method entry/exitFunction arguments, loop iterationsNo — dev only
Log Sampling Strategies
StrategyHow It WorksSample RateBest For
Always sample errors100% of ERROR/FATAL logs retained100%All environments
Rate-basedKeep 1 in N logs per time window1-10%High-volume INFO logs
Priority-basedSample based on log level + service criticalityVariesCost optimization
Tail-basedDecide after request completes (keep if slow/error)DynamicDistributed tracing correlation
Hash-basedConsistent sampling by trace_id hashConfigurableCorrelated log/trace sampling
⚠️ Log Anti-Patterns: Logging PII/secrets · Unstructured string concatenation · Logging inside tight loops · No correlation ID · Logging full request bodies in prod · Missing timestamps
One-liner: Emit structured JSON with correlation_id + trace_id. Ship via Fluentd → Kafka → ES. Sample 100% errors, 1-10% info. Never log PII. Use log levels as severity contracts.

Metrics

Golden Signals (Google SRE): Latency · Traffic · Errors · Saturation — numeric time-series data for alerting and trending

Metrics Collection Flow
Metrics Collection: App → OTel SDK → Collector → Prometheus → Grafana Application OTel SDK (auto-instr) counter / histogram OTLP OTel Collector Receive → Process → Export Batch · Filter · Transform remote write Prometheus TSDB (time-series) PromQL · Rules · Alerts query Grafana Dashboards · Panels Alert Manager 🚨 PagerDuty 💬 Slack 📧 Email OpenTelemetry → Prometheus → Grafana — the modern open-source metrics stack
SignalWhat It MeasuresKey MetricsAlert When
LatencyTime to serve a requestp50 · p95 · p99 · p999. Never use avg — hides tail latencyp99 > SLA threshold
TrafficDemand on the systemRPS · TPS · bytes/sec · active connectionsSudden spike or unexpected drop
ErrorsRate of failed requestsError rate % · 5xx count · timeout count · DLQ depthError rate > 1% or any 5xx spike
SaturationHow full / overloaded the system isCPU % · Memory % · Disk I/O · Thread pool queue depthCPU > 80% sustained
MethodFull FormBest ForMetrics
REDRate · Errors · DurationMicroservices, APIsRequests/sec · Error % · p99 response time
USEUtilization · Saturation · ErrorsInfrastructure — CPU, memory, disk, networkCPU % · queue depth · device error count
Why p99 Matters More Than Average
Percentile Distribution: Histogram showing why p99 matters more than average Response Time (ms) Request Count p50 (50ms) p95 (120ms) p99 (800ms) p999 (2.5s) avg=85ms (misleading!) ⚠️ The "long tail" 1% of users see 800ms+ At 1M req/day = 10K bad experiences
SLI / SLO / SLA Relationship
SLI/SLO/SLA: Indicator → Objective → Agreement hierarchy SLA (Agreement) Contractual — penalty if breached 99.9% availability SLO (Objective) Internal target — stricter than SLA 99.95% availability SLI (Indicator) Actual measured: 99.97%
SLI / SLO / SLA: SLI (indicator) — actual measured metric. SLO (objective) — internal target. SLA (agreement) — contractual commitment with penalty. SLO should be stricter than SLA. Error Budget = 100% − SLO.
⚠️ Cardinality Explosion: Every unique combination of label values creates a new time series. user_id as a label = millions of series → OOM. request_path with IDs (/users/12345) = unbounded. Fix: use bounded labels (method, status_code, service) and move high-cardinality to logs/traces. Rule of thumb: <10 values per label.
Tools: Prometheus — scrape + store time-series. Grafana — dashboards + alerting. Datadog — managed APM. CloudWatch — AWS native. OpenTelemetry — vendor-neutral standard. Thanos/Cortex — long-term Prometheus storage.
One-liner: Track p99 not average — use RED for services, USE for infra, alert on Golden Signals, define SLOs stricter than SLA. Watch for cardinality explosion.

Distributed Tracing

Track a single request across services. Trace ID → Spans → Parent-child relationships → Latency breakdown. Essential for debugging microservices.

Trace / Span Hierarchy — Request Flow
Distributed Trace: Request flowing through API Gateway → Auth → User Service → DB with timing bars Trace ID: abc-123-def-456 Total Duration: 245ms 0ms 60ms 120ms 245ms API Gateway span-001 (root) 245ms — HTTP GET /api/users/profile Auth Service span-002 (child of 001) 72ms — JWT validation User Service span-003 (child of 001) 135ms — getProfile() PostgreSQL span-004 (child of 003) 89ms — SELECT * FROM users ⚠️ Bottleneck: DB query = 36% of total
Core Concepts: Trace — end-to-end journey of a request. Span — single unit of work (one service call). Root Span — first span, sets trace duration. Child Span — nested operation within parent. Span Context — trace_id + span_id + flags propagated across boundaries.
Context Propagation Standards
StandardHeader FormatExampleUsed By
W3C TraceContexttraceparent / tracestate00-abc123-span456-01OpenTelemetry (default), modern systems
B3 (Zipkin)X-B3-TraceId / X-B3-SpanIdX-B3-TraceId: abc123Zipkin, Spring Cloud Sleuth
B3 Singleb3 (single header)abc123-span456-1Zipkin compact format
Jaegeruber-trace-idabc123:span456:0:1Jaeger native (legacy)
Baggagebaggageuser_id=123,region=usW3C Baggage — custom context across services
Sampling Strategies: Head-Based vs Tail-Based
StrategyDecision PointProsConsBest For
Head-basedAt trace start (first service)Simple, low overhead, consistentMay miss interesting traces (errors decided later)High-volume, cost-sensitive
Tail-basedAfter trace completes (collector)Keep all errors/slow traces, smarterHigher memory (buffer full traces), complexDebug-focused, error analysis
Priority-basedBased on attributes (user tier, endpoint)VIP users always tracedConfiguration complexityMulti-tenant systems
Rate-limitingN traces per second per servicePredictable costMay miss burstsBudget-constrained
Async Boundary Propagation: For Kafka — inject trace context into message headers (traceparent header). For SQS — use message attributes. For gRPC — metadata headers. For HTTP — request headers. Key: consumer creates a new span linked to producer span (SpanLink, not parent-child).
Tools: OpenTelemetry (vendor-neutral SDK) · Jaeger (open-source backend) · Zipkin (lightweight) · Datadog APM · AWS X-Ray · Tempo (Grafana, uses object storage). Sample: 100% errors, 1-5% successes.
One-liner: Propagate W3C TraceContext headers across all boundaries. Use tail-based sampling to capture errors. Every span needs: service name, operation, duration, status, and parent span ID.

Monitoring & Alerting

Collect → Evaluate → Alert → Route → Respond → Root Cause Analysis. Only page if human action is needed.

Alerting Pipeline Architecture
Alerting Pipeline: Metric → Rule Evaluation → Alert Manager → Routing → Notification Channels Metrics Prometheus TSDB Time-series data Rule Engine PromQL evaluation every 15-60s FIRING Alert Manager Deduplicate Group · Silence Inhibit · Route Routing By severity By team/service 🚨 PagerDuty (SEV1) 💬 Slack #alerts 📧 Email (SEV3-4) 📋 Jira Ticket Alert fatigue killer: deduplicate → group → route by severity → escalate on timeout
Alert Quality: Good vs Bad
QualityAlert ExampleWhyAction
✅ GoodError rate > 1% for 5 min on payment-svcSustained, actionable, specific serviceInvestigate payment gateway
✅ Goodp99 latency > 2s for 3 minUser-impacting, time-windowedCheck DB queries, scale pods
✅ GoodError budget burn rate > 14.4x for 1hSLO-based, predictiveWill breach SLO in 6h if unchecked
❌ BadAny single 500 errorToo noisy — single errors are normalAlert fatigue, ignored
❌ BadCPU > 50%Not actionable — 50% is healthyWastes on-call time
❌ BadDisk usage > 80% (no duration)No time window — transient spikes triggerFalse positives
On-Call Best Practices
On-Call Rules: Every alert must have a runbook — link in alert annotation. Escalation policy — if no ack in 5 min, escalate. Rotation — weekly, with handoff notes. Blameless culture — focus on systems, not people. Toil budget — if >50% time on toil, fix the system.
Burn Rate Alerting (Multi-Window)
Burn Rate Concept: If SLO = 99.9% over 30 days → error budget = 0.1% = 43.2 min of downtime/month.

Burn rate 1x = consuming budget at exactly the allowed rate (will exhaust in 30 days).
Burn rate 14.4x = will exhaust entire budget in ~2 days → page immediately.
Burn rate 6x = will exhaust in ~5 days → ticket, investigate.
Burn rate 1x = normal → no action.

Multi-window: Use short window (5 min) to detect fast burns + long window (1h) to confirm sustained. Prevents false positives from brief spikes.
Tools: PagerDuty · Opsgenie · Grafana OnCall · Prometheus Alertmanager. Key features: deduplication, grouping, silencing, inhibition, escalation chains.
One-liner: Only page if human action needed. Use burn rate alerts over static thresholds. Every alert needs a runbook. Group + deduplicate to prevent alert fatigue.

OpenTelemetry

Vendor-neutral observability framework — one SDK for Traces + Metrics + Logs. Instrument once, export to any backend. CNCF project, industry standard.

OpenTelemetry Architecture
OpenTelemetry Architecture: SDK → Processor → Exporter → Collector → Multiple Backends Application + OTel SDK 📍 Traces (SpanProcessor) 📊 Metrics (MeterProvider) 📝 Logs (LoggerProvider) Auto + Manual Instrumentation Context Propagation (W3C) OTLP (gRPC/HTTP) OTel Collector Receivers OTLP · Prometheus · Jaeger · Zipkin Processors Batch · Filter · Transform · Sampling Exporters OTLP · Prometheus · Jaeger · Datadog Connectors (route between pipelines) Jaeger / Tempo (Traces) Prometheus (Metrics) Loki / ES (Logs) Datadog / New Relic Grafana Unified View Instrument once → export everywhere. Vendor-neutral, CNCF graduated project.
Three Signals Unified
SignalWhat It CapturesOTel APIData ModelBest Backend
TracesRequest flow across servicesTracerProvider → Tracer → SpanSpans with parent-child, attributes, eventsJaeger, Tempo, Zipkin
MetricsNumeric measurements over timeMeterProvider → Meter → InstrumentCounter, Histogram, Gauge, UpDownCounterPrometheus, Datadog
LogsDiscrete events with contextLoggerProvider → Logger → LogRecordTimestamp, severity, body, attributes, trace_idLoki, Elasticsearch
Instrumentation Patterns
TypeHowEffortCoverageExample
Auto-instrumentationAgent/SDK hooks into frameworks automaticallyZero code changesHTTP, DB, gRPC, messagingJava agent, Python auto-instr, Node.js require hook
Manual instrumentationDeveloper adds spans/metrics in codeCode changes requiredBusiness logic, custom operationstracer.startSpan("processPayment")
Semantic ConventionsStandardized attribute namesFollow naming guideCross-service consistencyhttp.method, db.system, rpc.service
Collector Deployment Patterns
PatternArchitectureProsConsBest For
SidecarCollector per pod (DaemonSet or sidecar container)Isolation, per-service config, low latencyMore resource usage, many instancesKubernetes, per-service sampling
GatewayCentralized collector cluster (Deployment)Fewer instances, centralized config, easier to manageSingle point of failure, network hopSimple setups, centralized processing
Agent + GatewayLocal agent → central gateway (two-tier)Best of both: local buffering + central processingMore complex, two configsLarge-scale production
Key Benefits: Vendor-neutral — switch backends without re-instrumenting. Correlation — trace_id links logs ↔ traces ↔ metrics. Semantic conventions — standardized attribute names across languages. Collector — offloads processing from app (batching, retry, sampling).
One-liner: Use OTel auto-instrumentation for 80% coverage, add manual spans for business logic. Deploy collector as agent + gateway in production. Correlate all three signals via trace_id.

Dashboards & Visualization

Dashboards are the first thing you look at during an incident. Design for clarity: USE for infra, RED for services, business KPIs for stakeholders.

Dashboard Design Principles
PrincipleDescriptionExample
Audience-firstDifferent dashboards for different rolesSRE: latency/errors. PM: conversion rate. Exec: uptime %
Top-down drillStart high-level, click to detailService overview → endpoint breakdown → individual trace
Time alignmentAll panels share same time rangeCorrelate CPU spike with latency increase at same moment
AnnotationsMark deployments, incidents on timelineVertical line: "v2.4.1 deployed" — correlate with metric change
Thresholds visibleShow SLO/SLA lines on graphsRed line at p99 = 500ms (SLO boundary)
≤ 8 panelsCognitive load limit per dashboardMore panels = slower load + harder to scan during incident
The 4 Golden Dashboards Every Service Needs

1. Service Health (RED)

  • Request rate (RPS)
  • Error rate (%)
  • p50 / p95 / p99 latency
  • Active connections

2. Infrastructure (USE)

  • CPU utilization %
  • Memory usage / limits
  • Disk I/O + space
  • Network in/out

3. Dependencies

  • DB query latency
  • Cache hit ratio
  • External API latency
  • Queue depth / lag

4. Business KPIs

  • Orders/min
  • Signup conversion
  • Revenue per minute
  • Active users
Dashboard Anti-Patterns
Anti-PatternProblemFix
Too many panelsCognitive overload, slow rendering, can't find signal in noiseMax 6-8 panels per dashboard. Split into sub-dashboards.
Vanity metrics"Total requests ever" — not actionable, always goes upShow rate of change (RPS), not cumulative totals
No contextGraph shows spike but no reference for "normal"Add SLO threshold lines + deployment annotations
Average-onlyHides tail latency — 1% of users sufferingAlways show p50 + p95 + p99 together
Stale dashboardsPanels for decommissioned services, broken queriesQuarterly dashboard review. Delete unused panels.
No drill-downSee problem but can't investigate furtherLink panels to detailed dashboards, traces, logs
Grafana Tips: Use variables for service/environment selectors. Annotations for deploys. Alert rules directly on panels. Exemplars — click a metric data point to jump to the exact trace. Explore mode for ad-hoc investigation.
One-liner: Build 4 dashboards per service (RED, USE, Dependencies, Business). Max 8 panels each. Show percentiles not averages. Add SLO lines + deploy annotations. Link to traces for drill-down.

Incident Response

Structured process: Detect → Triage → Mitigate → Resolve → Postmortem. Goal: minimize user impact, learn from failures, prevent recurrence.

Incident Lifecycle
Incident Lifecycle: Detect → Triage → Mitigate → Resolve → Postmortem 🚨 Detect Alert fires User reports Anomaly detection 🔍 Triage Assess severity Assign IC Open war room 🛡️ Mitigate Stop the bleeding Rollback / scale Feature flag off ✅ Resolve Root cause fix Verify recovery Close incident 📝 Postmortem Blameless review Action items Prevent recurrence MTTD Time to Detect MTTR Time to Resolve Learn Prevent next Goal: Minimize MTTD + MTTR. Maximize learning from every incident.
Severity Levels
SeverityImpactResponse TimeWho's PagedExample
SEV1 — CriticalComplete outage, data loss, security breach< 5 minOn-call + manager + execPayment system down, data breach
SEV2 — MajorSignificant degradation, partial outage< 15 minOn-call + team lead50% of requests failing, one region down
SEV3 — MinorLimited impact, workaround available< 4 hoursOn-call (next business day OK)Non-critical feature broken, slow queries
SEV4 — LowCosmetic, no user impactNext sprintTicket onlyTypo in error message, minor UI glitch
Key Reliability Metrics
MetricFull NameFormulaTargetHow to Improve
MTTDMean Time to DetectTime from failure start → alert fires< 5 minBetter monitoring, anomaly detection, synthetic probes
MTTRMean Time to ResolveTime from detection → service restored< 30 min (SEV1)Runbooks, automation, rollback capability, feature flags
MTBFMean Time Between FailuresTotal uptime ÷ number of failuresMaximizeChaos engineering, testing, redundancy, code quality
MTTAMean Time to AcknowledgeTime from alert → human acknowledges< 5 minClear escalation policy, on-call rotation
Postmortem Template Outline
Blameless Postmortem Structure:

1. Summary — What happened, impact, duration, severity
2. Timeline — Minute-by-minute: detection, actions taken, resolution
3. Root Cause — The "5 Whys" analysis. What actually broke and why
4. Impact — Users affected, revenue lost, SLO budget consumed
5. What Went Well — Detection speed, team response, tools that helped
6. What Went Wrong — Gaps in monitoring, slow detection, missing runbooks
7. Action Items — Specific, assigned, time-bound fixes (with owners + deadlines)
8. Lessons Learned — Systemic improvements, process changes
Incident Response Tools: PagerDuty (alerting + escalation) · Statuspage (external communication) · Slack/Teams (war room) · Jira/Linear (action items) · Rootly/incident.io (incident management) · Blameless (postmortem tracking)
Chaos Engineering: Proactively inject failures to find weaknesses before production incidents. Tools: Chaos Monkey (random instance kill) · Litmus (Kubernetes chaos) · Gremlin (managed platform). Start with Game Days — scheduled, controlled experiments with rollback plan.
One-liner: Detect fast (MTTD < 5 min), mitigate first (rollback > debug), resolve properly, then blameless postmortem with action items. Every SEV1 gets a postmortem within 48h.