Since Redis 3.0 the eviction code keeps a persistent pool of candidate keys instead of simply evicting the best key of each random sample. How does that pool work, and what problem did it fix?
answer
- 16-slot pool, sorted by score
- sample merges into the pool, worst displaced
- good candidates survive across rounds
- 5 samples with pool ~ 10 samples without
- pooled entries re-validated before eviction
basics
~20 sRedis keeps a small array of the best eviction candidates seen so far, sorted by idle time. Each round's random sample is merged into that pool, and the pool's best entry is evicted. The pool remembers good candidates across rounds, so quality no longer depends on one lucky sample.
solid answer
~50 sBefore 3.0 each eviction round sampled N keys and evicted the idlest of that sample; a good candidate seen in an earlier round was simply forgotten. Redis 3.0 added an eviction pool: a fixed-size array (16 entries) of candidate keys ordered by score - idle time under LRU, inverse frequency under LFU. Each round samples `maxmemory-samples` keys and inserts them into the pool, keeping only the best 16 across all rounds; a candidate is dropped if the pool is full and it is worse than everything in it. Redis then evicts the pool's best entry and removes it, re-validating that the key still exists. The effect is that the pool accumulates the idlest tail of the keyspace over successive rounds, so with only 5 samples per round the decisions approach the quality that pure sampling needed roughly 10 samples to reach - accuracy without paying for a bigger sample on every round.
go deeper
It is enough to know Redis remembers a short list of good eviction candidates between rounds rather than restarting from a fresh random sample each time.
Describe the fixed-size sorted pool, how samples are merged into it, and why that improves accuracy without raising the sample size.
Add the operational nuances: stale entries revalidated at eviction time, the pool spanning databases, and the fact that accuracy still bottlenecks on what sampling surfaces.
Generalise it as a bounded-memory approximation pattern - accumulate the best candidates seen over time instead of buying accuracy per decision - and judge when that heuristic is acceptable for the system being designed.
## The weakness of memoryless sampling The original approximation was memoryless: sample N keys, evict the idlest of the N, throw the rest away. If a round happened to surface an extremely idle key in second place, that knowledge was discarded and the next round started from scratch. The quality of every decision was therefore bounded by the quality of one small random draw, and the only tuning knob was to make every draw bigger, which costs CPU on the single command-execution thread on every eviction. ## What the pool adds Redis 3.0 introduced a persistent candidate structure, the eviction pool: a fixed array of 16 slots, each holding a key name, its database, and a score. The score is a monotone "how evictable is this" value - estimated idle time for the LRU policies, and a value derived from the inverse of the frequency counter for LFU, so that in both cases the highest score is the best victim. The array is kept sorted, so inserting a candidate is a small ordered insert and the best candidate is always at a known end. Each eviction round does the following: 1. Sample `maxmemory-samples` random keys from the policy's candidate dictionary. 2. Compute each sampled key's score and try to insert it into the pool; if the pool is full, the worst existing entry is displaced only when the newcomer is better. 3. Walk the pool from the best entry down, look the key up in the dictionary to confirm it still exists (it may have been deleted, expired or already evicted since it entered the pool), and evict the first one that does, removing it from the pool. 4. If memory is still above `maxmemory`, repeat. Because the pool survives between rounds, good candidates found earlier stay available. Over a burst of eviction the pool converges on the genuinely idle tail of the keyspace, so the outcome is much closer to true LRU than the sample size alone would suggest. This is why the documented accuracy of Redis 3.0 with 5 samples is comparable to Redis 2.8 with 10, and why the default was able to stay at 5. ## Details that matter in practice - The pool is per-instance eviction state, not per-database; each entry records which database the key came from, since eviction may span databases. - Entries are stale by design. A key can be modified, deleted or expire while sitting in the pool, which is why the eviction step re-validates before deleting - a pooled key is a hint, not a reservation. - The pool does not remove the randomness. It biases the search toward already-seen good candidates but still only ever sees keys that random sampling surfaced, so a key that is never sampled is never evicted no matter how idle it is. - Under LFU the same structure is reused; only the scoring function changes, which is why the tuning story (sample size versus CPU) is identical for both families. ## Why an interviewer asks this It separates candidates who have read how Redis eviction actually behaves from those who repeat "it samples five keys". The useful takeaway is the general technique: when exact global ordering is too expensive, keep a bounded window of the best candidates seen so far and refresh it incrementally, so accuracy accumulates over time instead of being re-purchased on every decision.
- Can a key sitting in the eviction pool disappear before it is evicted?Yes, and Redis handles it. A pooled entry is only a name plus a score, so between insertion and eviction the key may have been deleted by a client, expired, or evicted already. The eviction step looks the key up again and skips entries that no longer resolve, moving on to the next best candidate.
- Does the pool remove the need to tune maxmemory-samples?No, it shifts the curve rather than flattening it. The pool can only rank keys that sampling actually surfaced, so a larger sample still feeds it better candidates and gets closer to true LRU. The pool is why the default of 5 is good enough for most caches instead of needing 10.
Instead of judging each random handful on its own, you keep a shortlist of the sixteen dustiest boxes you have ever pulled, and every new handful can only bump something off that shortlist.
saying these in an interview costs you the question
- Describing the pool as a full ordered index of the keyspace rather than a bounded 16-entry shortlist
- Claiming the pool makes Redis eviction exact LRU
- Assuming a key placed in the pool is guaranteed to be the next one deleted
- Confusing the eviction pool with the expires dictionary used by TTL scanning