Redis's CLIENT TRACKING supports a default per-key mode and a BCAST mode with key prefixes. Compare them, and explain what determines which one you would enable.
answer
- default = remember key→clients, precise, bounded table
- BCAST = remember prefixes only, broadcast, noisy
- tracking-table-max-keys full → spurious invalidations
- empty prefix = every write in the keyspace
- prefixes must be disjoint; NOLOOP kills self-echo
basics
~20 sDefault mode: the server remembers which keys each connection read and invalidates precisely — accurate, but it costs a bounded server-side table that can overflow. BCAST: the server remembers nothing per key and instead broadcasts invalidations for registered key prefixes — zero per-key memory, but clients receive messages for keys they never cached.
solid answer
~60 s**Default (per-key) mode** keeps a global invalidation table mapping key → interested client IDs. Invalidations are precise: you only hear about keys you read. Costs: server memory proportional to distinct tracked keys, capped by `tracking-table-max-keys` (default 1,000,000); when the cap is hit Redis evicts entries and sends invalidations for them, so clients see spurious messages anyway. Memory grows with the number of clients times their working sets. **BCAST mode** (`CLIENT TRACKING on BCAST PREFIX user: PREFIX cfg:`) stores no per-key state at all. The server keeps only the registered prefixes and broadcasts an invalidation for any modified key matching them, to every client registered on that prefix. Server memory is O(prefixes), not O(keys). The cost is client-side noise: you receive invalidations for keys you never cached, and with an empty prefix you receive every write in the keyspace. Choose by shape: **narrow, unpredictable key sets and few clients → default**; **a well-defined prefix with a high read/write ratio, or very many clients whose combined working set would blow the tracking table → BCAST with tight, non-overlapping prefixes**. Both benefit from `NOLOOP` to suppress the echo of your own writes.
code
text · 10 linesHELLO 3
CLIENT TRACKING on BCAST PREFIX cfg: PREFIX flags: NOLOOP
OK
# invalidations now arrive for ANY key starting with cfg: or flags:,
# whether or not this client ever read it; NOLOOP suppresses this
# client's own writes.
# overlapping prefixes are rejected:
CLIENT TRACKING on BCAST PREFIX user: PREFIX user:profile:
(error) ERR Prefix 'user:profile:' overlaps with an existing prefixgo deeper
Know the one-line difference: default tracks the exact keys you read, BCAST broadcasts by key prefix and needs no per-key server state.
Explain the tracking table and its cap, what BCAST trades away, and that an empty prefix means the entire keyspace.
Pick a mode from concrete numbers — distinct cached keys across the fleet versus write rate under the candidate prefix — and mention NOLOOP, disjoint prefixes, and per-node registration in cluster mode.
Own it as a capacity decision on shared infrastructure: how much server RAM the tracking table may consume, which key prefixes are broadcast-eligible, and how the choice degrades under fleet growth.
## Two ways to answer "who cares about this key?" When a key changes, the server must decide which clients to notify. There are only two strategies, and Redis implements both. **Remember** which clients read which keys — precise, costs memory. **Guess by name** — free, imprecise. Default mode is the first; BCAST is the second. ## Default mode mechanics A single global **invalidation table** maps each tracked key name to the set of client IDs that read it. Note it is per-server, not per-client: if 500 connections read `cfg:flags`, that is one table entry with 500 interested clients, not 500 entries. Sizing is bounded by `tracking-table-max-keys` (default 1,000,000). Once full, Redis makes room by evicting random entries — and, because it must never leave a client believing a stale value is fresh, it **sends an invalidation for each evicted key**. So a saturated table degrades gracefully into over-invalidation: correctness holds, hit ratio suffers. Raising the cap trades server memory for fewer spurious drops; lowering it does the opposite. What drives table size is the number of **distinct keys** the whole fleet reads and caches, not the number of clients. A thousand processes reading the same 200 config keys is trivial; fifty processes each caching a different 100k user objects is 5 million entries and will thrash. Precision is the payoff: a client is only woken for keys it actually asked about, so every invalidation it receives is one it needed. ## BCAST mode mechanics `CLIENT TRACKING on BCAST PREFIX user: PREFIX cfg:` registers **interest by name prefix**. The server holds only a small prefix table. On every write, it checks the modified key name against the registered prefixes and pushes an invalidation to all clients registered for a matching prefix — regardless of whether they ever read that key. Consequences: - **Server memory is O(number of registered prefixes)** and independent of the keyspace or the clients' working sets. This is the entire point: BCAST cannot overflow the way the tracking table can. - **Clients receive noise.** If you register `user:` and cache 50 user objects while the system writes 20k user keys per second, you get 20k pushes per second, discard nearly all, and pay the bandwidth and parsing cost. The read/write ratio of the prefix, not of your subset, determines whether this is acceptable. - **An empty prefix means everything.** `CLIENT TRACKING on BCAST` with no PREFIX registers the empty prefix and you receive an invalidation for every write in the keyspace. Occasionally that is what you want (a tiny keyspace, a control-plane cache); usually it is an accident with severe consequences on a busy instance. - **Prefixes must not overlap** for the same client. Registering both `user:` and `user:profile:` is rejected, because a single write would otherwise be signalled twice under the same subscription; keep prefixes disjoint. - **Invalidations are batched** by the server within an event-loop cycle where possible, which softens the cost of a write burst compared with a naive one-message-per-write model. BCAST is also the natural fit when the client library wants tracking without per-command bookkeeping — hence its incompatibility with OPTIN/OPTOUT, which are per-command mechanisms with nothing to attach to when the server keeps no per-key state. ## The selection criteria Ask four questions. 1. **Can you name the cacheable set with a prefix?** If your locally cached keys share a clean prefix (`cfg:`, `flags:`, `catalog:meta:`), BCAST is available. If they are scattered across the keyspace, default mode is your only precise option. 2. **What is the write rate under that prefix versus the size of your cached subset?** BCAST cost scales with writes under the *prefix*; benefit scales with your *subset*. A prefix with a high write rate and a small cached subset is the worst case — you get all the noise for little gain. 3. **How large is the fleet's distinct cached-key set?** Multiply distinct keys across all clients. Approaching or exceeding `tracking-table-max-keys` means default mode is already degrading into spurious invalidations, and BCAST with a tight prefix becomes more predictable. 4. **How much server memory can you give it?** Every table entry is server RAM that is not holding cached data. On a memory-pressured instance BCAST's O(prefixes) footprint is compelling. A common landing spot: BCAST with narrow prefixes for small, hot, low-write reference data (configuration, feature flags, entitlement tables), and default mode with OPTIN for scattered per-entity caching. ## Shared operational concerns - **NOLOOP** in either mode suppresses invalidations caused by the client's own writes — pure saving when the writer already updates its own copy. - **Reconnect means flush.** Anything that changed while the connection was down was never delivered, in both modes. - **Cluster:** tracking is established per node connection, so prefixes must be registered on every node a client talks to, and a prefix's keys may live on many nodes. - **Measure it.** `CLIENT TRACKINGINFO` shows the mode and prefixes; `INFO clients`/`INFO memory` and the tracking-related fields let you watch table size. If you cannot see the invalidation rate your client is discarding, you cannot tell whether BCAST is paying.
- What happens when the server's tracking table reaches tracking-table-max-keys?Redis evicts entries to make room and sends an invalidation message for each evicted key, because it must never leave a client believing a stale local copy is still valid. Correctness is preserved and the local hit ratio degrades instead. A table that is chronically saturated is a signal to raise the cap, narrow what is tracked with OPTIN, or move to BCAST with a tight prefix.
- What is the danger of enabling BCAST without specifying any PREFIX?No prefix means the empty prefix, which matches every key, so the client receives an invalidation for every write in the entire keyspace. On a busy instance that is a large, continuous stream of push messages the client parses and mostly discards, consuming bandwidth and client CPU. Always register the narrowest prefixes that cover the keys you actually cache.
- Which mode scales better with a large fleet of application instances?BCAST, in server memory terms: its footprint is proportional to the number of registered prefixes, not to keys or clients, so it cannot overflow the tracking table. Default mode's table is keyed by distinct key names across the whole fleet, so many processes caching different entities can saturate it. The tradeoff is that BCAST pushes each matching write to every registered client, so its cost grows with the write rate under the prefix.
- What does NOLOOP do and when is it worth setting?It suppresses invalidation messages for keys modified by the very client that would receive them. It is worth setting whenever your writers also hold the local cache, because the writer already knows it changed the value and can update or drop its own copy directly. It removes a whole class of pointless round-trip traffic at no correctness cost.
Default mode is a subscription list per article; BCAST is a notice board for a whole section — nothing to maintain per article, but you read a lot of notices that were not about your article.
saying these in an interview costs you the question
- Claiming BCAST is strictly better because it uses no server memory, ignoring the client-side push volume.
- Enabling BCAST with no PREFIX and being surprised by keyspace-wide invalidation traffic.
- Believing a full tracking table silently loses invalidations rather than over-invalidating.
- Registering overlapping prefixes and expecting Redis to deduplicate them.
- Sizing default mode by client count rather than by the number of distinct cached keys across the fleet.