patternjavascriptMajor
Load balancer health checks: what they check and why endpoints matter
Viewed 0 times
health checkload balancerlivenessreadiness503kubernetes probeavailability
Problem
A server is technically running but in a degraded state (database disconnected, out of memory, job queue backed up). The load balancer keeps routing traffic to it because the process is alive.
Solution
Implement a real health check endpoint that verifies actual dependencies:
Nginx upstream health check config:
// Express health check endpoint
app.get('/health', async (req, res) => {
const checks = {};
let status = 200;
try {
await db.raw('SELECT 1'); // verify database connectivity
checks.database = 'ok';
} catch (err) {
checks.database = 'error';
status = 503;
}
try {
await redis.ping();
checks.redis = 'ok';
} catch (err) {
checks.redis = 'degraded'; // non-fatal
}
res.status(status).json({
status: status === 200 ? 'ok' : 'degraded',
checks,
uptime: process.uptime(),
timestamp: new Date().toISOString()
});
});Nginx upstream health check config:
upstream backend {
server 10.0.0.1:3000;
server 10.0.0.2:3000;
}Why
A process-alive check only confirms the web server is accepting TCP connections. A deep health check catches application-level failures that affect real users.
Gotchas
- Health check endpoints must not require authentication — the load balancer calls them without credentials
- Distinguish between liveness (restart me) and readiness (send me traffic) probes in Kubernetes
- Health checks themselves can cause load — keep them lightweight and avoid expensive queries
- Return 503 (not 500) for health failures — some load balancers only remove servers on 5xx
Revisions (0)
No revisions yet.