Open-Source Wikis

/

Redis

/

Systems

/

Pub/Sub & client tracking

redis/redis

Pub/Sub & client tracking

Active contributors: antirez, Oran Agra, Madelyn Olson, debing.sun.

These two subsystems push asynchronous messages from the server to clients without those clients polling. Pub/Sub is the user-facing message broker; tracking is the engine for server-assisted client-side caching.

Source layout

File Role
src/pubsub.c Pub/Sub: channels, patterns, sharded channels, PUBLISH/SUBSCRIBE/PSUBSCRIBE/SSUBSCRIBE. ~27 KB.
src/notify.c Keyspace and key-event notifications (notify-keyspace-events).
src/tracking.c Server-assisted client-side caching (CLIENT TRACKING).
src/blocked.c Blocking commands (BLPOP, XREAD BLOCK, WAIT, …).
src/timeout.c Per-blocked-client timeout sweeper.

Pub/Sub

A PUBLISH chan msg walks server.pubsub_channels (a dict<sds, list<client*>>) and a list of pattern subscribers (server.pubsub_patterns). Each subscriber is sent a 3-element message frame: ["message", chan, msg] (or ["pmessage", pattern, chan, msg] for patterns).

There is no message queue, no acknowledgements, no replay. If a subscriber's output buffer overflows the client-output-buffer-limit pubsub, the connection is closed.

Channels and patterns

Command What it does
SUBSCRIBE chan ... Subscribe to exact channel names.
PSUBSCRIBE pat ... Subscribe to a glob pattern.
UNSUBSCRIBE [chan ...], PUNSUBSCRIBE [pat ...] Stop.
PUBLISH chan msg Send.
PUBSUB CHANNELS [pattern] List channels with subscribers.
PUBSUB NUMSUB [chan ...] Subscriber count per channel.
PUBSUB NUMPAT Pattern-subscriber count.

A subscribed client cannot run regular commands — its flags carry CLIENT_PUBSUB, and the dispatcher rejects most commands. The exceptions: SUBSCRIBE, UNSUBSCRIBE, PSUBSCRIBE, PUNSUBSCRIBE, SSUBSCRIBE, SUNSUBSCRIBE, PING, QUIT, RESET.

Sharded Pub/Sub

Sharded Pub/Sub (SPUBLISH, SSUBSCRIBE, SUNSUBSCRIBE) delivers messages only within the cluster shard that owns the channel's slot. The slot is computed the same way as for keys (CRC16(channel) % 16384).

  • Reduces fan-out cost in clusters.
  • Keeps message volume on the local shard's bus.
  • Subscribers on other shards never see the message.

The implementation lives in src/pubsub.c alongside the regular code, but the dispatch consults the cluster's slot owner to refuse cross-shard publishes.

Replication

Pub/Sub messages are not replicated. Replicas don't see the publish stream. This was a deliberate design choice — Pub/Sub's semantics are "fire and forget" and replication adds nothing.

The cluster bus, on the other hand, propagates regular Pub/Sub messages between nodes when a subscriber on a different node has matching subscriptions. Sharded Pub/Sub doesn't propagate.

Keyspace notifications

notify-keyspace-events <flags> enables Pub/Sub messages on data mutations:

  • __keyspace@<dbid>__:<key> channel emits the event name (e.g. del, expired, set).
  • __keyevent@<dbid>__:<event> channel emits the key that experienced the event.

Flag letters select event categories: K (keyspace), E (keyevent), g (generic — del, expire, rename), $ (string), l (list), s (set), h (hash), z (zset), x (expired), e (evicted), t (stream), d (module), m (key-miss), A (alias for g$lshzxe).

The implementation is notifyKeyspaceEvent in src/notify.c. Callers in the type implementations invoke it after a successful mutation:

notifyKeyspaceEvent(NOTIFY_GENERIC, "del", c->argv[1], c->db->id);

Client tracking

Client-side caching (CLIENT TRACKING ON/OFF) lets a client cache the values of keys it has fetched, with the server proactively pushing an "invalidation" message when a key changes. The client doesn't need to TTL its cache or poll — it follows the server's signal.

There are two modes:

  • Default mode — the server tracks per-key per-client which clients have read which keys. On mutation, every interested client receives an invalidation.
  • Broadcast mode (BCAST) — the client subscribes to one or more prefix patterns (PREFIX user:); whenever any key matching a prefix changes, every BCAST subscriber for that prefix is notified. No per-key bookkeeping.

The invalidation message arrives on a separate connection identified by CLIENT TRACKING ON REDIRECT <client-id> (RESP2 mode), or as an inline RESP3 push frame.

src/tracking.c implements both modes, the prefix table, and the per-key inverted index (server.tracking_table).

CLIENT TRACKINGINFO returns the current tracking state.

Blocking commands

BLPOP, BRPOP, BLMPOP, BLMOVE, BRPOPLPUSH, BZPOPMIN, BZPOPMAX, BZMPOP, XREAD BLOCK, XREADGROUP BLOCK, WAIT, WAITAOF, SUBSCRIBE-state, MIGRATE and a few module-defined commands all block the client until either:

  • The condition that the command is waiting for becomes true (a list gets pushed to, a stream gets a new entry, a replica catches up).
  • A timeout fires (per-command argument or default).

The implementation uses a blocked client state on client.bstate. The blocking command sets the state, returns from the handler without sending a reply, and the cron scans periodically. When the condition is met (e.g. a new LPUSH arrives), the producer's command path calls into signalKeyAsReady and the blocked client is unblocked, the original command re-run on the main thread.

src/blocked.c holds the lifecycle: blockClient, unblockClient, processUnblockedClients, the per-key wait list. src/timeout.c runs the per-block timeout sweeper.

Where to start modifying

  • Add a Pub/Sub variant — the dispatch in subscribeCommand / publishCommand is a small switch in src/pubsub.c.
  • Add a keyspace event letter — extend the NOTIFY_* flags in src/server.h and the parser in keyspaceEventsFlagsToString/StringToFlags in src/notify.c.
  • Tighten tracking memorytracking-table-max-keys caps the inverted index size; the eviction policy is in trackingRememberKeys.
  • Implement a blocking command — the canonical pattern is blockForKeys followed by replyToBlockedClientTimedOut and a serveClientBlockedOnList-style ready callback.
  • Networking — clients carry the Pub/Sub state.
  • ModulesRedisModule_BlockClient is the blocking-command primitive for modules.
  • Cluster — sharded Pub/Sub is cluster-aware.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Pub/Sub & client tracking – Redis wiki | Factory