Key-value stores
See why a flat key space pushes structure into your naming, why expiry belongs to the data rather than your code, and the command that blocks a server.
A key-value API retrieves a value by its key. This page uses Redis: keys within one selected database use a naming convention, TTL declares lifetime, and SCAN walks incrementally. Other key-value systems can provide tables, namespaces, schemas and secondary indexes.
A key is a label on a box. Redis will find that box without understanding your label’s business meaning, so your application agrees on names such as user:1000. Other stores may also organise the boxes into tables or indexes.
A key-value API starts with retrieval by key; it does not imply that every product lacks tables, schemas or query features. Redis is the concrete example here. DynamoDB, for example, has tables, partition/sort keys and secondary indexes. First distinguish the access model from the capabilities of a particular store.
A flat key space, on purpose#
Within one selected Redis database, top-level key names share a naming space. A colon in a name is a convention, not an enforced nested namespace. Redis still has data structures such as hashes and sets, and database selection or clustering changes the scope you operate in. Agree on names so independent parts of an application do not overwrite the same key accidentally.
What fills that gap is convention. The documented one is a colon separating sections of the key — person:1, office:London — with the recommendation to stick to a schema such as object-type:id. That is worth recognising for what it is: the schema has not disappeared, it has moved out of the database and into a naming agreement that nothing enforces. Break it in one service and the store will cheerfully accept the result.
The advice on key length points the same way, and it cuts both ways. Very long keys are discouraged not only for memory but because looking one up may require several costly key comparisons — so hashing a large value is better than using it as a key. Very short keys are discouraged too: there is little point writing u1000flw when user:1000:followers costs little more and can be read by whoever finds it in a log. Underneath, the lookup is the same hashing arrangement any hash table uses, which is why the key’s own size shows up in the cost of finding it.
Expiry belongs to the data#
Most storage systems make lifetime someone else’s problem: rows persist until deleted, and anything time-bound needs a cleanup job. A key-value store commonly makes expiry a property of the key, so a value can be written with the instruction that it stops existing in ten seconds and no code is responsible for coming back for it.
The detail that decides whether you can rely on it is what happens while nothing is running. Redis persists and replicates expiry information by storing the date at which a key will expire, so — in its own words — the time virtually passes when the server remains stopped. A key with ten seconds left before a shutdown is gone when the server returns an hour later. That is the behaviour you want and not the one people assume, because, provided the host clock is correct, a restart does not revive a key whose expiry time has passed.
Expiry declares when the store must stop returning a key as live; eviction drops data under memory pressure. Neither proves that a cached fact stayed true until expiry: an upstream value can change earlier. Choose invalidation and freshness rules separately from the TTL. Physical removal of an expired key can also happen after its logical expiry. The LRU walkthrough distinguishes recency-based eviction from that time limit.
Advance the clock while the store is stopped
At t = 0, Redis stores a key with an absolute expiry at t = 10 seconds. Stop the server at t = 4. Predict whether restarting pauses the remaining lifetime.
Restart at t = 8: 2 seconds remain. Restart at t = 20: the stored expiry is already past; the key must not be returned as live.
One Redis expiry record, stable wall clock, successfully restored data. This is not durability testing or an eviction model. Clock jumps can change expiry behaviour; TTL does not prove that a cached value remained factually current.
Walking the whole key space#
The classic outage is a single command. KEYS matches a pattern across the whole key space and blocks the server until it has returned every match — Redis warns it should be used in production with extreme care, that it may ruin performance against large databases, and that it is intended for debugging rather than regular application code. It behaves perfectly on a development dataset of a hundred keys, which is exactly why it reaches production.
Redis SCAN uses a cursor and incremental calls, not a consistent snapshot. A call can return zero elements before the cursor finishes, and COUNT is a work hint rather than a strict result cap. A complete iteration may return duplicates. Keys present for the entire iteration are covered; keys added or removed during it have limited guarantees. Continue until the returned cursor is zero, and make processing duplicate-safe.
A full key scan is often the wrong access path for an application lookup. Redis sets, sorted sets and hashes can provide other operations, and some products offer search or secondary indexes. Design the structure around the question and maintain its consistency; do not infer that every query beyond a single key has outgrown all key-value stores.
IF YOU REMEMBER ONE THING
Giving up the schema does not remove it; it moves it into your key names, where nothing checks it. A recurring full scan is a reason to design an appropriate set, index or query path; it does not establish that every key-value product lacks one.
Questions people also ask
4 QUESTIONSHow should I name keys?
Pick a schema and hold to it, because nothing else will. Redis has no namespaces, so its documentation recommends the colon convention — object-type:id, as in user:1000 — and warns in both directions on length. A 1024-byte key is bad not only for memory but because lookup may require several costly comparisons, while u1000flw saves little against user:1000:followers and costs you readability.
Why is running KEYS in production a problem?
Because it blocks the server until every key has been returned. Redis documents it as a command to use with extreme care, intended for debugging and special operations rather than regular application code, and notes it may ruin performance against large databases. SCAN is the alternative — it iterates incrementally; COUNT is a hint, an intermediate call may return no matches and results may repeat.
Does SCAN give me a consistent snapshot?
No, and the documentation is explicit that it offers only limited guarantees, because the collection being iterated can change during the iteration. That is the price of not blocking. Code that treats a SCAN as an exact inventory will be wrong on a busy database, in ways that depend on what other clients happened to be doing.
What happens to expiry while the server is down?
It still elapses. Redis stores the date at which a key will expire, and that information is replicated and persisted, so — in its own phrasing — the time virtually passes while the server remains stopped. A key with ten seconds left before a shutdown is gone after an hour of downtime, which is the behaviour you want and not the one people assume.