分布式缓存Redis技术
摘要
Redis 是一个以内存为核心的数据结构服务器,官方文档将其定位为面向 caching 与 streaming 的开源内存数据库。
在分布式系统中,它最常被用来承担以下几类职责:
- 为数据库、搜索引擎和下游服务提供高命中率的热点缓存
- 存储会话、验证码、令牌、购物车、临时状态等短生命周期数据
- 实现计数器、排行榜、限流器、分布式锁、延迟队列和轻量消息能力
- 通过复制、Sentinel 与 Cluster 支撑高可用与横向扩展
Redis 的价值不只是“快”,而是它把常见的数据结构能力直接暴露为网络服务,使很多原本要在应用层手写的数据组织逻辑,能够以更少的代码、更低的延迟完成。
一、什么是分布式缓存与 Redis
1. 分布式缓存要解决什么问题
在典型互联网或企业应用中,真正昂贵的往往不是一次内存访问,而是:
- 数据库磁盘 I/O
- 跨网络调用下游服务
- 热点数据被重复计算或重复查询
- 高并发场景下的共享状态协调
分布式缓存的目标,就是把一部分高频、可复用、可接受短暂不一致的数据提前放到独立的缓存层,减少核心存储和服务的压力。
从工程角度看,分布式缓存通常关注四件事:
- 低延迟:尽量把访问时延压到毫秒级甚至更低
- 高吞吐:承受高并发读写
- 可扩展:可以通过副本、分片或集群扩容
- 可治理:能处理过期、淘汰、故障转移和容量问题
2. Redis 的基本含义
Redis 通常可以理解为:
- 一个以内存为主的数据结构服务器
- 一个支持多种原生数据类型的键值数据库
- 一个常用于分布式缓存、实时计数、队列与流处理的基础组件
- 一个既支持缓存,也支持一定持久化与高可用能力的中间件
3. Redis 为什么适合做分布式缓存
Redis 之所以被广泛用于缓存层,核心原因在于:
- 数据存放在内存中,读写延迟低
- 原生支持字符串、哈希、列表、集合、有序集合、流等结构
- 原生支持 TTL、过期与内存淘汰策略
- 提供复制、Sentinel、Cluster 等高可用与扩展方案
- 支持事务、Lua/Functions、流水线等服务端原子能力
- 生态成熟,客户端、监控、运维工具丰富
4. Redis、关系型数据库、Memcached 的粗略对比
| 维度 | Redis | 关系型数据库 | Memcached |
|---|---|---|---|
| 主要定位 | 缓存 + 数据结构服务 | 持久化业务数据 | 纯缓存 |
| 数据模型 | 键值 + 多数据结构 | 表、行、列、关系 | 键值 |
| 主要介质 | 内存为主 | 磁盘为主 | 内存 |
| 延迟特征 | 很低 | 相对更高 | 很低 |
| 原生持久化 | 支持 | 支持 | 不支持 |
| 原生复制/高可用 | 支持 | 支持 | 较弱 |
| 原子结构操作 | 丰富 | 依赖 SQL / 事务 | 较少 |
| 典型用途 | 缓存、计数、排行、限流、流 | 核心交易与持久化 | 纯对象缓存 |
5. 常见英文缩写
| 缩写 | 完整写法 | 中文含义 | 说明 |
|---|---|---|---|
| TTL | Time To Live | 生存时间 | 键的剩余有效期 |
| RDB | Redis Database | 快照持久化文件 | 点时间快照 |
| AOF | Append Only File | 追加日志文件 | 记录写命令 |
| ACL | Access Control List | 访问控制列表 | Redis 用户和权限控制 |
| HA | High Availability | 高可用 | 故障时尽量保持服务可用 |
| RTT | Round Trip Time | 往返时延 | 一次请求-响应的网络耗时 |
| QPS | Queries Per Second | 每秒请求数 | 吞吐能力指标 |
| LRU | Least Recently Used | 最近最少使用 | 常见淘汰策略 |
| LFU | Least Frequently Used | 最不经常使用 | 常见淘汰策略 |
| LRM | Least Recently Modified | 最近最少修改 | Redis 新增淘汰策略之一 |
二、Redis 的核心数据结构
Redis 官方文档明确将 Redis 视为 data structure server。
对分布式缓存场景来说,真正要掌握的不是“命令有多少”,而是“什么数据适合放进什么结构”。
1. 常用结构与典型场景
| 数据结构 | 典型场景 | 关键特点 |
|---|---|---|
| String | 对象缓存、计数器、令牌、锁 | 最基础,适合存 JSON、数字、二进制 |
| Hash | 用户资料、商品属性、配置缓存 | 适合字段化对象 |
| List | 简单队列、最近访问列表 | 保留插入顺序 |
| Set | 去重、标签、共同关系 | 无序且元素唯一 |
| Sorted Set | 排行榜、延迟队列、滑动窗口限流 | 有序且可按 score 排名 |
| Stream | 可靠消息流、事件处理 | 追加日志 + 消费者组 |
| Bitmap | 签到、布尔位统计 | 空间效率高 |
| HyperLogLog | UV 估算、去重计数 | 近似基数统计,内存占用低 |
2. 结构选择的经验判断
- 只想缓存一个对象:优先
String - 想对对象字段局部更新:优先
Hash - 想做排行或按权重取 TopN:优先
Sorted Set - 想做去重或共同好友/标签:优先
Set - 想做可靠消息与消费组:优先
Stream - 想做高密度状态位存储:优先
Bitmap - 想做超大规模 UV 统计:优先
HyperLogLog
3. 典型示例
# 1) String: 对象缓存
redis.setex("user:1001", 1800, user_json)
# 2) Hash: 字段化存储
redis.hset("user:1001:profile", mapping={
"name": "Alice",
"level": "vip",
"city": "Shanghai"
})
# 3) Sorted Set: 排行榜
redis.zadd("rank:game:2026", {"u1001": 9300, "u1002": 8800})
top10 = redis.zrevrange("rank:game:2026", 0, 9, withscores=True)
# 4) Stream: 事件流
redis.xadd("order:events", {"type": "created", "order_id": "A10001"})
4. 一个容易忽略的事实
Redis 的很多业务价值,并不是来自复杂 SQL,而是来自:
- 用
INCR做原子计数 - 用
EXPIRE做自动失效 - 用
ZSET做排序与窗口 - 用
SET NX PX做轻量互斥 - 用
XADD/XREADGROUP做事件处理
也就是说,Redis 更像“面向高频状态与结构操作的服务”,而不是传统关系型数据库的替代品。
三、Redis 的部署模式与高可用架构
1. 单机模式
单机模式最简单,适合:
- 本地开发
- 测试环境
- 单点可接受的小型内部工具
优点:
- 部署简单
- 延迟低
- 运维成本小
缺点:
- 单点故障明显
- 容量受单机内存限制
- 无法支撑真正的生产级高可用
2. 主从复制
Redis 官方文档指出,Redis 默认使用 异步复制。
这意味着:
- 主节点负责写
- 从节点复制主节点数据
- 从节点可用于分担读压力
- 在故障时,可能存在已确认写入尚未复制完成而丢失的窗口
适用场景:
- 读多写少
- 需要副本备份
- 接受一定复制延迟
3. Sentinel
Redis Sentinel 用于 非 Cluster 模式下的高可用。官方文档给出的核心能力包括:
- 监控主从节点健康状态
- 故障通知
- 自动故障转移
- 为客户端提供当前主节点地址
Sentinel 的关键结论:
- 适合不做分片、但要求高可用的 Redis 部署
- 官方建议做稳健部署时至少使用 3 个 Sentinel 实例
- 因为复制是异步的,所以 Sentinel 并不能保证故障时零数据丢失
4. Redis Cluster
Redis Cluster 同时解决两类问题:
- 分片:把数据自动切到多个节点
- 一定程度的高可用:部分节点故障时继续提供服务
Redis Cluster 的关键机制:
- 使用 16384 个 hash slots
- 键通过
CRC16(key) % 16384映射到槽位 - 每个主节点负责一部分槽位
- 通过副本提升在节点故障时恢复服务
需要注意:
- Redis Cluster 不是简单“多主复制”,而是 槽位分片
- 它不是一致性哈希,而是基于 hash slot 的分片
- 当多数主节点不可用时,集群也可能不可用
5. 常见部署模式对比
| 模式 | 是否高可用 | 是否自动故障转移 | 是否支持分片 | 适用场景 |
|---|---|---|---|---|
| 单机 | 否 | 否 | 否 | 开发测试、小型场景 |
| 主从复制 | 弱 | 否 | 否 | 读写分离、备份 |
| 主从 + Sentinel | 是 | 是 | 否 | 中小规模高可用缓存 |
| Redis Cluster | 是 | 是 | 是 | 大规模、高并发、需横向扩容 |
6. 一个务实的架构判断
- 只想做高可用,不需要分片:优先考虑
主从 + Sentinel - 内存规模、写入压力或热点分布已经逼近单主上限:考虑
Redis Cluster - 项目还很小:先单机或主从,不要过早把复杂度推到 Cluster
四、Redis 在分布式缓存中的典型模式
1. Cache-Aside
这是最常见、也最务实的缓存模式:
- 应用先查 Redis
- 命中则直接返回
- 未命中则查数据库
- 把结果写入 Redis 并设置 TTL
优点:
- 逻辑简单
- 业务掌控缓存粒度
- 适合绝大多数读多写少场景
缺点:
- 需要应用自己处理缓存一致性
- 首次访问会有缓存未命中的冷启动开销
def get_user(user_id: int):
key = f"user:{user_id}"
cached = redis.get(key)
if cached:
return json.loads(cached)
user = db.query_user(user_id)
if user is None:
redis.setex(key, 60, "NULL")
return None
redis.setex(key, 1800, json.dumps(user))
return user
2. Read-Through / Write-Through / Write-Behind
| 模式 | 基本思路 | 适用场景 | 风险点 |
|---|---|---|---|
| Cache-Aside | 应用自己控制缓存读写 | 最通用 | 一致性逻辑在业务层 |
| Read-Through | 缓存层负责回源 | 标准化缓存平台 | 平台复杂度更高 |
| Write-Through | 写缓存时同步写后端 | 一致性要求高 | 写延迟上升 |
| Write-Behind | 先写缓存,后异步刷后端 | 写入削峰 | 故障恢复与一致性复杂 |
在多数业务系统里,优先级通常是:
- 先做好
Cache-Aside - 再根据平台能力决定是否演进到
Read-Through或Write-Through
3. 两级缓存
常见组合:
- 本地缓存(进程内) + Redis
- Redis + 数据库
典型收益:
- 减少网络 RTT
- 进一步吸收热点流量
典型代价:
- 本地缓存与 Redis 的失效同步更复杂
- 热点切换时更容易出现短暂不一致
4. Key 设计与 TTL 设计
推荐实践:
- 使用统一前缀:如
user:,order:,session: - Key 尽量可读、可分组、可批量扫描
- TTL 按业务价值与更新频率分级,而不是一刀切
- 对大量同类缓存增加少量随机过期抖动,降低雪崩风险
示例:
user:1001
user:1001:profile
product:sku:90001
session:token:8ab3...
rate_limit:login:mobile:138xxxx
5. Pipeline 与批量操作
在高并发系统中,很多瓶颈不是单条命令执行,而是网络往返次数。
Redis 的流水线(pipelining)适合:
- 批量写缓存
- 批量读取多个 key
- 预热数据
- 定时刷新热点数据
原则上:
- 能批量就不要逐条发
- 能合并 RTT 就不要堆无谓网络开销
五、可靠性、一致性与并发控制
1. 过期机制与淘汰策略
Redis 支持通过 EXPIRE、PEXPIRE、TTL 等机制控制键生命周期。
在缓存场景里,TTL 不是附属配置,而是业务语义的一部分。
当设置了 maxmemory 后,Redis 会在超过上限时按策略淘汰键。官方文档列出的常见策略包括:
noevictionallkeys-lruallkeys-lfuallkeys-randomvolatile-lruvolatile-lfuvolatile-randomvolatile-ttl- 较新的
allkeys-lrm/volatile-lrm
经验上:
- 默认可优先考虑
allkeys-lru作为通用缓存策略 - 访问频率分布明显时,可评估
allkeys-lfu - 如果一个实例同时混放“缓存键”和“持久键”,要非常谨慎,必要时拆实例
2. 持久化:RDB、AOF 与混合策略
Redis 官方文档对持久化的总结很清晰:
- RDB:点时间快照,文件紧凑,恢复快,适合备份,但可能丢失最近一段时间数据
- AOF:记录写命令,默认
fsync every second,耐久性更好,通常最多丢失约 1 秒数据 - RDB + AOF:兼顾恢复速度与数据安全
粗略判断:
| 策略 | 优势 | 代价 | 适用场景 |
|---|---|---|---|
| RDB | 文件小、恢复快、适合备份 | 丢数据窗口更大 | 偏缓存、备份导向 |
| AOF | 数据更安全 | 文件更大、恢复慢于 RDB | 更关注持久性 |
| 混合 | 兼顾两者 | 配置与维护更复杂 | 生产环境常见选择 |
3. 复制一致性边界
Redis 默认是异步复制,因此必须接受一个现实:
- 主节点成功返回,并不等于所有副本都已落盘或已同步
- 故障切换时,可能丢失最近已确认但尚未传播完成的写入
Redis 提供可选的同步确认机制来收敛风险,但不能把 Redis 复制误解成强一致数据库复制。
4. 事务、Lua 与服务端原子性
Redis 事务通过 MULTI / EXEC / WATCH 提供批量执行能力。官方文档强调:
- 事务中的命令会 串行、顺序执行
- 事务执行过程中,不会夹入其他客户端命令
但 Redis 事务并不是传统数据库那种完整回滚型事务。
如果你需要更强的“读改写原子逻辑”,通常更务实的方式是:
- 优先使用单条原子命令,如
INCR - 对复杂逻辑使用 Lua / Functions
5. Pub/Sub 与 Stream 的边界
Redis Pub/Sub 很轻量,但官方文档明确指出它是 at-most-once 语义:
- 消息发出后,订阅者如果没接住,就可能永久丢失
- 它更适合广播通知,不适合强可靠消息消费
而 Stream 则适合:
- 需要保留消息
- 需要消费者组
- 需要确认与重试
- 需要在缓存系统内顺带承接轻量事件流
因此:
- 广播通知:Pub/Sub
- 可靠处理:Stream
6. 分布式锁的正确姿势
Redis 官方文档给出的单实例锁基础形式是:
SET resource_name unique_value NX PX 30000
释放锁时,不能简单直接 DEL,而应校验 value,避免误删别人的锁。
需要特别注意:
- 基于主从切换的“锁高可用”并不天然安全
- 因为复制是异步的,主节点崩溃前未同步到副本的锁可能丢失
- 如果业务对互斥正确性要求极高,应谨慎评估 Redlock 或更强一致方案
务实建议:
- 大多数业务只需要“降低并发重入风险”,此时 Redis 锁 + 幂等校验就足够
- 需要金融级、强一致互斥语义时,不要轻率把 Redis 当成唯一答案
六、Redis 在业务中的典型应用
1. 热点数据缓存
最典型的 Redis 用法:
- 商品详情
- 用户资料
- 字典数据
- 配置快照
- 首页推荐结果
核心目标:
- 降低数据库 QPS
- 缩短响应时间
- 吸收突发流量
2. 会话与令牌
Redis 很适合存储:
- Session
- 登录态
- 验证码
- 短期访问令牌
- 幂等 token
因为这些数据通常具备以下特征:
- 生命周期短
- 读写频率高
- 适合按 TTL 自动清理
3. 排行榜与实时统计
Sorted Set 是 Redis 的经典能力之一,适用于:
- 游戏积分榜
- 活跃榜
- 热搜榜
- 秒杀实时队列优先级
4. 限流
Redis 很适合做:
- 固定窗口限流
- 滑动窗口限流
- 漏桶 / 令牌桶近似实现
def fixed_window_limit(key: str, limit: int, window_sec: int) -> bool:
count = redis.incr(key)
if count == 1:
redis.expire(key, window_sec)
return count <= limit
5. 轻量消息与事件流
对于中小规模事件流处理,Redis Stream 往往足够覆盖:
- 异步任务通知
- 订单事件分发
- 审计事件收集
- 轻量日志流处理
但如果场景需要:
- 超长消息保留
- 超大规模消费组
- 强持久化审计链路
则应评估 Kafka、Pulsar 等更专门的消息平台。
七、常见问题与治理方案
1. 缓存穿透
问题表现:
- 大量请求访问根本不存在的数据
- 请求持续打到数据库
常见治理:
- 缓存空值
- 布隆过滤器
- 参数校验与风控拦截
2. 缓存击穿
问题表现:
- 某个热点 key 过期瞬间,大量请求同时回源
常见治理:
- 热点 key 互斥重建
- 逻辑过期 + 异步刷新
- 热点预热
3. 缓存雪崩
问题表现:
- 大量 key 在同一时间集中失效
- 后端服务被瞬时打爆
常见治理:
- TTL 加随机抖动
- 多级缓存
- 预热机制
- 限流与降级
4. 热 Key
问题表现:
- 单个 key 流量过高,单节点成为瓶颈
常见治理:
- 本地缓存分流
- 只读副本分担
- 热点拆分
- 请求合并
5. 大 Key
问题表现:
- 单个 key 的 value、list、set、zset 过大
- 删除、迁移、复制、持久化都变慢
常见治理:
- 拆 key
- 控制单 key 元素规模
- 避免把超大 JSON 或超长列表长期堆在一个键里
6. 内存打满与淘汰失控
重点关注:
used_memorymem_not_counted_for_evictevicted_keysexpired_keyskeyspace_hits/keyspace_misses
如果实例同时使用复制或持久化,还要给复制/AOF 缓冲区预留空间,不能把 maxmemory 配得过满。
7. 慢查询与阻塞
要特别警惕:
- 大范围扫描
- 大 key 操作
- 长 Lua 脚本
- 阻塞型命令堆积
常见排查手段:
INFOSLOWLOGMEMORY USAGEredis-cli --bigkeys
八、运维与安全建议
1. 最值得长期监控的指标
| 指标 | 关注点 |
|---|---|
| used_memory | 内存使用是否接近上限 |
| keyspace_hits / keyspace_misses | 缓存命中是否符合预期 |
| evicted_keys | 是否发生频繁淘汰 |
| expired_keys | 过期节奏是否正常 |
| connected_clients | 连接数是否异常上涨 |
| 复制偏移或延迟 | 主从复制是否堆积 |
| 慢查询数量 | 是否存在危险命令或大 key |
2. 安全控制
Redis 官方文档提供 ACL 机制,可基于用户、命令类别、键模式和 Pub/Sub 通道做访问控制。
生产环境建议至少做到:
- 禁止匿名暴露公网
- 启用认证和 ACL
- 区分应用用户与管理用户
- 限制危险命令
- 配合网络隔离、TLS、堡垒机或专线访问
3. 一个常见误区
不要把“Redis 很快”误解成“Redis 不需要治理”。
真正把 Redis 用好的团队,通常会同时做好:
- Key 设计
- TTL 策略
- 容量规划
- 热点治理
- 慢查询排查
- 故障演练
九、Redis 选型建议
1. 场景到方案的对应关系
| 场景 | 推荐方案 | 说明 |
|---|---|---|
| 开发测试 | 单机 | 最低成本 |
| 中小规模高可用缓存 | 主从 + Sentinel | 不做分片,但要故障转移 |
| 大规模缓存、需横向扩容 | Redis Cluster | 分片 + 高可用 |
| 只做轻量广播 | Pub/Sub | 简单直接,但不可靠投递 |
| 需要可靠消费 | Stream | 有持久化与消费者组 |
| 需要高命中热点缓存 | String/Hash + LRU/LFU | 先把缓存层打稳 |
2. 选型时优先回答的问题
- 数据规模是否已经逼近单机内存上限
- 可接受多大的数据丢失窗口
- 业务是否需要自动故障转移
- 是否真的需要分片,还是只需要高可用
- 热点是否集中在少量 key
- 团队是否具备 Cluster 和故障演练能力
3. 务实结论
- 小系统优先把
Cache-Aside + TTL + 监控做扎实 - 中型系统优先把
Sentinel用明白,再考虑更复杂的扩展 - 真正需要写扩展、内存扩展和多分片治理时,再上
Cluster
十、常见误区
误区 1:Redis 可以直接替代 MySQL
不是。
Redis 擅长热点数据、临时状态和结构化高频操作,不等于适合承载全部核心业务持久化数据。
误区 2:上了 Sentinel 就不会丢数据
不是。
Sentinel 解决的是故障发现和切换问题,不会消除异步复制带来的写丢失窗口。
误区 3:Pub/Sub 可以当可靠消息队列
不建议。
官方文档明确说明 Pub/Sub 是 at-most-once 语义,丢了就丢了。
误区 4:Redis 事务等于关系型数据库事务
不是。
Redis 事务强调批量顺序执行和隔离执行,不等于传统 ACID 回滚模型。
误区 5:缓存命中率低就只需要加机器
不一定。
很多时候问题出在:
- TTL 设计不合理
- 热点治理不足
- 淘汰策略选错
- Key 组织混乱
- 本不该缓存的数据也放进来了
十一、总结
从工程实践看,Redis 是分布式系统中极其高价值的基础组件,但它的价值并不只在“高性能”,更在于它把缓存、结构操作、过期机制、排行、限流、流式处理和一定的高可用能力整合成了一个统一的服务接口。
可以把关键结论浓缩成下面几句话:
- Redis 适合做热点缓存和高频状态服务,不适合被想当然地当作所有核心数据的唯一归宿
- String、Hash、Sorted Set、Stream 是最值得优先掌握的几类结构
- 主从复制解决副本,Sentinel 解决非分片高可用,Cluster 解决分片扩展
- TTL、淘汰策略、持久化、热点治理,决定 Redis 能不能在生产环境里稳定长期运行
- Pub/Sub 适合广播,Stream 更适合可靠处理
- 真正成熟的 Redis 能力,不是记住多少命令,而是知道什么该缓存、怎么过期、何时分片、怎么治理风险
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)