2021 字
10 分钟

Redis 完全指南 2026:核心数据结构 + 缓存设计模式 + 持久化 + 高可用集群

Redis 是现代后端架构中几乎不可缺少的一环——缓存、会话存储、消息队列、排行榜、分布式锁,它几乎无处不在。但很多开发者只会简单的 GET/SET,遇到缓存雪崩、数据一致性问题时就束手无策。

本文系统梳理 Redis 核心知识,从数据结构到高可用集群,配合实际可运行的代码和设计决策说明。


一、核心数据结构与使用场景#

1.1 String(字符串)#

Terminal window
# 基础操作
SET user:1000:name "Alice"
GET user:1000:name
# 带过期时间(EX=秒,PX=毫秒)
SET session:abc123 "user_data" EX 3600
# 原子计数(点赞、访问量,无竞态)
INCR article:42:views
INCRBY article:42:views 100
DECR article:42:views
# 分布式锁(NX=不存在则设置,EX=过期秒数)
SET lock:order:1001 "worker-uuid" NX EX 30
# 批量操作
MSET user:1:name Alice user:2:name Bob
MGET user:1:name user:2:name

适用场景:缓存对象(JSON 序列化)、计数器、分布式锁、会话 token、限流计数

1.2 Hash(哈希)#

Terminal window
# 存储对象(类似数据库一行记录)
HSET user:1000 name Alice email alice@example.com age 30
HGET user:1000 name
HMGET user:1000 name email
HGETALL user:1000
# 原子更新单个字段(无需序列化整个对象)
HSET user:1000 last_login "2026-08-03"
HINCRBY user:1000 login_count 1
HDEL user:1000 age

适用场景:用户/商品详情、购物车(field=商品ID,value=数量)

1.3 List(列表)#

Terminal window
# 消息队列
LPUSH queue:tasks '{"task":"send_email","to":"alice@example.com"}'
BRPOP queue:tasks 30 # 阻塞弹出,最多等30秒
# 最近 N 条记录(固定长度)
LPUSH user:1000:history "/page/about"
LTRIM user:1000:history 0 49 # 保留最近50条
# 分页获取
LRANGE user:1000:history 0 9 # 最近10条
LLEN user:1000:history

适用场景:消息队列(简单)、最近浏览记录、时间线

1.4 Set(集合)#

Terminal window
# 标签系统
SADD article:42:tags python backend redis
SADD user:1000:interests python devops
# 集合运算
SINTER article:42:tags user:1000:interests # 交集(共同标签)
SUNION article:42:tags user:1000:interests # 并集
SDIFF user:2:follows user:1:follows # 差集(推荐关注)
# 成员判断
SISMEMBER online:users user:1000
SCARD online:users # 集合大小

适用场景:标签/兴趣、关注/粉丝(共同好友)、签到去重

1.5 Sorted Set(有序集合)#

Terminal window
# 排行榜
ZADD leaderboard 9850 "Alice"
ZADD leaderboard 10000 "Carol"
# Top 3(分数从高到低)
ZREVRANGE leaderboard 0 2 WITHSCORES
# 用户排名(0-indexed)
ZREVRANK leaderboard "Alice"
# 原子增加分数
ZINCRBY leaderboard 500 "Alice"
# 按分数范围查询(滑动窗口限流)
ZRANGEBYSCORE ratelimit:user:1000 1722668400 +inf
ZCOUNT ratelimit:user:1000 1722668400 +inf
ZREMRANGEBYSCORE ratelimit:user:1000 -inf 1722668400

适用场景:排行榜、延迟队列(score=执行时间戳)、滑动窗口限流

1.6 HyperLogLog(基数估计)#

Terminal window
# UV 统计(误差约 0.81%,固定 12KB 内存)
PFADD uv:2026-08-03 user:1000 user:1001 user:1002
PFADD uv:2026-08-03 user:1000 # 重复不计
PFCOUNT uv:2026-08-03 # 约 3
# 合并多天 UV
PFMERGE uv:week uv:2026-08-01 uv:2026-08-02 uv:2026-08-03
PFCOUNT uv:week

适用场景:UV 统计、大规模去重计数(内存比 Set 少 90%+)

1.7 Stream(事件流)#

Terminal window
# 生产者
XADD events:orders * product_id 42 user_id 1000 action purchase
# 消费者组
XGROUP CREATE events:orders group1 $ MKSTREAM
XREADGROUP GROUP group1 consumer1 COUNT 10 BLOCK 2000 STREAMS events:orders >
# 确认消费
XACK events:orders group1 <message-id>

适用场景:事件溯源、消息队列(支持消费者组、消息确认,比 List 更完整)


二、缓存设计模式与问题解决#

2.1 Cache Aside(旁路缓存,最常用)#

import redis.asyncio as aioredis
import json
redis_client = aioredis.from_url("redis://localhost:6379", decode_responses=True)
async def get_user(user_id: int) -> dict | None:
cache_key = f"user:{user_id}"
# 1. 查缓存
cached = await redis_client.get(cache_key)
if cached:
return json.loads(cached)
# 2. 缓存未命中,查数据库
user = await db.fetch_one("SELECT * FROM users WHERE id = ?", user_id)
if user is None:
# 缓存空值,防止穿透(短 TTL)
await redis_client.set(cache_key, "null", ex=60)
return None
# 3. 写入缓存
await redis_client.set(cache_key, json.dumps(dict(user)), ex=3600)
return dict(user)
async def update_user(user_id: int, data: dict) -> None:
await db.execute("UPDATE users SET ... WHERE id = ?", user_id)
# 更新数据库后删缓存(下次读时重建),不要直接更新缓存!
await redis_client.delete(f"user:{user_id}")

2.2 缓存雪崩:TTL 抖动#

import random
async def set_cache(key: str, value: str, base_ttl: int = 3600):
# 加随机偏移(±10%),避免大量 key 同时过期
jitter = random.randint(-base_ttl // 10, base_ttl // 10)
await redis_client.set(key, value, ex=base_ttl + jitter)

2.3 缓存击穿:分布式互斥锁#

import asyncio, uuid
async def get_hot_data(key: str) -> dict:
cached = await redis_client.get(key)
if cached:
return json.loads(cached)
lock_key = f"lock:{key}"
lock_val = str(uuid.uuid4())
# NX:不存在才设置(只有一个请求拿到锁)
acquired = await redis_client.set(lock_key, lock_val, nx=True, ex=10)
if acquired:
try:
cached = await redis_client.get(key) # 双重检查
if cached:
return json.loads(cached)
data = await db.fetch_data(key)
await redis_client.set(key, json.dumps(data), ex=3600)
return data
finally:
# Lua 脚本原子释放锁(只释放自己的锁)
script = """if redis.call("get",KEYS[1])==ARGV[1] then
return redis.call("del",KEYS[1]) else return 0 end"""
await redis_client.eval(script, 1, lock_key, lock_val)
else:
await asyncio.sleep(0.1)
return await get_hot_data(key)

2.4 缓存穿透:布隆过滤器#

# 初始化布隆过滤器(100万元素,误判率 0.1%)
await redis_client.execute_command("BF.RESERVE", "user_bloom", 0.001, 1_000_000)
async def create_user(user_id: int, data: dict):
await db.insert(user_id, data)
# 同步到布隆过滤器
await redis_client.execute_command("BF.ADD", "user_bloom", user_id)
async def get_user_safe(user_id: int) -> dict | None:
# 布隆过滤器说不存在 → 一定不存在,直接返回
if not await redis_client.execute_command("BF.EXISTS", "user_bloom", user_id):
return None
return await get_user(user_id)

三、持久化策略#

对比速查#

策略数据安全性能影响恢复速度推荐场景
RDB only最差(分钟级丢失)最小最快可接受数据丢失的缓存
AOF only最好(最多1秒)中等数据安全优先
RDB + AOF好(最多1秒)生产推荐
无持久化无(重启全丢)N/A纯缓存(可重建)
Terminal window
# /etc/redis/redis.conf(生产推荐配置)
# RDB 快照
save 900 1
save 300 10
save 60 10000
# AOF
appendonly yes
appendfsync everysec # 每秒 fsync(推荐,最多丢1秒数据)
no-appendfsync-on-rewrite yes
# 混合持久化(Redis 4.0+)
aof-use-rdb-preamble yes # AOF 重写时前段用 RDB 格式,加快恢复
# 内存淘汰策略
maxmemory 4gb
maxmemory-policy allkeys-lru # 淘汰最久未使用的 key(缓存场景推荐)

四、高可用方案#

4.1 Redis Sentinel(哨兵)#

主从架构:Master → Slave × 2
哨兵监控:Sentinel × 3(奇数,防脑裂)
主节点故障 → 哨兵选举 → 从节点升主 → 客户端更新连接
Terminal window
# sentinel.conf
sentinel monitor mymaster 192.168.1.10 6379 2 # 2个哨兵同意才切换
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 10000
redis-sentinel /etc/redis/sentinel.conf
from redis.sentinel import Sentinel
sentinel = Sentinel(
[("sentinel1", 26379), ("sentinel2", 26379), ("sentinel3", 26379)],
socket_timeout=0.1,
)
master = sentinel.master_for("mymaster") # 写操作
slave = sentinel.slave_for("mymaster") # 读操作(负载均衡)

4.2 Redis Cluster(分片集群)#

最小配置:3主节点(16384个哈希槽均分)+ 每主1从
数据路由:客户端计算 HASH_SLOT(key) = CRC16(key) % 16384
Terminal window
# 创建集群(生产需要真实IP)
redis-cli --cluster create \
127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 \
127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 \
--cluster-replicas 1
redis-cli -p 7000 cluster info
redis-cli -p 7000 cluster nodes
from redis.cluster import RedisCluster
client = RedisCluster(
host="127.0.0.1", port=7000,
decode_responses=True,
skip_full_coverage_check=True,
)

五、实战代码#

5.1 滑动窗口限流#

async def is_rate_limited(user_id: str, limit: int = 100, window: int = 60) -> bool:
key = f"ratelimit:{user_id}"
now = time.time()
pipe = redis_client.pipeline()
pipe.zremrangebyscore(key, "-inf", now - window) # 删除窗口外记录
pipe.zadd(key, {str(uuid.uuid4()): now}) # 记录本次请求
pipe.zcard(key) # 窗口内请求数
pipe.expire(key, window + 1)
results = await pipe.execute()
return results[2] > limit # 超出限制返回 True

5.2 延迟队列#

async def schedule_task(task_data: dict, delay: int) -> None:
"""delay 秒后执行"""
await redis_client.zadd(
"delayed_queue",
{json.dumps(task_data): time.time() + delay}
)
async def poll_delayed_tasks():
while True:
now = time.time()
tasks = await redis_client.zrangebyscore("delayed_queue", "-inf", now)
for task_json in tasks:
if await redis_client.zrem("delayed_queue", task_json): # 原子删除防重复
await process_task(json.loads(task_json))
await asyncio.sleep(0.5)

5.3 Session 存储(滑动过期)#

async def create_session(user_id: int) -> str:
sid = str(uuid.uuid4())
await redis_client.setex(f"session:{sid}", 86400, json.dumps({"user_id": user_id}))
return sid
async def get_session(sid: str) -> dict | None:
data = await redis_client.get(f"session:{sid}")
if not data:
return None
await redis_client.expire(f"session:{sid}", 86400) # 每次访问刷新 TTL
return json.loads(data)

六、常用命令速查#

Terminal window
# ── 通用 ──────────────────────────────────────────────────────
SCAN 0 MATCH user:* COUNT 100 # 生产用 SCAN,禁用 KEYS
TTL key # 剩余 TTL(-1=永久,-2=不存在)
PERSIST key # 移除过期时间
TYPE key # 数据类型
UNLINK key # 异步删除(大 key 用这个)
# ── 监控与调试 ────────────────────────────────────────────────
INFO memory # 内存详情
INFO replication # 主从状态
SLOWLOG GET 10 # 最近10条慢查询
OBJECT ENCODING key # 内部编码
MONITOR # 实时命令监控(仅调试,勿用于生产)
# ── 管理 ──────────────────────────────────────────────────────
BGSAVE # 后台保存 RDB
BGREWRITEAOF # 后台重写 AOF
CONFIG GET maxmemory
CONFIG SET maxmemory 4gb # 动态修改
FLUSHDB # 清空当前库(危险)
FLUSHALL # 清空所有库(极危险)

相关文章

本文基于 Redis 7.2.x 验证。Redis 8.0 正式引入向量搜索(Vector Search),AI/RAG 应用场景可关注后续更新。

Redis 完全指南 2026:核心数据结构 + 缓存设计模式 + 持久化 + 高可用集群
https://971918.xyz/posts/docs/redis-complete-guide/
作者
九所长
发布于
2026-08-03
许可协议
CC BY-NC-SA 4.0