Stage 3 · Build
Redis
Redis Data Types
Strings, lists, sets, hashes, sorted sets, streams — choosing the right type.
Strings
Strings are the most basic Redis data type. They can hold text, integers, floating-point numbers, or binary data up to 512MB. Strings support atomic operations like increment, append, and range queries.
SET user:1:name "Alice Chen"
GET user:1:name # "Alice Chen"
SET counter 0
INCR counter # 1
INCRBY counter 10 # 11
SET session:abc123 '{"user_id": 1}' EX 3600 # expire in 1 hour
GET session:abc123 # '{"user_id": 1}'
TTL session:abc123 # remaining seconds
MSET key1 val1 key2 val2 key3 val3 # bulk set
MGET key1 key2 key3 # bulk getUse strings for simple key-value pairs, counters, session storage, and caching. The EX parameter sets a TTL (time-to-live) in seconds — the key is automatically deleted after expiration.
Use colon-separated namespaces: user:1:profile, order:42:items, cache:products:list. This makes keys readable and enables KEYSPACE NOTIFICATIONS and SCAN patterns.
Hashes
Hashes store maps of field-value pairs. They are memory-efficient for storing objects because Redis uses a compact encoding when the hash has few fields.
HSET user:1 name "Alice Chen" email "alice@example.com" role "admin"
HGET user:1 name # "Alice Chen"
HMGET user:1 name email # ["Alice Chen", "alice@example.com"]
HGETALL user:1 # {"name": "Alice Chen", "email": "...", "role": "admin"}
HINCRBY user:1 login_count 1 # atomic increment
HDEL user:1 email # delete field
HEXISTS user:1 name # 1 (true)
HLEN user:1 # 2 (field count)
-- Use hash for partial updates instead of replacing entire object
HSET user:1 role "superadmin" # update only roleHashes are ideal for storing objects where you frequently read or update individual fields. Unlike strings, you do not need to serialize/deserialize the entire object for each field access.
Lists
Lists are ordered collections of strings with O(1) push and pop operations at both ends. They implement a doubly-linked list backed by a quicklist (ziplist + linked list) for memory efficiency.
LPUSH notifications:1 "New order" "Payment received" # push to head
RPUSH queue:tasks "task1" "task2" "task3" # push to tail
LPOP notifications:1 # "Payment received" (most recent)
RPOP queue:tasks # "task1" (FIFO order)
BRPOP queue:tasks 30 # blocking pop — waits 30s for data
LLEN queue:tasks # 2 (length)
LRANGE queue:tasks 0 -1 # ["task2", "task3"] (all elements)
LINDEX queue:tasks 0 # "task2" (element at index)
LTRIM queue:tasks 0 99 # keep only first 100 elementsBRPOP is the foundation of simple job queues — workers block until a job appears. LTRIM implements a bounded list (ring buffer) by discarding old entries.
Sets
Sets are unordered collections of unique strings with O(1) membership testing. They support mathematical operations like intersection, union, and difference.
SADD tags:post:1 "redis" "database" "caching"
SADD tags:post:2 "redis" "performance"
SMEMBERS tags:post:1 # ["redis", "database", "caching"]
SISMEMBER tags:post:1 "redis" # 1 (true)
SCARD tags:post:1 # 3 (count)
-- Find posts with both "redis" and "database" tags
SINTER tags:post:1 tags:post:2 # ["redis"] (intersection)
-- Find posts with "redis" but not "database"
SDIFF tags:post:1 tags:post:2 # ["database", "caching"] (difference)
-- Combine tags from both posts
SUNION tags:post:1 tags:post:2 # ["redis", "database", "caching"]
-- Random sample
SRANDMEMBER tags:post:1 2 # 2 random tagsSets are perfect for tags, unique visitor tracking, and membership testing. SINTER implements AND logic, SDIFF implements NOT logic, and SUNION implements OR logic on collections.
Sorted Sets
Sorted sets are ordered collections where each element has a score. They combine the uniqueness of sets with ordering by score, enabling range queries and leaderboards.
-- Leaderboard: score is the points earned
ZADD leaderboard 1500 "alice" 2100 "bob" 1800 "carol"
ZRANK leaderboard "bob" # 1 (0-indexed, highest score first)
ZREVRANK leaderboard "bob" # 1 (from highest to lowest)
ZSCORE leaderboard "bob" # 2100
ZREVRANGE leaderboard 0 2 WITHSCORES # top 3 with scores
-- Range query: users with score between 1000 and 2000
ZRANGEBYSCORE leaderboard 1000 2000
-- Increment score
ZINCRBY leaderboard 50 "alice" # alice: 1550
-- Remove member
ZREM leaderboard "carol"
-- Count members in score range
ZCOUNT leaderboard 1000 2000 # 2Sorted sets are the go-to data type for leaderboards, rate limiting windows, priority queues, and time-series data where you need range queries by score or timestamp.
Store events with timestamp as score: ZADD events 1718450000 event_data. Then query by time range: ZRANGEBYSCORE events 1718440000 1718450000. This is simpler and faster than a dedicated time-series database for moderate volumes.
Streams
Streams are append-only logs with consumer groups. They are Redis's answer to Kafka — durable, ordered, and支持 multiple consumers processing different portions of the stream.
-- Add events to stream
XADD orders * user_id 1 product "widget" quantity 5
XADD orders * user_id 2 product "gadget" quantity 2
-- Read from stream
XRANGE orders - + COUNT 10 # first 10 events
XRANGE orders 1718450000000-0 + # from timestamp onward
-- Consumer groups for parallel processing
XGROUP CREATE orders workers 0
-- Consumer reads unacknowledged events
XREADGROUP GROUP workers consumer1 COUNT 10 BLOCK 5000 STREAMS orders >
-- Acknowledge processed events
XACK orders workers 1718450000000-0Streams provide at-least-once delivery semantics. Events are retained until explicitly deleted or the stream is trimmed. Consumer groups enable horizontal scaling of event processing.
Strings for simple values and counters. Hashes for objects with multiple fields. Lists for ordered collections and queues. Sets for unique memberships. Sorted sets for ranked data and time ranges. Streams for event logs and messaging.
Mark this lesson complete to store local progress and unlock a cleaner resume path the next time you visit.