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 仓库
  • 推荐阅读文章或视频
相关推荐
小陈工2 小时前
Python Web开发入门(十七):Vue.js与Python后端集成——让前后端真正“握手言和“
开发语言·前端·javascript·数据库·vue.js·人工智能·python
科技小花7 小时前
数据治理平台架构演进观察:AI原生设计如何重构企业数据管理范式
数据库·重构·架构·数据治理·ai-native·ai原生
一江寒逸7 小时前
零基础从入门到精通MySQL(中篇):进阶篇——吃透多表查询、事务核心与高级特性,搞定复杂业务SQL
数据库·sql·mysql
D4c-lovetrain7 小时前
linux个人心得22 (mysql)
数据库·mysql
阿里小阿希7 小时前
CentOS7 PostgreSQL 9.2 升级到 15 完整教程
数据库·postgresql
荒川之神8 小时前
Oracle 数据仓库雪花模型设计(完整实战方案)
数据库·数据仓库·oracle
做个文艺程序员8 小时前
MySQL安全加固十大硬核操作
数据库·mysql·安全
不吃香菜学java8 小时前
Redis简单应用
数据库·spring boot·tomcat·maven
一个天蝎座 白勺 程序猿8 小时前
Apache IoTDB(15):IoTDB查询写回(INTO子句)深度解析——从语法到实战的ETL全链路指南
数据库·apache·etl·iotdb
不知名的老吴8 小时前
Redis的延迟瓶颈:TCP栈开销无法避免
数据库·redis·缓存