Redis 设计思想总结

设计背景

  • 高性能缓存需求: 在2009年前后,Web应用规模迅速扩大,大量读请求对数据库造成巨大压力。开发者需要一种快速、轻量级的内存数据存储系统来缓存热点数据,减轻后端数据库负载。
  • 简单性与灵活性: 当时已有的缓存系统(如 Memcached)虽然快,但功能较为单一(仅支持字符串键值对)。开发者希望有一种既保留高性能,又支持更丰富数据结构(如列表、集合、有序集合等)的工具。
  • 作者的个人动机: Redis 由意大利开发者 Salvatore Sanfilippo(网名 antirez)于2009年创建。他最初是为了改进一个实时分析系统而开发 Redis,目标是构建一个"简单、快速、实用"的内存数据结构存储系统。
  • 对持久化能力的补充: 与纯内存缓存(如 Memcached)不同,Redis 从早期就引入了可选的持久化机制(RDB 快照和 AOF 日志),使其不仅能做缓存,还能作为轻量级数据库使用。

项目定位与目标

解决什么问题?

  • 数据库性能瓶颈问题
    • 问题:传统关系型数据库(如 MySQL、PostgreSQL)在高并发读写场景下容易成为系统瓶颈,尤其是频繁访问热点数据时。
    • Redis 的解决方式:将热点数据缓存在内存中,大幅降低数据库负载,提升响应速度(微秒级 vs 毫秒级)
  • 缓存功能单一的问题
    • 问题:早期缓存系统(如 Memcached)仅支持简单的字符串键值对,无法直接支持复杂数据结构操作(如排行榜、队列、集合运算等)。
    • Redis 的解决方式:原生支持 List、Set、Sorted Set、Hash 等多种数据结构,开发者无需在客户端拼装逻辑,直接通过原子命令完成复杂操作。
  • 实时性与低延迟需求
    • 问题:许多现代应用(如社交网络、游戏、金融交易)要求毫秒甚至微秒级响应。
    • Redis 的解决方式:基于内存存储 + 单线程事件驱动模型,确保极低延迟和高吞吐(可达数十万 QPS)。
  • 临时数据与会话管理难题
    • 问题:Web 应用中的用户会话(Session)、验证码、临时令牌等数据生命周期短、访问频繁,不适合长期存入磁盘数据库。
    • Redis 的解决方式:提供自动过期(TTL)机制,天然适合存储临时性数据。
  • 分布式协调与消息传递
    • 问题:构建分布式系统时常需实现分布式锁、发布/订阅、任务队列等功能。
    • Redis 的解决方式: 利用 SETNX 实现分布式锁; 使用 PUB/SUB 实现实时消息广播; 借助 List 或 Stream 构建轻量级消息队列。

Redis 解决的核心问题是:在高并发、低延迟、灵活数据操作的场景下,提供一个简单、快速、可靠的内存数据结构存储系统。

目标用户是谁?

  • 后端开发工程师: 缓存数据查询结果, 加速API响应, 会话共享
  • 系统架构师: 作为缓存层或者中间件, 设计高可用的系统
  • DevOps/SRE工程师: 部署,监控和维护Redis集群, 配置持久化策略
  • 数据工程师: 使用Redis的Stream结构进行实时数据流处理

核心设计理念是什么?

  • 内存优先(In-Memory First): Redis 将所有数据存储在内存中,以实现极低的访问延迟(通常在微秒级别)。这是其高性能的基础。
  • 丰富的数据结构: Redis 不只是一个简单的 key-value 存储,而是提供多种原生数据结构, 这些结构直接在服务端实现,避免了客户端复杂逻辑,提升了效率
    • String(字符串)
    • List(列表)
    • Set(集合)
    • Sorted Set(有序集合)
    • Hash(哈希表)
    • Stream(流,用于消息队列)
    • Bitmaps、HyperLogLog、Geospatial 等扩展结构
  • 单线程模型(主线程): Redis 的核心网络 I/O 和命令执行采用单线程模型(自 Redis 6 起引入多线程 I/O,但命令执行仍为单线程),避免了多线程带来的锁竞争和上下文切换开销,简化了并发控制,同时保证了操作的原子性。
  • 非阻塞 I/O 与事件驱动: 使用 epoll(Linux)、kqueue(BSD)等高效 I/O 多路复用技术,使单个线程能高效处理成千上万的并发连接。
  • 可选持久化(Persistence as an Option)Redis 提供两种持久化方式, 用户可根据需求选择是否开启持久化,平衡性能与数据安全性
    • RDB(快照):定期将内存数据写入磁盘
    • AOF(Append-Only File):记录每个写操作,支持重放恢复
  • 简单即强大(Simplicity over Complexity): Redis 的 API 设计简洁直观,命令语义清晰。作者坚持"做一件事并做到极致"的哲学,避免过度工程化。
  • 高可用与扩展性支持: 虽然核心设计简单,但通过主从复制、哨兵(Sentinel)自动故障转移、集群(Cluster)分片等机制,Redis 支持构建高可用、可水平扩展的分布式系统。

整体架构概览

  • 主要组件有哪些?它们如何协作?

  • 事件驱动模型(单线程 + I/O 多路复用): Redis采用单线程(主线程)的事件驱动架构, 通过I/O多路复用(epoll/kqueue/select)同时监听多个客户端的连接, 避免多线程上下文切换和锁竞争, 保证执行的原子性同时高效

    • 文件事件处理器(FileEventHandler): 处理客户端的连接, 请求读写
    • 事件事件处理器(TimeEventHandler): 处理定时任务, 过期清理,持久化触发等
  • 内存存储与对象系统: 数据默认存储在内存中, 提供微秒级访问速度

    • 键空间(KeySpace): 全局哈希表(dict), 存储所有的key-value
    • 对象系统(redisObject): 每个value封装为redisObject, 包含类型, 编码引用计数, LRU信息等
    • 多种底层数据结构: 根据数据类型和大小自动选择最优编码, ziplist, quicklist, skiplist, intset等
  • 多数据类型与动态编码

    • 支持数据类型: String, List, Set, SortedSet, Hash, Stream, Bitmap, HyperlogLog, Geospatial等
    • 动态编码优化
      • 小对象使用紧凑结构, 节省内存
      • 数据增长后自动转化为更高效的结构, 比如linkedlist或skiplist
      • 通过OBJECT ENCODING命令可以查看实际编码
  • 持久化机制(RDB / AOF)

    • RDB(RedisDatabase): 定时快照, 内存数据全量写入二进制而建
    • AOF(Append-OnlyFile): 记录每个写命令, 以日志追加到文件
  • 高可用体系(主从 / 哨兵 / Cluster)

    • 主从复制(Replication): 主节点(master)将写操作同步给一个或者多个节点(slave/replica) 支持异步复制
    • 哨兵模式: 独立进程, 监控主从集群, 自动完成故障检测,主从切换,服务发现
    • RedisCluster(集群): 支持数据分片, 去中心化高可用, 通过16384哈希槽分配key, 自动故障转移, 客户端连接任意节点集群重定向请求
  • 客户端与 RESP 协议: Redis自定义的文本协议, 简单, 可读, 高效, 兼容TCP长链接, 是Redis客户端库的基础

    • 目标: 简单/快速/可读/多种数据类型
    • 数据类型, RESP 使用前缀字符标识数据类型
    类型 前缀 说明 示例
    Simple String(简单字符串) + 非二进制安全,通常用于状态回复(如 OK)
    Error(错误) - 服务器返回的错误信息(客户端应抛出异常) -ERR unknown command\r\n
    Integer(整数) : 64 位有符号整数 :1000\r\n
    Bulk String(批量字符串) $ 二进制安全,可表示任意字节序列,包括空值 6\\r\\nfoobar\\r\\n0\r\n\r\n(空字符串)$-1\r\n(表示 nil)
    Array(数组) * 元素可以是任意 RESP 类型(嵌套支持) *2\r\n3\\r\\nfoo\\r\\n3\r\nbar\r\n
    • pipeline模式: 基于socket长链接实现, Redis一旦从 socket 读取到完整的一条或多条命令,就会立即按顺序逐条执行, 每执行完一条命令,就将响应写入客户端的输出缓冲区(output buffer)
  • 内存管理与淘汰策略

    • 内存分配器: 默认水用jemalloc, 减少内存碎片
    • 过期键删除策略:
      • 惰性删除: 访问key时检查是否过期
      • 定期删除: 后台周期性删除过期key
    • 内存淘汰策略(maxmemory-policy): 当内存达到上限时, 按策略驱逐数据(LRU, LFU, TTL, 随机等)
  • 画一张简单的架构图(可用文字描述)

Redis 服务端核心流程
SET key value
GET key
写命令, 如 SET, LPUSH
读命令, 如 GET, HGET
触发

每秒 默认

异步
异步
客户端
Redis 服务端
命令类型?
更新内存中的键空间

dict 哈希表
从内存键空间读取数据
返回结果给客户端
追加写命令到 AOF 缓冲区, 若 AOF 开启
更新 key 的过期时间 / LRU 信息
时间事件处理器, 每秒/定期
是否满足 RDB 条件?, 如 save 900 1
执行 bgsave:

fork 子进程生成 RDB 快照
子进程将内存数据写入 .rdb 文件
是否开启 AOF?
将 AOF 缓冲区内容

写入并同步到 AOF 文件, 策略: everysec/always/no
磁盘: dump.rdb
磁盘: appendonly.aof

关键设计与实现机制

选择 2--3 个最具代表性的设计点深入分析

🔹 设计点 1:单线程事件驱动模型 + I/O 多路复用,实现高吞吐与低延迟

  • 问题背景:在高并发场景下,传统多线程/多进程模型因上下文切换、锁竞争和系统调用开销,难以满足微秒级响应需求。如何在有限资源下最大化吞吐量并保持低延迟?
  • 解决方案
    • 单线程事件循环(Event Loop) + I/O 多路复用(epoll/kqueue) 的架构
      • 所有客户端请求由同一个主线程顺序处理,避免锁竞争;
      • 通过 Reactor 模式 监听多个 socket 连接,当任一连接就绪(可读/可写)时触发回调处理;
      • 利用操作系统提供的 epoll(Linux)或 kqueue(BSD) 实现高效的网络 I/O 多路复用
      • 请求解析、命令执行、响应返回均在事件循环中完成,形成"非阻塞、无锁、串行化"的处理流水线
    • 内存存储和对象系统
      • 将数据存储到内存中, 通过dict存储, 并且将value进行封装
      • 提高访问效率
    • 自定义请求REST协议: 根据Redis的特点自定义协议加快Redis在链路上的流畅度
  • 关键技术
    • I/O 多路复用(epoll/select/poll)
    • eactor 事件驱动模型
    • 自定义二进制安全协议 RESP(REdis Serialization Protocol),轻量、易解析、支持批量操作
    • 避免系统调用和线程调度开销
  • 优点
    • 极低的延迟(通常 < 1ms)
    • 高吞吐(单机可达 10w+ QPS)
    • 代码逻辑简单,无并发竞争问题,易于维护和调试

🔹 设计点 2:内存优先的数据模型与高效对象封装

  • 问题背景:磁盘 I/O 速度远低于内存(相差 10⁴~10⁶ 倍),在需要亚毫秒级响应的缓存/实时系统中,磁盘成为性能瓶颈。如何在保证数据结构灵活性的同时,最大化内存访问效率?
  • 解决方案
    • Redis 将所有数据存储于内存中,并通过精心设计的对象系统平衡内存占用与操作效率:
    • 每个 value 被封装为 redisObject 结构,包含类型(type)、编码(encoding)、引用计数、LRU 信息等;
    • 同一逻辑类型(如 List、Set)可采用多种底层编码(如 ziplist、quicklist、intset、hashtable),根据数据规模和特征自动优化;
    • 支持 LRU/LFU 淘汰策略,在内存不足时自动驱逐冷数据。
  • 关键技术:内存存储映射, value的redisObject封装
  • 优点:提高访问效率
  • 缺点
    • 内存成本高,容量受限于物理内存;
    • 需依赖持久化机制(RDB/AOF)防止宕机丢数据;
    • 不适合存储超大 value(如 > 100MB),易引发主线程阻塞

4. 我的收获与启发

把"学到的东西"转化为"我能用的东西"

启发 我可以怎么应用到实际工作中?
单线程+I/O多路复用模型 在构建高并发、低延迟的内部服务(如实时通知、限流网关)时,优先考虑异步非阻塞架构(如 Go 的 goroutine + epoll、Node.js event loop),避免过早引入多线程复杂性。
内存优先 + 自适应编码的数据结构 对高频访问的业务数据(如用户会话、商品库存、排行榜),可利用 Redis 内置结构:• 用 Hash 存储对象字段(节省内存)• 用 Sorted Set 实现带权重的排行榜• 用 Bitmap 做用户签到/布隆过滤, 同时注意控制 value 大小,避免大 key 阻塞主线程。
RDB/AOF 混合持久化机制 在需要"缓存+轻量持久化"的场景(如配置中心、任务队列状态),可开启 AOF + everysec 策略,平衡性能与数据安全;同时通过定期 RDB 快照实现快速冷备恢复。

5. 延伸思考(可选)

  • 如果让你改进它,你会做什么?

    例如:我会完善它的认证系统, 支持更多的认证方式和加密策略, 或者基于现有的使用考量Redis内部可以出一个内置的白名单系统

    例如:优化大 Key 自动检测与拆分建议:在 INFO 或 SLOWLOG 中主动提示潜在性能风险。

  • 它不适合什么场景?

    例如:适合高并发和缓存的场景

  • 不适合什么场景?

    例如:事务强一致, Redis 的事务不支持回滚,也不保证 ACID,不适合金融核心账务系统

    例如:海量持久化存储, Redis基于内存存储, 空间有限不适用海量持久化存储

    例如:复杂查询, Redis是基于Key-Value存储, 对于复杂查询不支持

    例如:超大 Value 存储, 如视频、文件等二进制大对象(BLOB),易导致主线程阻塞和内存碎片。

6. 参考资料

  • 官方文档链接
  • GitHub 仓库
  • 推荐阅读文章或视频
相关推荐
曹牧3 小时前
Java:Assert.isTrue()
java·前端·数据库
你不是我我3 小时前
【Java 开发日记】我们来说一说 Redis 主从复制的原理及作用
java·redis·github
程序员葫芦娃3 小时前
【Java毕设项目】基于SSM的旅游资源网站
java·开发语言·数据库·编程·课程设计·旅游·毕设
2401_865854884 小时前
怎样挑选适合业务的数据库云服务?
数据库
lkbhua莱克瓦244 小时前
基础-函数
开发语言·数据库·笔记·sql·mysql·函数
福大大架构师每日一题4 小时前
dify 1.11.2 正式发布:向量数据库、安全增强、测试优化与多语言支持全面升级
数据库·安全
码农学院5 小时前
Mysql 中的性能调优方法
数据库·mysql
UrSpecial5 小时前
MySQL索引
数据库·mysql
DB虚空行者5 小时前
聊下几次线上删除MySQL导致的故障
数据库