本文是大数据系列第 38 篇,介绍 Redis 的定位与核心能力,重点讲解生产中最常用的三种缓存读写模式。
Redis 简介
Redis(Remote Dictionary Server)是用 C 语言开发的开源高性能键值对存储系统。它将数据存储在内存中,读写速度可达数十万 QPS,同时通过 RDB 和 AOF 机制保障数据持久化。
主要特点:
- 内存存储:极快的读写速度,典型读写延迟在微秒级
- 持久化:RDB(快照)和 AOF(追加日志)双保险
- 丰富的数据结构:String、Hash、List、Set、Sorted Set
- 高可用性:主从复制 + 哨兵模式,支持自动故障转移
- 事务支持:
MULTI/EXEC命令块原子执行
五大核心数据类型
| 类型 | 典型使用场景 |
|---|---|
| String(字符串) | 缓存简单数据、计数器、分布式锁 |
| Hash(散列) | 存储对象/用户信息、购物车数据 |
| List(列表) | 消息队列、最新动态、粉丝列表 |
| Set(集合) | 标签系统、共同好友、去重统计 |
| Sorted Set(有序集合) | 排行榜、带权重队列、范围查询 |
常见使用场景
- 热点数据缓存:将高频 DB 查询结果缓存到 Redis,可将数据库 QPS 降低 50%–90%
- Session 分离:集群环境下所有 Tomcat 实例共享 Redis Session,避免传统 Session 复制的性能问题
- 分布式锁:
SET key value NX EX ttl实现轻量级分布式互斥 - 任务队列:秒杀、抢红包等高并发写场景削峰填谷
- 排行榜:Sorted Set 天然支持按分值排序
- 签到统计:Bitmap 高效存储布尔型时序数据
缓存读写模式
旁路缓存模式(Cache Aside Pattern)
最常用的模式,应用程序直接管理缓存与数据库的一致性。
读操作流程:
- 查询 Redis 缓存
- 缓存命中 → 直接返回
- 缓存未命中 → 查询数据库
- 将查询结果写入 Redis(设置合理的 TTL)
- 返回数据
写操作流程:
- 更新数据库
- 删除(而非更新)对应的缓存 key
为什么写操作要删除而不是更新缓存?更新操作存在并发写时的竞态条件(两个线程先后写库后先后写缓存,顺序可能错乱),删除操作是幂等的,下次读时重建缓存更安全。
潜在问题:
- 缓存穿透:频繁查询不存在的 key,可用布隆过滤器或缓存空值解决
- 缓存击穿:热点 key 过期瞬间大量请求打到数据库,可用互斥锁或逻辑过期解决
- 数据不一致窗口:数据库更新后到缓存删除成功前的短暂不一致
读写穿透模式(Read/Write Through Pattern)
应用程序只与缓存交互,由缓存层负责与数据库同步。缓存未命中时,缓存自动从数据库加载数据;写入时,缓存同步写入数据库后再返回成功。
适用场景:需要缓存层屏蔽存储细节,逻辑简单但依赖缓存框架支持(如 Spring Cache)。
异步写回模式(Write Behind / Write Back Pattern)
应用程序只更新缓存,缓存将数据异步批量刷写到数据库,类似 CPU L1/L2 缓存机制。
优势:写性能极高,适合写多读少场景。
缺点:
- 缓存宕机可能丢失未持久化的数据
- 数据库中的数据可能短暂滞后,不适合强一致性场景
模式对比
| 模式 | 一致性 | 复杂度 | 适用场景 |
|---|---|---|---|
| Cache Aside | 最终一致 | 低 | 通用场景,读多写少 |
| Read/Write Through | 强一致 | 中 | 需要透明缓存的业务 |
| Write Behind | 弱一致 | 高 | 极高写吞吐,可接受数据丢失 |