Redis 工程实践:核心概念、架构与缓存问题全解

Words 3237Read Time 9 min
2026-2-11
cover
type
Post
status
Published
date
Apr 17, 2021 09:03
slug
summary
本文系统梳理 Redis 工程实践核心知识。解释单线程为何高性能(内存+I/O多路复用+数据结构优化);详解五大数据结构应用场景(String计数、Hash用户资料、List队列、Set去重、ZSet排行榜)与 Bitmap 签到统计;对比定时删除与惰性删除的过期策略、近似 LRU 的内存淘汰机制;对比 RDB 快照与 AOF 日志在数据完整性、恢复速度、文件体积上的权衡;介绍 RESP 协议与 Pipeline 减少 RTT 的优化思路;对比单机/主从/哨兵/集群四种架构的适用场景与代价;提供缓存穿透(布隆过滤器)、击穿(互斥锁)、雪崩(随机过期时间)、双写一致性(先更新DB再删缓存)的完整解决方案;对比 Redis vs Memcached 在持久化、数据类型、底层模型上的差异。
tags
Redis
category
Database
icon
password
wordCount
3024

前言

Redis 是工程实践中最常用的高性能中间件之一。它以 Key-Value 形式存取数据,通常以 内存 作为主要承载介质,从而获得极低延迟与高吞吐。同时,Redis 也提供了持久化、复制与集群能力,使其能够在缓存、会话共享、计数、队列与分布式锁等场景中稳定落地。
🧭
阅读导航
  • 先理解:Redis 的定位与为什么快
  • 再掌握:数据结构、过期与淘汰、持久化
  • 最后补全:协议、Pipeline、架构与缓存典型问题
本文面向“希望把 Redis 讲清楚并能用起来”的读者,按概念到实践的路径,系统梳理 Redis 的核心能力与常见面试要点,包括:运行模型与性能来源、常用数据结构与适用场景、过期与淘汰策略、RDB/AOF 持久化机制、RESP 协议与 Pipeline、主从/哨兵/集群架构,以及缓存穿透、击穿、雪崩等典型问题的处理思路。
Redis 标志
Redis 标志

什么是 Redis(以及它到底像什么)

Redis(Remote Dictionary Server)是一个开源的 Key-Value 数据库,常见使用方式是把数据放在内存里,因此读写非常快。同时它也支持把数据落盘做持久化,所以它不是那种“断电就失忆”的选手。
如果把系统比作一家餐厅:
  • 关系型数据库像后厨,流程严谨,强调事务一致性(ACID)。
  • Redis 更像前台的“热菜保温柜”,用于存放高频、需要快速取用的数据。
ACID、NoSQL、CAP:别怕,先把名词当成“门牌号”
传统关系型数据库遵循 ACID(原子性、一致性、隔离性、持久性)。而 NoSQL 是一大类“不是传统关系型数据库”的集合,通常更偏向分布式场景。
分布式系统里经常会提 CAP 定理:
  • C 一致性(Consistency):大家看到的数据一致。
  • A 可用性(Availability):请求来了尽量都能得到响应。
  • P 分区容错性(Partition Tolerance):网络分区或节点间断联时系统还能继续工作。
CAP 的结论是:分布式系统不可能同时完美满足 C、A、P 三者,只能在具体场景里做权衡。
补充一个“旁听席代表”:ZooKeeper 常被描述为偏 CP 的实现。它在极端情况下可能拒绝部分请求,并且选主期间集群会短暂不可用。

Redis 的应用场景(它最擅长的活)

  • 缓存:把热点数据放在 Redis,减轻数据库压力。
  • 消息队列(轻量):例如 List 结构实现简单队列。
  • 共享 Session:多实例应用共享登录态。
  • 分布式锁:在多实例并发里做互斥控制。
一句话总结:Redis 是“速度型选手”,适合用在高频读写、低延迟、热点数据、并发控制的地方。

单线程 Redis 为什么还能这么快

Redis 常被称为“单线程模型”(核心命令执行路径上单线程),但这并不等于“它只有一个 CPU 在干活”。它快主要因为:
  • 数据结构设计合理:很多操作是 O(1) 或接近 O(1)。
  • 基于内存:内存访问比磁盘快几个数量级。
  • I/O 多路复用:一个线程能同时处理大量连接的就绪事件。
  • 减少上下文切换:多线程锁竞争和切换成本很高,Redis 通过模型选择避免了不少开销。
把它想象成:
一位效率极高的“窗口工作人员”,不靠加人手,而靠流程设计与工具(多路复用)让队伍转得飞快。

I/O 机制小剧场:阻塞、非阻塞、多路复用

如果你对 I/O 还不熟,可以把它当作“等快递”的不同方式:
1) 阻塞 I/O
  • 你打电话问快递到了没。
  • 没到就一直挂着电话等,啥也干不了。
2) 非阻塞 I/O
  • 你每隔一分钟打一次电话。
  • 电话不会占线,但你会被自己烦死。
3) I/O 多路复用(select/poll/epoll)
  • 你雇了一个“通知员”,同时盯着很多快递。
  • 哪个到了就通知谁来取。
Redis 就偏向第三种:让线程把精力花在“处理到达的数据”上,而不是傻等。

Redis 的数据结构与常见使用场景

Redis 的数据结构可以理解为一个工具箱,每种结构都对应一类高效操作:
  1. String:缓存、计数器、限流、简单状态。
  1. Hash:用户资料、商品信息、购物车(一个 key 下多个 field)。
  1. List:队列、消息流(轻量场景)。
  1. Set:去重、共同好友、共同兴趣(交集/并集/差集)。
  1. Sorted Set(ZSet):排行榜、Top N、按权重排序。
  1. Bitmap:签到统计、布隆过滤器等。

Redis 的过期策略:定时删除 + 惰性删除

Redis 的 key 过期删除通常可以理解为两种方式配合:
  • 定时删除(更准确说是定期抽样)
    • Redis 会周期性抽取一部分 key 检查是否过期,过期就删除。
      优点:能主动清理。
      缺点:如果全量扫描会很耗 CPU,所以实际会抽样。
  • 惰性删除
    • 当你访问某个 key 时,Redis 顺手检查它是否已过期。
      优点:访问路径上保证不会拿到过期数据。
      缺点:长期不访问的过期 key 可能会在内存里躺很久。
如果你问:那一直躺着不删怎么办?
答:别急,Redis 还有“清场保安”。

Redis 内存淘汰机制:内存不够时谁先走

当内存不足以容纳新写入数据时,Redis 会按配置策略淘汰 key。常见策略包括:
  • 直接报错(默认行为之一,取决于配置)。
  • LRU(最近最少使用):优先淘汰最久没被访问的 key。
  • 随机淘汰
  • 只在设置了过期时间的 key 中淘汰(LRU 或随机)。
  • 快过期的优先淘汰
Redis 的 LRU 实现(近似 LRU)
传统精确 LRU 维护成本高。Redis 常用近似 LRU:
  • key 的元信息里维护 LRU 时间戳。
  • 每次淘汰时随机采样若干个 key,从中挑“最不常用”的淘汰。
  • 3.0 后通过 pool(如 16 大小)改进采样效果:把候选 key 放入池中排序,淘汰时从池里挑最小 LRU。
用人话说:
Redis 没有把“最近使用顺序”写成一本账本,而是用抽查与候选池,保证大概率赶走“最不受宠的那位”。

Redis 持久化机制:RDB 与 AOF

Redis 为了性能,主要把数据放在内存里;为了可恢复,又需要把数据以某种方式落盘。Redis 提供两条路线:RDB 快照AOF 追加日志
维度
RDB(快照)
AOF(追加日志)
核心思路
定期把某一时刻的内存数据生成快照文件(dump.rdb)
把写命令按顺序追加到日志文件(appendonly.aof)
写盘方式
通常 fork 子进程写临时文件,写完再原子替换
写命令追加到缓冲区与文件;按策略 fsync 落盘
数据完整性
可能丢失最后一次快照之后的数据
取决于 fsync 策略;常见 everysec,最坏丢 1 秒左右
恢复速度
快(加载快照即可)
相对慢(需要重放写命令)
文件体积
通常更小、更紧凑
通常更大(同一数据可能对应多条命令)
适合场景
备份、全量恢复、主从全量同步(常见)
更关注数据安全性、希望更接近实时恢复
选择建议(常见工程实践)
  • 追求恢复更完整:优先启用 AOF(常见 everysec)。
  • 追求恢复更快与备份更省:启用 RDB。
  • 两者都开启:重启通常优先加载 AOF(更接近最新写入)。

Redis 的 RESP 协议:它和客户端怎么聊天

RESP 是 Redis 的通信协议。你可以把它理解为 Redis 的“聊天格式”。常见返回类型包括:
  • 简单字符串(+ 开头)
  • 错误(- 开头)
  • 整数(: 开头)
  • Bulk String($ 开头)
  • 数组(* 开头)

Pipeline:一次发一堆命令,少跑几趟

Pipeline 的思路很朴素:
  • 不要每发一个命令就等待一次响应。
  • 把多个命令一次性发给 Redis。
  • Redis 处理完按顺序返回响应,客户端再解析。
收益主要来自:减少 TCP 往返等待时间(RTT)。

Redis 常见架构(从单机到集群)

把 Redis 架构理解成“从易到强、从省心到更复杂”的升级路线会更清晰:单机解决功能与性能,主从解决读扩展与备份,哨兵解决高可用切换,集群解决水平扩展。
模式
解决什么问题
优点
主要代价 / 风险
单机
最小可用形态
部署简单,成本低
单点故障,容量与吞吐受限
主从复制
读扩展与数据副本
从库分担读;有备份副本
主库仍是单点;写扩展有限
哨兵(Sentinel)
高可用与自动故障转移
自动监控与切主
切换窗口;异步复制可能丢少量数据
集群(Proxy 分片)
水平扩展(分片)
对业务可透明;多种 hash 策略
多一层组件要运维;扩缩容与 failover 常需额外设计
集群(直连)
水平扩展 + 去中心化
slot 分布;节点间 gossip;可自动 failover
异步复制不保证强一致;运维与排障复杂度更高
单机
单机
主从复制
主从复制
哨兵
哨兵
集群
集群

Redis 常见问题与解决方案(面试官的快乐源泉)

1) Redis 与 MySQL 双写一致性

常见思路:先更新数据库,再删除缓存
原因:数据库读远快于写,脏数据窗口相对小。
进阶:异步延时二次删除,降低并发下的脏读概率。

2) 并发竞争同一个 key

  • 分布式锁 + 时间戳。
  • 用消息队列把并行改串行。

3) 缓存穿透

现象:查一个根本不存在的 key,缓存没有,数据库也没有,请求次次打到数据库。
解决:
  • 接口层做参数校验。
  • 缓存空值(注意过期时间)。
  • 布隆过滤器:不存在就直接拦截。

4) 缓存击穿

现象:某个热点 key 过期瞬间,大量请求同时打到数据库。
解决:
  • 互斥锁(mutex):缓存失效时先抢锁,只有一个线程去构建缓存。

5) 缓存雪崩

现象:大量 key 在同一时间过期,导致请求集体打到数据库。
解决:
  • 过期时间加随机数。
  • 热点 key 设为不过期或提前刷新。
  • 缓存服务做高可用。
  • 监控与告警,提前发现风险。

Redis vs Memcached(老对手对比)

  • 存储方式:Memcached 纯内存,断电数据没了;Redis 可落盘。
  • 数据类型:Memcached 主要 key-value;Redis 支持多种结构。
  • 底层模型与协议:不同实现与通信协议。
  • value 大小:Redis 可支持更大 value(视配置与实现细节),Memcached 单条通常更小。

收个尾:你应该怎么把这篇内容用起来

  • 写业务系统:优先把 Redis 当“缓存与并发工具箱”,而不是当主存储。
  • 面试复习:重点记住数据结构使用场景、过期与淘汰、持久化差异、缓存三连。
  • 真上生产:别忘了配监控、限流、降级、以及灾备方案。

参考文档

📚
优先参考官方文档,其次参考权威社区文章。不同版本的行为细节可能略有差异,建议以实际线上版本为准。
Loading...