Topic 1.1
Strings: Values, Counters, and Conditional Writes
In one line
A Redis string is a binary-safe byte array up to 512 MB. It holds cached blobs, integers you can increment atomically, and flags you can set conditionally with an expiry, which makes it the building block for counters, locks and rate limiters.
Think of it like this
A numbered ticket dispenser at a deli counter. Two customers can press the button at exactly the same moment and still get different numbers, because the machine hands them out one at a time. INCR is that machine: no matter how many app servers call it concurrently, every caller gets a unique, ordered number.
Key ideas
- 01
Core commands:
SET,GET,MSET/MGET(many keys in one round trip),INCR/INCRBY/DECR/INCRBYFLOAT,APPEND,STRLEN,GETRANGE/SETRANGE,GETDELandGETEX(6.2). All single-key operations are O(1) except range operations, which are O(length). - 02
SEThas options that replace older commands:NX(only if absent, replacesSETNX),XX(only if present),EX/PX/EXAT/PXAT(expiry),KEEPTTL(don't reset the TTL on overwrite), andGET(return the old value, replaces the deprecatedGETSET).SET lock:job token NX PX 30000is one atomic command for "create with expiry if absent", the basis of locks (Topic 12.1). - 03
Integers are stored efficiently: a string that looks like a 64-bit signed integer uses the
intencoding.INCRon a missing key starts from 0. Going past the range returnsERR increment or decrement would overflow, so overflow is an error, never a silent wrap-around. Shared integer objects (0–9999) cost no extra memory. - 04
Other encodings:
embstrfor short strings (up to 44 bytes, stored in one allocation with the object header) andrawfor longer ones.OBJECT ENCODING keyshows which one you have. Values have a hard limit of 512 MB, but anything over about 100 KB is a big-key smell (Topic 13.2). - 05
Atomicity: every command is atomic, so
INCRis safe from any number of clients. But a sequence likeGETthenSETis not atomic; another client can write between them. Use one command,SET ... NX/XX/GET,WATCH, or Lua (Phase 3) when correctness depends on the previous value. - 06
A common trap:
SET key valuewithoutKEEPTTLremoves any existing TTL. Code that updates a cached value and forgets the expiry turns a cache entry into a permanent key.
Code & diagrams
127.0.0.1:6379> SET product:123:views 0
OK
127.0.0.1:6379> INCR product:123:views
(integer) 1
127.0.0.1:6379> INCRBY product:123:views 10
(integer) 11
127.0.0.1:6379> SET feature:dark-mode on NX EX 60
OK
127.0.0.1:6379> SET feature:dark-mode off NX EX 60
(nil) # already exists, nothing written
127.0.0.1:6379> SET cfg:rate 100 EX 300
OK
127.0.0.1:6379> SET cfg:rate 200 KEEPTTL
OK
127.0.0.1:6379> TTL cfg:rate
(integer) 294 # TTL kept
127.0.0.1:6379> SET cfg:rate 300
OK
127.0.0.1:6379> TTL cfg:rate
(integer) -1 # TTL silently removed
127.0.0.1:6379> SET counter 9223372036854775807
OK
127.0.0.1:6379> INCR counter
(error) ERR increment or decrement would overflow
127.0.0.1:6379> MGET product:123:views cfg:rate missing
1) "11"
2) "300"
3) (nil)Many app servers, one counter, no lost updates: INCR runs one at a time on the server.
Interview problem
The problem
Page view counter at 1M requests/sec
Count product page views. Traffic peaks at 1 million requests per second across all products. The product page shows the view count. Start with the simple design, then handle a product going viral.
You're given
- 1M views/sec total
- Count shown on page
- Approximate counts are OK on the page
- Daily totals must be accurate for billing
The interviewer follows up
Why not just UPDATE products SET views = views + 1 in the database?
How would you count unique viewers instead of views?
When it breaks
Read-modify-write on a counter from multiple app servers
What you see
Two servers GET 41, both SET 42: one view is lost. Under load, counts drift far below reality and nobody sees an error.
Fix & prevent
Use INCR/INCRBY (atomic on the server), or Lua for more complex updates.
Cache update with plain SET removes the TTL
What you see
Keys that should expire live forever; memory creeps up until eviction or OOM errors start.
Fix & prevent
Use SET ... EX on every write or KEEPTTL when updating; audit with redis-cli --scan plus TTL sampling and alert on keys with no TTL in cache namespaces.
Explain it without notes
Why is INCR safe with 100 concurrent clients while GET + SET isn't?
What do SET options NX, XX, GET and KEEPTTL each do, and which old commands do they replace?
Practice
Implement a "login attempts" counter that locks an account after 5 failed attempts within 15 minutes, using only string commands.
Use OBJECT ENCODING on values "42", "hello" and a 100-character string. Explain each result.
Trade-offs
- ↔
One string holding a JSON blob vs a hash with fields: the string is simpler and you read it all at once; the hash lets you update single fields atomically and read part of the object (Topic 1.2).
- ↔
Exact counters on one hot key vs sharded or buffered counters: exactness and simplicity against write throughput.
Done when you can
I can use
SETwithNX,XX,EX,PX,KEEPTTLandGETcorrectly.I can design a high-throughput counter and fix the hot-key version.
I know when a string is
int,embstrorraw.