Key-value stores
There are no tables and no namespaces, so every bit of structure you want has to be encoded in the key itself. That is the trade — the store stops organising your data and in exchange stops needing to know anything about it.
Nothing here is filed like a library shelf. It is a vast wall of numbered pigeonholes with no sections and no floor plan: finding anything is instant if you know the number, and grouping things at all means agreeing on how the numbers are written, because the wall will never do it for you.
A key-value store gives up almost everything a relational database offers — no tables, no joins, no schema, no query planner — and gets a very fast lookup in return. What makes that trade interesting is not the speed, which is easy to predict, but where the structure you gave up has to reappear.
A flat key space, on purpose#
Every value is reached by exactly one key, and the keys live in one flat space. Redis states the consequence rather than glossing it: it does not support namespaces or other categories for keys, so you must take care to avoid name collisions. There is no layer that will keep two parts of your application from choosing the same name, because there is no layer at all.
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 it means a restart cannot resurrect data that should have aged out.
Building on that is what separates a store from a cache that evicts by how recently something was used. Eviction is the store deciding what to drop under memory pressure; expiry is you declaring how long a fact remains true. Sessions, tokens and rate-limit counters are all statements of the second kind, and putting the lifetime on the key is what keeps that statement in one place.
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.
The replacement carries a caveat that has to be understood rather than skipped. SCAN iterates incrementally, returning a small number of elements per call so the server stays responsive, and in exchange it offers only limited guarantees, because the collection being iterated can change while you iterate it. Anything treating a scan as an exact inventory is wrong on a busy database — not occasionally, but in proportion to how much else is happening.
Both failures come from the same place. A flat key space with no query layer means every question except “what is at this key” has to be answered by walking the keys, and walking the keys is the one thing the design is not built for. If you find yourself scanning to answer a question, the store is telling you the answer wanted a different structure — a set, an index maintained alongside the data, or a different database entirely.
IF YOU REMEMBER ONE THING
Giving up the schema does not remove it; it moves it into your key names, where nothing checks it. Any question you cannot answer from a key alone is a sign the shape of the data has outgrown the store.
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 and returns a small number of elements per call.
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.