Redis: Caching, Data Structures & Persistence
Single-threaded model, five core types, persistence RDB/AOF, eviction policies, clustering and common cache patterns.
Single-Threaded but Fast
Redis processes commands in one thread with epoll multiplexing: no locks, no context switches, and in-memory access dominates. Single-threaded refers to command execution — persistence, async deletion and I/O threads run separately. The ceiling is roughly 100k QPS per instance, which is why you scale with shards instead of CPU cores.
Five Core Types and Common Idioms
redis-cli # 连接本地
# String:计数器 / 分布式锁基础
SET token:abc 1 EX 3600 # 秒级过期
INCR article:42:views # 原子自增(阅读量)
INCRBY stock:sku7 -1 # 原子扣减库存
# Hash:对象字段
HSET user:7 name Alice age 30
HMGET user:7 name age
HINCRBY user:7 age 1
# List:简单消息队列
LPUSH queue:pay order:1
BRPOP queue:pay 5 # 阻塞 5 秒
# Set:去重 / 交并
SADD tags:42 hot sale
SISMEMBER tags:42 hot
SINTER set_a set_b # 共同好友
# ZSet:排行榜
ZADD rank 100 alice 90 bob 150 carol
ZREVRANK rank carol # 名次
ZINCRBY rank 5 alice
# 过期与扫除
EXPIRE user:7 3600
TTL user:7 # -1 永久 -2 不存在
KEYS * # ✗ 线上禁用(阻塞)
SCAN 0 MATCH user:* COUNT 100 # ✓ 游标分页
KEYS blocks the single thread — always use SCAN in production. One slow command freezes the entire instance.
Persistence: RDB and AOF
| 维度 | RDB 快照 | AOF 日志 |
|---|---|---|
| 原理 | 全量数据快照(fork 子进程) | 追加写命令(可重写压缩) |
| 数据完整性 | 周期性,崩溃丢最近一段 | fsync 策略决定(always 最稳) |
| 体积 | 紧凑小 | 较大(重写后变小) |
| 恢复速度 | 快 | 重放慢 |
| 适用 | 备份 / 冷备 / 低损失容忍 | 热数据 / 高安全 |
# 综合策略:RDB 兜底 + AOF 保近实时(推荐)
save 900 1
appendonly yes
appendfsync everysec # 每秒刷盘:崩溃最多丢 1 秒
auto-aof-rewrite-percentage 100
# 手动触发
redis-cli BGSAVE # 后台快照
redis-cli BGREWRITEAOF # 后台重写
# 数据恢复:把 dump.rdb / appendonly.aof 放数据目录启动即可
# 主从同步:首次全量 RDB 传输 + 后续命令流复制
replicaof 10.0.0.2 6379
Eviction and Memory
maxmemory 4gb
maxmemory-policy allkeys-lru
# noeviction 写满直接报错(默认,缓存场景不合适)
# allkeys-lru 全键 LRU(纯缓存首选)
# volatile-lru 仅设过期的键 LRU
# allkeys-lfu 全键 LFU(热点明显时更优)
# volatile-ttl 优先淘汰快过期的
# 查看内存明细
MEMORY STATS
INFO memory # used_memory / fragmentation_ratio
# 碎片率 > 1.5 考虑 activedefrag yes
# 大 key 排查
redis-cli --bigkeys
MEMORY USAGE user:7 # 单键占用估计(字节)
- Set an expiry on every cached key — rely on eviction only as a safety net.
- Big keys (multi-MB hashes/lists) cause latency spikes on deletion; split or use UNLINK to delete asynchronously.
- Never let Redis swap — monitor memory and alert at 70%.
Cluster vs Sentinel
# 主从 + 哨兵:自动故障转移(高可用,容量仍是单机)
# 主写从读;sentinel 们选主并改写客户端连接
# sentinel.conf 示例
sentinel monitor mymaster 10.0.0.2 6379 2 # 2 个哨兵同意才切换
sentinel down-after-milliseconds mymaster 5000
# Cluster:数据分片(16384 槽,横向扩展)
# 每个主节点负责一段槽,至少 3 主 3 从
# 客户端拿 MOVED 重定向后缓存槽映射
redis-cli --cluster create 10.0.0.1:6379 \
10.0.0.2:6379 10.0.0.3:6379 \
10.0.0.1:6380 10.0.0.2:6380 10.0.0.3:6380 \
--cluster-replicas 1
# 跨槽命令限制:MGET / 事务 / Lua 涉及多键时
# 必须用 hash tag 保证同槽:user:{7}:profile 与 user:{7}:detail
# 大多数 SDK 会对 MGET 自动按组拆分重试
Common Cache Patterns
1) Cache-Aside(旁路缓存,默认)
读:查缓存 → 未命中查 DB → 回写缓存
写:更新 DB → 删除缓存(不是更新缓存)
2) Read/Write-Through(穿透)
读写都经过缓存层,缓存同步回源
3) Write-Behind(异步写)
写只写缓存,异步刷回 DB(容忍数据丢失)
防三大问题:
缓存穿透(查不存在数据)→ 空值缓存 / 布隆过滤器
缓存击穿(热点 key 失效)→ 互斥锁重建 / 永不过期+异步更新
缓存雪崩(大量 key 同时失效)→ 过期时间加随机抖动单线程为什么快
Redis 用 epoll 多路复用在一个线程里执行命令:没有锁、没有上下文切换,且瓶颈在内存访问。单线程指的是命令执行——持久化、异步删除、IO 线程是分开的。单实例约 10 万 QPS 上限,所以横向扩展靠分片而非加 CPU。
五大核心类型与惯用法
redis-cli # 连接本地
# String:计数器 / 分布式锁基础
SET token:abc 1 EX 3600 # 秒级过期
INCR article:42:views # 原子自增(阅读量)
INCRBY stock:sku7 -1 # 原子扣减库存
# Hash:对象字段
HSET user:7 name Alice age 30
HMGET user:7 name age
HINCRBY user:7 age 1
# List:简单消息队列
LPUSH queue:pay order:1
BRPOP queue:pay 5 # 阻塞 5 秒
# Set:去重 / 交并
SADD tags:42 hot sale
SISMEMBER tags:42 hot
SINTER set_a set_b # 共同好友
# ZSet:排行榜
ZADD rank 100 alice 90 bob 150 carol
ZREVRANK rank carol # 名次
ZINCRBY rank 5 alice
# 过期与扫除
EXPIRE user:7 3600
TTL user:7 # -1 永久 -2 不存在
KEYS * # ✗ 线上禁用(阻塞)
SCAN 0 MATCH user:* COUNT 100 # ✓ 游标分页
KEYS 会阻塞唯一的命令线程——线上一律 SCAN。一条慢命令会卡死整个实例。
持久化:RDB 与 AOF
| 维度 | RDB 快照 | AOF 日志 |
|---|---|---|
| 原理 | 全量数据快照(fork 子进程) | 追加写命令(可重写压缩) |
| 数据完整性 | 周期性,崩溃丢最近一段 | fsync 策略决定(always 最稳) |
| 体积 | 紧凑小 | 较大(重写后变小) |
| 恢复速度 | 快 | 重放慢 |
| 适用 | 备份 / 冷备 / 低损失容忍 | 热数据 / 高安全 |
# 综合策略:RDB 兜底 + AOF 保近实时(推荐)
save 900 1
appendonly yes
appendfsync everysec # 每秒刷盘:崩溃最多丢 1 秒
auto-aof-rewrite-percentage 100
# 手动触发
redis-cli BGSAVE # 后台快照
redis-cli BGREWRITEAOF # 后台重写
# 数据恢复:把 dump.rdb / appendonly.aof 放数据目录启动即可
# 主从同步:首次全量 RDB 传输 + 后续命令流复制
replicaof 10.0.0.2 6379
淘汰策略与内存
maxmemory 4gb
maxmemory-policy allkeys-lru
# noeviction 写满直接报错(默认,缓存场景不合适)
# allkeys-lru 全键 LRU(纯缓存首选)
# volatile-lru 仅设过期的键 LRU
# allkeys-lfu 全键 LFU(热点明显时更优)
# volatile-ttl 优先淘汰快过期的
# 查看内存明细
MEMORY STATS
INFO memory # used_memory / fragmentation_ratio
# 碎片率 > 1.5 考虑 activedefrag yes
# 大 key 排查
redis-cli --bigkeys
MEMORY USAGE user:7 # 单键占用估计(字节)
- 每个缓存键都设过期,淘汰只是兜底。
- 大 key(数 MB 的 hash/list)删除时造成延迟抖动;拆细或用 UNLINK 异步删。
- 绝不让 Redis 落 swap:监控内存,70% 报警。
集群与哨兵
# 主从 + 哨兵:自动故障转移(高可用,容量仍是单机)
# 主写从读;sentinel 们选主并改写客户端连接
# sentinel.conf 示例
sentinel monitor mymaster 10.0.0.2 6379 2 # 2 个哨兵同意才切换
sentinel down-after-milliseconds mymaster 5000
# Cluster:数据分片(16384 槽,横向扩展)
# 每个主节点负责一段槽,至少 3 主 3 从
# 客户端拿 MOVED 重定向后缓存槽映射
redis-cli --cluster create 10.0.0.1:6379 \
10.0.0.2:6379 10.0.0.3:6379 \
10.0.0.1:6380 10.0.0.2:6380 10.0.0.3:6380 \
--cluster-replicas 1
# 跨槽命令限制:MGET / 事务 / Lua 涉及多键时
# 必须用 hash tag 保证同槽:user:{7}:profile 与 user:{7}:detail
# 大多数 SDK 会对 MGET 自动按组拆分重试
三种经典缓存模式
1) Cache-Aside(旁路缓存,默认)
读:查缓存 → 未命中查 DB → 回写缓存
写:更新 DB → 删除缓存(不是更新缓存)
2) Read/Write-Through(穿透)
读写都经过缓存层,缓存同步回源
3) Write-Behind(异步写)
写只写缓存,异步刷回 DB(容忍数据丢失)
防三大问题:
缓存穿透(查不存在数据)→ 空值缓存 / 布隆过滤器
缓存击穿(热点 key 失效)→ 互斥锁重建 / 永不过期+异步更新
缓存雪崩(大量 key 同时失效)→ 过期时间加随机抖动