Comprehensive Overview of Redis: Data Types, Structures, Use Cases, Persistence, Replication, and More
This article provides an in‑depth guide to Redis, covering its core data types, internal data structures, common usage scenarios, differences from Memcached, key expiration, eviction policies, persistence mechanisms, transactions, event handling, replication, Sentinel, sharding, and a practical forum system example.
Overview
Redis is a high‑performance, non‑relational (NoSQL) in‑memory key‑value store that maps keys to five different value types.
Keys are strings; values can be STRING, LIST, SET, HASH, or ZSET. Redis supports features such as persistence, replication for read scaling, and sharding for write scaling.
Data Types
Data Type
Storable Value
Operations
STRING
String, integer or float
Operate on whole string or part; increment/decrement integers and floats
LIST
List
Push/pop from both ends; trim ranges; access elements
SET
Unordered set
Add, get, remove elements; membership test; set operations; random member
HASH
Unordered hash table of key‑value pairs
Add, get, delete single fields; retrieve all fields; existence check
ZSET
Ordered set
Add, get, delete members; range queries by score or member; rank calculation
STRING Example
> set hello world
OK
> get hello
"world"
> del hello
(integer) 1
> get hello
(nil)LIST Example
> rpush list-key item
(integer) 1
> rpush list-key item2
(integer) 2
> rpush list-key item
(integer) 3
> lrange list-key 0 -1
1) "item"
2) "item2"
3) "item"
> lindex list-key 1
"item2"
> lpop list-key
"item"
> lrange list-key 0 -1
1) "item2"
2) "item"SET Example
> sadd set-key item
(integer) 1
> sadd set-key item2
(integer) 1
> sadd set-key item3
(integer) 1
> sadd set-key item
(integer) 0
> smembers set-key
1) "item"
2) "item2"
3) "item3"
> sismember set-key item4
(integer) 0
> sismember set-key item
(integer) 1
> srem set-key item2
(integer) 1
> srem set-key item2
(integer) 0
> smembers set-key
1) "item"
2) "item3"HASH Example
> hset hash-key sub-key1 value1
(integer) 1
> hset hash-key sub-key2 value2
(integer) 1
> hset hash-key sub-key1 value1
(integer) 0
> hgetall hash-key
1) "sub-key1"
2) "value1"
3) "sub-key2"
4) "value2"
> hdel hash-key sub-key2
(integer) 1
> hdel hash-key sub-key2
(integer) 0
> hget hash-key sub-key1
"value1"
> hgetall hash-key
1) "sub-key1"
2) "value1"ZSET Example
> zadd zset-key 728 member1
(integer) 1
> zadd zset-key 982 member0
(integer) 1
> zadd zset-key 982 member0
(integer) 0
> zrange zset-key 0 -1 withscores
1) "member1"
2) "728"
3) "member0"
4) "982"
> zrangebyscore zset-key 0 800 withscores
1) "member1"
2) "728"
> zrem zset-key member1
(integer) 1
> zrem zset-key member1
(integer) 0
> zrange zset-key 0 -1 withscores
1) "member0"
2) "982"Data Structures
Dictionary (hash table)
/* This is our hash table structure. Every dictionary has two of this as we
* implement incremental rehashing, for the old to the new table. */
typedef struct dictht {
dictEntry **table;
unsigned long size;
unsigned long sizemask;
unsigned long used;
} dictht; typedef struct dictEntry {
void *key;
union {
void *val;
uint64_t u64;
int64_t s64;
double d;
} v;
struct dictEntry *next;
} dictEntry;Redis uses two hash tables (dictht) to enable incremental rehashing, moving keys bucket‑by‑bucket from the old table to the new one without blocking the server.
int dictRehash(dict *d, int n) {
int empty_visits = n * 10; /* Max empty buckets to visit */
if (!dictIsRehashing(d)) return 0;
while (n-- && d->ht[0].used != 0) {
while (d->ht[0].table[d->rehashidx] == NULL) {
d->rehashidx++;
if (--empty_visits == 0) return 1;
}
dictEntry *de = d->ht[0].table[d->rehashidx];
while (de) {
uint64_t h;
dictEntry *nextde = de->next;
h = dictHashKey(d, de->key) & d->ht[1].sizemask;
de->next = d->ht[1].table[h];
d->ht[1].table[h] = de;
d->ht[0].used--;
d->ht[1].used++;
de = nextde;
}
d->ht[0].table[d->rehashidx] = NULL;
d->rehashidx++;
}
if (d->ht[0].used == 0) {
zfree(d->ht[0].table);
d->ht[0] = d->ht[1];
_dictReset(&d->ht[1]);
d->rehashidx = -1;
return 0;
}
return 1;
}Skip List
Skip lists implement ordered sets (ZSET) and provide fast insertion, search, and range queries using multiple forward pointers.
Use Cases
Counter
STRING values can be incremented/decremented to implement high‑throughput counters.
Cache
Hot data can be stored in memory with configurable max memory and eviction policies to achieve high cache hit rates.
Lookup Table
Static data such as DNS records can be stored in Redis for fast lookups; unlike caches, lookup tables are not expected to expire.
Message Queue
LIST can act as a simple queue via LPUSH/RPOP, though dedicated brokers like Kafka or RabbitMQ are preferred for production.
Session Store
Redis can centralize session data across multiple application servers, enabling stateless web servers and easy horizontal scaling.
Distributed Lock
SETNX (or the RedLock algorithm) provides a way to acquire locks across distributed nodes.
Other
SET enables set operations (intersection, union) for features like mutual friends; ZSET enables ranking and leaderboards.
Redis vs. Memcached
Memcached only supports strings and lacks persistence, while Redis offers five data types, RDB/AOF persistence, native clustering, and richer memory management.
Key Expiration
Each key can have a TTL; when the TTL expires Redis automatically deletes the key.
Eviction Policies
When max memory is reached Redis can evict keys using policies such as volatile‑lru, volatile‑ttl, volatile‑random, allkeys‑lru, allkeys‑random, noeviction, and the newer LFU‑based policies.
Persistence
RDB
Snapshots the entire dataset at intervals; useful for backups but may lose recent writes.
AOF
Appends every write command to a log; configurable sync options (always, everysec, no) balance durability and performance.
Transactions
Multiple commands can be wrapped in MULTI/EXEC to execute atomically; pipelining reduces round‑trip latency.
Events
File Events
Redis uses a Reactor pattern with I/O multiplexing to handle socket events.
Time Events
Scheduled tasks (one‑off or periodic) are stored in an unordered list and processed when their time arrives.
def aeProcessEvents():
time_event = aeSearchNearestTimer()
remaind_ms = time_event.when - unix_ts_now()
if remaind_ms < 0:
remaind_ms = 0
timeval = create_timeval_with_ms(remaind_ms)
aeApiPoll(timeval)
procesFileEvents()
processTimeEvents() def main():
init_server()
while server_is_not_shutdown():
aeProcessEvents()
clean_server()Replication
Slave servers synchronize with a master using snapshots and a command buffer; a master‑slave chain can be built for scaling.
Sentinel
Monitors Redis instances and performs automatic failover by electing a new master when the current one goes down.
Sharding
Data can be partitioned across multiple nodes via range sharding, hash sharding (e.g., CRC32), or using Redis Cluster (server‑side sharding).
Simple Forum System Analysis
Articles are stored as HASHes (e.g., article:92617); likes are tracked with a SET of voted users and a ZSET for ranking by timestamp or vote count.
References
Carlson J L. Redis in Action. 2013.
黄健宏. Redis 设计与实现. 机械工业出版社, 2014.
REDIS IN ACTION
Skip Lists: Done Right
论述 Redis 和 Memcached 的差异
Redis 3.0 中文版- 分片
Redis 应用场景
Using Redis as an LRU cache
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Selected Java Interview Questions
A professional Java tech channel sharing common knowledge to help developers fill gaps. Follow us!
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
