Module P-10·18 min read

TCP connection overhead, ioredis connection pool sizing, reconnection strategies with exponential backoff, command timeout configuration, lazy connect vs eager connect, and health check patterns for production clients.

P-10 — Connection Pooling and Client Configuration

Who this module is for: You create a Redis client with new Redis() and call commands on it. It works. But under production load you see connection refused errors, command timeouts, or Redis reporting hundreds of connected clients. This module covers how Redis connections work at the TCP level, how ioredis manages connections, and how to configure your client for production reliability.


The Cost of a TCP Connection

Every Redis client maintains at least one persistent TCP connection to the Redis server. Establishing a TCP connection requires a three-way handshake (SYN → SYN-ACK → ACK) plus any TLS handshake — roughly 1–3 RTTs before the first command can be sent.

Redis itself can handle tens of thousands of concurrent connections, but each connection consumes:

  • ~20KB of kernel socket buffer (send + receive)
  • A slot in Redis's client list (memory for the client struct, output buffer)
  • A file descriptor on both the client and server side

For a Node.js application, one Redis client holds one persistent TCP connection that is multiplexed — all commands share the connection via the RESP protocol. This is different from PostgreSQL's connection model where each database session is a separate stateful connection requiring explicit pooling.


ioredis Connection Model

ioredis maintains a single persistent TCP connection per Redis instance. Commands are sent over this connection and responses are parsed in order. Pipelining (auto-pipelining) batches commands issued in the same event loop tick.

typescript

When One Connection is Not Enough

A single connection becomes a bottleneck when:

  • You have many concurrent await redis.command() calls that cannot be batched
  • Some commands block the connection (BLPOP, SUBSCRIBE)
  • You need Pub/Sub (subscriber mode) alongside normal commands

For these cases, create multiple Redis instances or use a cluster/sentinel client.


Key Configuration Options

typescript

connectTimeout vs commandTimeout

  • connectTimeout — how long to wait for the initial TCP + auth handshake. If Redis is briefly unavailable at startup, this controls how long you wait before failing.
  • commandTimeout — how long to wait for a command response after sending it. This is the most important setting to prevent hung requests. Without it, a command can wait forever if the connection drops mid-flight.

Always set commandTimeout. A reasonable value is 2–5× your P99 Redis latency. For a Redis instance with P99 < 5ms, set commandTimeout: 500 (500ms). This allows for occasional latency spikes without hanging your application.

retryStrategy

The retry strategy function receives the number of previous retry attempts and returns the milliseconds to wait before the next attempt (or null to stop retrying).

typescript

maxRetriesPerRequest: 3 — limits how many times a command is retried on connection error. The default of 20 means a command issued during a Redis outage can block for up to 20 reconnection cycles before failing. For most applications, 2–3 retries is more appropriate.


Connection Events

typescript

Always listen for error events. An unhandled error event on an EventEmitter crashes the Node.js process. Even if you just log and continue, register the handler.


Multiple Connections for Specific Use Cases

Pub/Sub Requires a Dedicated Connection

typescript

A subscribed connection cannot issue non-Pub/Sub commands. Always use a separate Redis instance for subscribers.

Blocking Commands

BLPOP, BRPOP, BLMOVE, XREAD BLOCK — these block the connection until data is available. If you use them on your main Redis connection, no other commands can be sent until the block resolves.

typescript

Health Checks and Circuit Breaking

In production, Redis may become temporarily unavailable — brief network interruptions, rolling restarts, failovers. Your application should degrade gracefully rather than hanging.

Periodic Health Check

typescript

Graceful Degradation

Design cache reads to degrade gracefully when Redis is unavailable:

typescript

Cache writes should also be non-blocking on failure:

typescript

Sentinel and Cluster Clients

For production deployments with Sentinel or Cluster, ioredis provides dedicated client classes:

Sentinel Client

typescript

The Sentinel client queries the sentinels to discover the current primary address and reconnects automatically on failover.

Cluster Client

typescript

The Cluster client handles MOVED and ASK redirections automatically.


Monitoring Connections

text
text

blocked_clients > 0 is normal if you use blocking commands. A large number that is growing suggests workers are blocking and not consuming from queues.

connected_clients approaching maxclients is a warning. Increase maxclients in redis.conf or identify clients that are not disconnecting (connection leaks).


Summary

  • Redis uses persistent TCP connections — one connection per Redis instance, multiplexed via RESP
  • Always set commandTimeout — prevents commands from hanging indefinitely on connection issues
  • Set maxRetriesPerRequest: 2-3 — the default of 20 holds commands too long during outages
  • retryStrategy controls reconnection backoff — use exponential backoff with jitter, cap retries
  • Pub/Sub and blocking commands (BLPOP) require dedicated Redis instances
  • Always listen for error events — unhandled error on an EventEmitter crashes Node.js
  • For Sentinel: use the sentinels option; for Cluster: use ioredis.Cluster
  • Monitor connected_clients and blocked_clients via INFO clients
  • Design cache reads to degrade gracefully — catch Redis errors and fall back to the database

Next: P-11 — Monitoring and Observability — the INFO command section by section, SLOWLOG analysis, LATENCY HISTORY, and the 10 metrics every Redis dashboard must include.


Knowledge Check

A Node.js application uses ioredis with default configuration settings. During a minor network partition, the application loses connectivity to Redis for 10 seconds. How does ioredis handle the commands issued by the application during this 10-second window?


An engineer notices that their application's primary Redis connection is occasionally unresponsive to standard GET and SET commands, yet INFO clients shows the connection is active. The application uses a single ioredis instance for all operations. Which of the following operations is most likely causing the primary connection to hang?


What is the primary operational difference between configuring connectTimeout and commandTimeout in a Redis client?

Test your knowledge with more question sets

Sign in to access a wider variety of questions and get notified when new practice sets are added to this module.

Sign in & Register

Discussion

0

Join the discussion

Loading comments...

© 2026 Jatin Jain Saraf (JJS). All rights reserved.