Redis 原理及底层实现——深入解析内存数据库的高性能引擎

Redis原理及底层实现 出发,全面剖析其内存管理、数据结构设计、持久化机制、并发控制与网络IO模型。结合真实源码片段、性能对比与实战经验,助您构建扎实的 Redis原理及底层实现 知识体系,成为高并发系统架构的真正高手。

Redis 是什么?为什么它“快”得离谱?

Redis(Remote Dictionary Server)是一个开源的、基于内存的键值对数据库。它支持字符串、哈希、列表、集合、有序集合等丰富数据结构,并提供持久化、事务、发布/订阅、Lua脚本等高级能力。

但它的“快”,远不止于“内存数据库”这么简单——真正的性能秘密,深藏于其精心设计的 Redis原理及底层实现 中。

⚡ 单线程 ≠ 低效

Redis 默认采用单线程处理客户端请求(网络IO与命令执行),但这并非“性能瓶颈”,而是刻意为之的设计选择:

• 避免多线程上下文切换开销 • 无需加锁,简化数据结构实现 • CPU 不是瓶颈,网络和内存才是

实测:在 10 万 QPS 场景下,单线程 Redis 的 CPU 利用率仅约 70%,仍有充足余量。

? 高性能的三大支柱

  • 内存存储:数据全驻留 RAM,访问延迟低至微秒级(典型值:0.1ms 内)
  • 高效数据结构:SDS、ziplist、intset、skiplist 等按场景动态选择
  • IO 多路复用:epoll/kqueue 实现高并发连接(单实例支持 10 万+ 连接)

? Redis vs MySQL:性能对比

场景 Redis MySQL(InnoDB)
单值读(1KB) ~120,000 QPS ~1,500 QPS
批量插入(100 条/批) ~80,000 QPS ~5,000 QPS

因此,Redis原理及底层实现 的核心思想是:以空间换时间,以简化换极致性能——它不做复杂事务、不支持复杂查询,却在缓存、计数、实时排行榜等场景中无可替代。

数据结构:Redis 的“内存搬运工”工具箱

Redis 的底层数据结构是其性能的关键。它没有采用传统数据库的 B+ 树索引,而是针对内存场景优化了多种紧凑型结构,实现“按需切换”的动态适配机制。

Redis 字符串:SDS(Simple Dynamic String)

Redis 并未直接使用 C 语言的 char 字符串,而是自研了 SDS 结构:

struct sdshdr { int len; int free; char buf[]; };

优势

  • O(1) 获取字符串长度(避免 strlen 遍历)
  • 预分配空间,减少内存重分配次数
  • 进制安全(可存储图片、序列化对象)
示例:SET user:1001 "Alice" 实际存储为 SDS,而非以 '' 结尾的传统字符串。

哈希(Hash):内存友好型字典

哈希底层有两种编码:ziplist(压缩列表)和 hashtable(哈希表)。

默认触发条件

  • 字段数 ≤ 512
  • 任意字段值长度 ≤ 64 字节

满足任一即用 ziplist;否则升级为 hashtable。

struct ziplist { int32 zlbytes; int32 zltail_offset; int16 zllen; byte entry[]; int8 zlend; };

当 Hash 字段较多时,自动升级为 hashtable(链地址法解决冲突),平均 O(1) 查找。

列表(List):双端队列的极致优化

旧版使用 linkedlist(双向链表),新版默认采用 ziplistquicklist(压缩列表 + 双端链表组合):

struct quicklist { quicklistNode head; quicklistNode tail; long count; int compress; int fill; };

fill 默认为 -2:表示每个 ziplist 不超过 8KB(实测性能最优)

compress 默认为 0:禁用压缩;可设为 1~2 提升内存效率(但牺牲部分性能)

示例:LPOP list 总是从 head 的 ziplist 头部弹出;若 head 空则释放并指向 next 节点。

有序集合(ZSET):跳表(skiplist)的精妙应用

ZSET 同时支持:score 排序 + member 唯一性,底层使用:
dict(存 member→score) + skiplist(按 score 排序)

struct zskiplistNode { struct zskiplistLevel { struct zskiplistNode forward; unsigned int span; } level[]; struct zskiplistNode backward; double score; robj obj; };

跳表特性

  • 查找/插入/删除:平均 O(log N),最坏 O(N)
  • 支持范围查询(如 ZRANGEBYSCORE)
  • 插入时动态决定层数(随机化保证平衡)
示例:ZADD leaderboard 10086 "Alice" → 同时更新 dict 和 skiplist
ZRANK leaderboard "Alice" → 通过 backward 指针反向计算排名(O(log N))

这些结构的动态切换,正是 Redis原理及底层实现 中“智能自适应”的体现——在内存占用与性能之间取得最佳平衡点。

内存管理:如何让 1GB 内存发挥 2GB 的价值?

Redis 的内存优化策略堪称教科书级别。它不仅关注“存多少”,更关注“怎么存最省”。以下是关键机制:

? 1. 内存池(Object Encoding)

Redis 不直接存储字符串,而是根据内容类型选择最优编码:

  • INT:整数直接存为 long(0 字节开销)
  • EMBSTR:≤44 字节的字符串(一次分配,与 SDS 头部一体)
  • RAW:长字符串(单独分配)

实测:10 万条短字符串,EMBSTR 比 RAW 节省内存 32%。

? 2. 共享对象池(Shared Objects)

启动时预创建 10,000 个常用整数对象(0~9999):

shared.integers[10000];

适用于 INCRLPUSH 等高频命令,减少内存分配。

? 3. 内存回收策略

Redis 采用 惰性删除 + 定期删除 组合:

  • 惰性删除:访问时检查过期,立即释放
  • 定期删除:每秒 10 次抽样扫描,释放过期键
  • 内存不足时触发 maxmemory-policy 策略
策略 说明
volatile-lru仅对设置了 TTL 的键,用 LRU 淘汰
allkeys-lru对所有键,用 LRU 淘汰(最常用)
volatile-ttl优先淘汰 TTL 较短的键
noeviction不淘汰,写满报错(默认)

? 4. 内存碎片整理(Redis 6.0+)

通过 ACTIVEREFrag 后台线程,定期检测碎片率(Fragmentation Ratio):

info memory → used_memory_rss / used_memory
若 > 1.5,则触发内存整理(malloc_trim / madvise)

这些策略共同构成 Redis原理及底层实现 中的内存优化体系,让 Redis 在 2GB 内存下稳定支撑 10 万 QPS 的缓存服务。

持久化:如何在“内存易失”与“数据可靠”间取舍?

Redis 提供两种持久化机制:RDB(快照)与 AOF(追加日志),可单独使用,亦可混合启用。

RDB:内存数据库的“快照备份”

通过 SAVE(同步)或 BGSAVE(子进程)触发,生成二进制文件 dump.rdb

触发条件(默认配置):

save 900 1 save 300 10 save 60 10000

优点:文件紧凑、恢复快、适合全量备份

缺点:故障时可能丢失最近 1~5 分钟数据

示例:执行 BGSAVE 时,Redis 主进程继续服务;子进程 fork 后写新文件,完成后原子替换旧文件。

AOF:命令级的“写前日志”

将每个写命令追加到 appendonly.aof,支持三种同步策略:

策略 fsync 频率 安全性 性能
always每次写同步极高(最多丢失 1 条)
everysec每秒同步高(最多丢失 1 秒)高(默认)
no依赖 OS

AOF 重写:通过 BGREWRITEAOF 清除冗余命令(如 SET a 1 → SET a 2 → GET a → 仅保留 SET a 2

混合持久化:RDB + AOF 的完美融合

Redis 4.0 引入,AOF 重写时先写 RDB 前缀(全量数据),再追加增量 AOF:

"xFAx52x45x44x49x53" "x00x05"

优势

  • 恢复速度比纯 AOF 快 5~10 倍
  • 故障丢失数据控制在 1 秒内(everysec)
  • 文件体积比纯 AOF 小 30%~50%
建议配置:appendonly yes + appendfsync everysec + aof-use-rdb-preamble yes

这些持久化机制,是 Redis原理及底层实现 中保障数据可靠性的基石,也是其从“纯缓存”走向“主存储”的关键一步。

并发模型:单线程如何扛住百万请求?

Redis 的“单线程”是误解——它采用 单线程处理命令 + 多线程后台任务 的混合模型:

.IO 多路复用(I/O Multiplexing)

通过 epoll(Linux)、kqueue(macOS)实现事件驱动:

int epoll_fd = epoll_create(1024); struct epoll_event ev; ev.events = EPOLLIN; ev.data.fd = server_fd; epoll_ctl(epoll_fd, EPOLL_CTL_ADD, server_fd, &ev); while (true) { int n = epoll_wait(epoll_fd, events, MAX_EVENTS, -1); for (int i = 0; i < n; i++) { if (events[i].data.fd == server_fd) { accept_new_client(); } else { process_client_request(events[i].data.fd); } } }

单线程即可高效处理数万并发连接,避免线程切换开销。

任务异步化

耗时操作由后台线程处理:

  • 关闭文件描述符:AOF 重写后关闭旧文件
  • LRU 淘汰:后台线程抽样更新淘汰池
  • 过期键删除:定期扫描 + 惰性删除配合
  • 集群节点通信:Gossip 协议异步同步

事务与 WATCH

Redis 事务(MULTI/EXEC)不支持回滚,但提供 WATCH 实现乐观锁:

WATCH stock multi DECR stock EXEC

stock 在 WATCH 后被修改,EXEC 返回空((nil)),客户端需重试。

这些设计共同构成 Redis原理及底层实现 中的并发模型核心——以极简逻辑实现高吞吐,是其成为云原生基础设施的关键。

网络 IO:Redis 如何做到“零拷贝”?

Redis 的网络层高度优化,关键特性如下:

RESP 协议:简单高效的文本协议

Redis Server Protocol(RESP)基于文本,但支持二进制安全:

+OKrn :1234rn $5rnhellorn 2rn$3rnSETrn$1rnarn

Redis 6.0 后支持 RESP3,新增布尔、错误类型等,提升可读性。

拷贝优化:splice() 与 sendfile()

Redis 6.0 引入 多线程 IO(仅用于读请求响应),避免主线程阻塞:

  • 主线程接收请求 → 写入客户端缓冲区
  • IO 线程(默认 4 个)读取缓冲区 → 发送响应
  • 客户端缓冲区大小 ≤ 1MB(默认)

注意:命令执行仍在主线程,多线程仅加速响应发送。

客户端缓冲区隔离

每个客户端有独立缓冲区(默认 1GB),防止“慢客户端”拖垮整体:

client-output-buffer-limit normal 0 0 0 client-output-buffer-limit replica 256mb 64mb 60 client-output-buffer-limit pubsub 32mb 8mb 60

当输出缓冲区超限,Redis 主动断开连接(避免 OOM)。

这些网络层优化,是 Redis原理及底层实现 中保障低延迟、高吞吐的又一核心支柱。

开发者高频问题解答

Q:Redis 单线程,如何处理大键(Big Key)导致的阻塞?

A:大键操作(如 HGETALL 100 万字段)会阻塞主线程。解决方案:

  • 使用 HSCAN 代替 HGETALL,分批读取
  • 设置 lua-time-limit(默认 5 秒),超时终止脚本
  • 监控 slowlog,定位慢命令
  • 对大键做分片(如 user:1001:field1, user:1001:field2)

Q:如何避免 Redis 穿透、击穿、雪崩?

A:

问题 现象 解决方案
穿透缓存无,DB 无 → 每次打到 DB布隆过滤器 + 空值缓存
击穿热点 Key 过期,瞬间大量请求打到 DB互斥锁 + 逻辑过期
雪崩大量 Key 同时过期 → DB 瞬间扛不住随机过期时间 + 二级缓存

Q:Redis 内存满了怎么办?如何设置合理上限?

A:

  • 物理内存 × 70% = maxmemory(预留空间给 OS 和碎片)
  • 策略选 allkeys-lru(通用缓存)或 volatile-lru(仅缓存带 TTL 的)
  • 监控 used_memory_peak,避免频繁触发淘汰

Q:Redis 如何做分布式?集群模式与哨兵模式区别?

A:

哨兵模式(Sentinel)

主从高可用:自动故障转移,但仍是单写(主节点)

集群模式(Cluster)

数据分片(16384 槽),支持水平扩展,但需客户端兼容

◆ 最新
heat exchanger 工作原理-热交换器工作原理贴吧二维码防删图原理-二维码防删图原理airpods定位的原理-Airpods 定位核心原理液晶屏工作原理及维修-液晶屏原理维修太阳能水位探头工作原理-太阳能水位探头工作原理直升机推进原理-直升机推进原理马自达cx8四驱工作原理-马自达 CX8 四驱工作原理v锥流量计原理动画-v 锥流量计原理动画可控硅控制电加热原理-可控硅电加热原理汽车手刹原理和保养-汽车手刹原理与保养明矾净水的原理方程式-明矾净水原理方程式微波双平衡混频器原理-微波双平衡混频器原理光伏发电原理讲解视频-光伏发电原理讲解视频蜂窝活性炭的吸附原理-活性炭吸附原理九阳电磁炉原理图 下载-九阳电磁炉原理图真空感应熔炼炉原理-真空感应熔炼原理安卓操作系统原理-安卓系统工作原理污水提升器原理-污水提升器工作原理车胎自补液原理-轮胎自补原理低失真音频电路原理-低失真音频电路原理vr原理详解-VR 原理详解初级抗阻动作及原理-初级抗阻动作与原理天然气锅炉原理介绍-天然气锅炉工作原理飞梭旋钮原理动画演示-飞梭原理动画演示非开挖钻机工作原理-非开挖钻机工作原理5mt变速箱工作原理-5MT 变速箱工作原理自动温度控制器原理图-自动温控器原理图光伏发电原理自制方法-自制光伏发电原理橡胶磨损原理-橡胶磨损基本机制zookeeper原理解析-zk 原理深度解析药代动力学实验原理-药代动力学实验原理喉咙异物感是什么原理-异物感源于咽喉黏膜牵拉充电芯片原理-充电芯片工作原理水表的结构和工作原理-水表结构与工作原理垃圾清理船的工作原理-垃圾清理船工作原理换热芯体原理-换热芯体工作原理热熔胶喷胶机原理-热熔胶喷胶机工作原理超声波塑胶熔接机原理-超声波塑胶熔接机原理荧光探针的原理-荧光探针原理简介qpcr原理详解-qpcr 原理详解法老之蛇实验原理-法老蛇实验原理短路保护工作原理-短路保护工作原理解真空回流焊的工作原理-真空回流焊工作原理真石漆喷涂机原理-真石漆喷涂机工作原理M2210的原理图设计图像处理器的工作原理-图像处理器工作原理精油的作用原理是什么-精油作用原理解析快排阀原理图解-快排阀原理图解话费慢充原理-话费慢充原理详解离心式过滤器原理图-离心过滤器原理图灭蚊器是什么原理-灭蚊器工作原理洗涤沉淀操作原理-洗涤原理与沉淀方法法士特取力器原理-法士特取力器工作原理气垫船原理与设计-气垫船原理与设计电子秤原理电路图-电子秤原理电路图电动机的原理与维修-电动机原理与维修作用式调压器工作原理-作用式调压器原理尼瑞克戒烟贴原理-尼瑞克戒烟贴原理无边泳池原理-泳池原理无边3d风扇原理图-3D 风扇原理图电动三通阀工作原理图-电动三通阀工作原理图串激电动机工作原理-串激电机工作原理电容原理差压传感器-差压电容传感器原理农用潜水泵原理-农用潜水泵工作原理阴极保护防腐技术原理-阴极保护防腐原理试漏机工作原理图-试漏机原理图str鉴定的原理-STR 鉴定原理介绍灭蚊灯的原理及图解-灭蚊灯原理图解削片机原理图解-削片机原理图解磷灰石定年原理-磷灰石定年原理360隔离沙箱原理-360沙箱隔离原理pcp自动回膛原理图-自动回膛原理图159减肥原理-160 减肥原理汽车刹车系统工作原理-汽车刹车系统工作原理纤磁纤惠减肥原理-纤磁纤惠减重原理(10 字)校园饮水机原理-校园饮水工作原理连杆传动的原理-连杆传动原理简述管壳式换热器原理-管壳式换热原理铜线剥皮机原理-铜线剥皮原理解析空气炸锅原理和微波炉一样吗-空气炸锅原理与微波炉是否相同车牌识别系统原理图-车牌识别系统原理图二向色镜的原理-二向色镜工作原理matlab随机数原理-matlab 随机数原理简化儿童玩具陀螺仪原理-儿童玩具陀螺仪原理铜的辟邪原理-铜制辟邪原理自动控制原理胡寿松ppt-自动控制原理胡寿松 PPT石膏 铸造 原理-石膏铸造原理电动伸缩看台结构原理-电动伸缩看台原理卧螺式离心机工作原理-卧螺离心机工作原理开式冷却塔工作原理-开式冷却塔工作原理总磷在线监测原理-总磷在线监测原理铁丝调直原理-铁丝调直原理风杯式风速表原理-风杯测速仪原理stm32功能板的原理图-stm32 功能板原理图电磁锁原理讲解-电磁锁原理说明晕车药的成分作用原理-晕车药成分及原理镍钯金打线原理-镍钯金打线原理简述蜗卷弹簧机械原理图-蜗卷弹簧原理图冷水机组制冷原理动画-冷水机组原理动画
瑞秋资讯
蜀ICP备2026006976号-18