Health Check / Heartbeat Service#
Problem statement (interviewer prompt)
Design a health-check / heartbeat service used by thousands of microservices for liveness / readiness probes + dashboards. Aggregate at 1Hz, detect failures within seconds, distinguish flap vs hard-down, and feed into the LB / orchestrator's removal decisions.
flowchart LR
N[Nodes]
HB[Heartbeat collector]
STATE[(Health state)]
ALERT[Alerts]
N -. heartbeat .-> HB --> STATE --> ALERT
classDef client fill:#dbeafe,stroke:#1e40af,stroke-width:1px,color:#0f172a;
classDef edge fill:#cffafe,stroke:#0e7490,stroke-width:1px,color:#0f172a;
classDef service fill:#fef3c7,stroke:#92400e,stroke-width:1px,color:#0f172a;
classDef datastore fill:#fee2e2,stroke:#991b1b,stroke-width:1px,color:#0f172a;
classDef cache fill:#fed7aa,stroke:#9a3412,stroke-width:1px,color:#0f172a;
classDef queue fill:#ede9fe,stroke:#5b21b6,stroke-width:1px,color:#0f172a;
classDef compute fill:#d1fae5,stroke:#065f46,stroke-width:1px,color:#0f172a;
classDef storage fill:#e5e7eb,stroke:#374151,stroke-width:1px,color:#0f172a;
classDef external fill:#fce7f3,stroke:#9d174d,stroke-width:1px,color:#0f172a;
classDef obs fill:#f3e8ff,stroke:#6b21a8,stroke-width:1px,color:#0f172a;
class N,HB service;
class STATE datastore;
class ALERT obs;
flowchart TB
subgraph Nodes
N1[Node 1]
N2[Node 2]
NN[Node N]
end
subgraph Modes[Probe modes]
ACTIVE[Active checks - HTTP/TCP/gRPC]
PASSIVE[Passive - outcome-based]
HB[Heartbeat push from node]
PHI[Phi-accrual detector]
end
subgraph Service
COL[Collector cluster]
STATE[(Health state KV)]
GOSSIP[Gossip across collectors]
RULES[Status rules]
DEPS[Dependency graph]
end
subgraph Reactions
LB[LB pool update]
ROUTE[Routing change]
ALERT[Alerts / pages]
RUNBOOK[Automated remediation]
end
Nodes --> Modes --> Service --> Reactions
classDef client fill:#dbeafe,stroke:#1e40af,stroke-width:1px,color:#0f172a;
classDef edge fill:#cffafe,stroke:#0e7490,stroke-width:1px,color:#0f172a;
classDef service fill:#fef3c7,stroke:#92400e,stroke-width:1px,color:#0f172a;
classDef datastore fill:#fee2e2,stroke:#991b1b,stroke-width:1px,color:#0f172a;
classDef cache fill:#fed7aa,stroke:#9a3412,stroke-width:1px,color:#0f172a;
classDef queue fill:#ede9fe,stroke:#5b21b6,stroke-width:1px,color:#0f172a;
classDef compute fill:#d1fae5,stroke:#065f46,stroke-width:1px,color:#0f172a;
classDef storage fill:#e5e7eb,stroke:#374151,stroke-width:1px,color:#0f172a;
classDef external fill:#fce7f3,stroke:#9d174d,stroke-width:1px,color:#0f172a;
classDef obs fill:#f3e8ff,stroke:#6b21a8,stroke-width:1px,color:#0f172a;
class LB edge;
class N1,N2,NN,ACTIVE,PASSIVE,HB,PHI,COL,GOSSIP,RULES,DEPS,ROUTE,RUNBOOK service;
class STATE datastore;
class ALERT obs;
Failure detection#
- Binary up/down is brittle.
- Phi-accrual outputs a suspicion value (probability host is dead); thresholding triggers reactions.
Probe vs heartbeat#
- Active probe = control plane initiates; ensures network path works.
- Heartbeat = node-initiated; cheaper at scale.
- Both used together.
Glossary & fundamentals#
| Concept | What it is | Fundamentals |
|---|---|---|
| Service discovery | feeds healthy set | service-discovery |
| Load balancer | consumes healthy pool | load-balancer |
| Resilience patterns | breakers + ejections | resilience-patterns |
| Observability | uptime SLO signals | observability |
Quick reference#
Functional#
- Periodic active and/or passive checks.
- Distributed agreement on liveness.
- Feed routing + LB + alerts.
- Dependency-aware (don't page if upstream is the real cause).
Non-functional#
- Sub-second detection ideal.
- Avoid flapping (debounce, hysteresis).
- Survive network partitions safely (prefer caution).
Trade-offs#
- Frequent probes = fast detection but load.
- Phi accrual = nuanced; tuning effort.
- Multi-checker quorum to avoid single observer triggering global change.
Refs#
- Cassandra & Akka phi-accrual.
- Consul / etcd / ZK health docs.
- "The Tail at Scale" Dean & Barroso.
FAQ#
What is a heartbeat service?#
A heartbeat service collects periodic liveness signals from nodes, stores recent samples, and emits alerts when a node misses N consecutive intervals. Orchestrators consume its verdict for removal decisions.
Active vs passive health checks?#
Active checks have a central prober dial each node on a schedule. Passive checks let each node push its own heartbeat. Active is simpler; passive scales better since the load is on the node, not the prober.
Liveness probe vs readiness probe?#
Liveness asks 'is the process alive'; if it fails, the orchestrator restarts the pod. Readiness asks 'is it ready to take traffic'; if it fails, the load balancer just stops sending requests.
How do you avoid false positives from flapping?#
Require N consecutive misses before marking down, and N consecutive successes before marking back up. Add jitter to probe schedules so a network blip does not synchronize failures.
How does the health service alert at scale?#
Aggregate state in memory per region, write durable transitions to a log, and let an alerting service tail the log. This separates fast detection from heavyweight notification delivery.