Redis 底层运行机制与原理浅析

文章目录

一、核心架构:事件驱动与单线程模型

Redis 采用 单线程事件驱动架构,通过 epoll/kqueue 实现 I/O 多路复用。其核心事件循环(aeEventLoop)持续监听两类事件:

  1. 文件事件:Socket 可读/可写状态(客户端请求/响应)
  2. 时间事件:定时任务(如过期键清理、持久化触发)

工作流程:主线程通过 epoll_wait() 等系统调用获取就绪事件 → 调用对应处理器(如 readQueryFromClient 解析命令)→ 执行命令 → 返回结果。这种设计避免了多线程锁竞争,但需确保单线程操作高效。

二、内存数据结构与动态编码

Redis 通过 redisObject 结构统一管理数据,其字段包括:

  • type:数据类型(String/List 等)
  • encoding:内部编码(如 ziplist/hashtable)
  • lru:LRU 时间戳(内存淘汰用)
  • refcount:引用计数(内存回收依据)
  • ptr:指向实际数据的指针

动态编码优化策略:

数据类型 编码方式 触发条件 性能特点
String int/embstr/raw 整数 → int;≤44字节 → embstr;大对象 → raw embstr 减少内存分配次数
List quicklist Redis 3.2+ 替代 ziplist/linkedlist,由 ziplist 节点+双向链表组成 平衡内存与操作效率
Hash ziplist/hashtable 元素少且值小 → ziplist;超阈值 → hashtable 节省小对象内存
Set intset/hashtable 全为整数 → intset;否则 → hashtable 整数集合压缩存储
ZSet ziplist/skiplist 元素少且分数小 → ziplist;否则 → skiplist 跳表支持快速范围查询
Stream radix tree + listpack 基数树索引消息 ID,listpack 存储消息内容 高效支持消息遍历

编码转换:当数据量超过阈值(如 ziplist 大小 > hash-max-ziplist-entries)时自动切换编码。

三、内存管理与碎片整理

1. 内存分配器

默认使用 jemalloc,其优势:

  • 按内存大小分级(small/large/huge)分配
  • 减少外部碎片,碎片率通常 ≈1.03
  • 支持后台线程异步释放内存(Lazy Free)

2. 内存淘汰策略

当达到 maxmemory 限制时触发:

  • LRU/LFU 近似算法:随机采样 5 个键(maxmemory-samples配置),淘汰最符合策略的键
  • LFU 实现:用概率计数器记录访问频率,并随时间衰减

3. 主动碎片整理(Active Defrag)

  • 触发:碎片率 > active-defrag-threshold-lower(默认 10%)
  • 过程:扫描内存 → 复制碎片化对象到新位置 → 释放原内存
  • 限制:需配合 jemalloc,每周期 CPU 占用 ≤ active-defrag-cycle-max(默认 25%)

四、持久化机制:RDB 与 AOF

1. RDB(快照持久化)

  • 流程:fork() 子进程 → 子进程遍历内存生成 RDB 文件 → 替换旧文件
  • COW 优化:父进程继续处理请求,仅当内存页被修改时复制
  • 触发:save(阻塞)、bgsave(后台)、配置自动触发(如 save 900 1)

2. AOF(日志持久化)

  • 流程:所有写命令追加到 AOF 缓冲区 → 根据策略(always/everysec/no)同步至磁盘
  • 重写:fork() 子进程生成精简版 AOF(只保留当前数据状态)
  • 混合持久化(Redis 4.0+):AOF 重写时嵌入 RDB 格式头,加速恢复

性能对比:

特性 RDB AOF
文件大小 小(二进制) 大(文本命令)
恢复速度
数据安全 可能丢失快照间数据 最多丢失 1 秒数据

五、复制与集群架构

1. 主从复制流程

  • 复制积压缓冲区:主节点维护环形缓冲区(默认 1MB),保存近期写命令
  • 无磁盘复制:RDB 数据直接流式传输到从节点,跳过磁盘 I/O(repl-diskless-sync yes)

2. 集群(Cluster)原理

  • 分片机制:16384 个哈希槽均匀分布到节点
  • Gossip 协议:节点间定期交换状态(PING/PONG/MEET/FAIL 消息)
  • 故障转移:当主节点下线,从节点发起投票选举新主节点

六、高级特性实现

1. Lua 脚本引擎

  • 原子性:单线程执行脚本期间阻塞其他命令
  • 执行环境:伪客户端模式调用 Redis 命令
  • 复制:主节点传播 EVALSHA + 脚本 SHA1,从节点通过 repl_scriptcache_dict 缓存

2. I/O 多线程(Redis 6.0+)

  • 线程分工:I/O 线程负责网络读写,主线程执行命令
  • 配置:io-threads 4 启用线程,io-threads-do-reads yes 启用读线程化
  • 效果:吞吐量提升 2 倍,但命令仍串行执行保证正确性

3. 模块系统

  • 加载:MODULE LOAD /path/to/module.so
  • API:RedisModule_CreateCommand 注册新命令
  • 交互:通过模块 API 访问核心数据结构(如 RedisModule_StringSet)

总结

Redis 的底层运行机制是一个精心设计的系统工程:

  • 以内存为核心,提供了极快的访问速度。

  • 精巧的数据结构,在速度与内存之间取得了最佳平衡。

  • 单线程 Reactor 模型,避免了并发复杂性,配合 I/O 多路复用轻松应对高并发。

  • 灵活可配的持久化方案(RDB, AOF, 混合),满足了不同场景下的数据安全需求。

  • 渐进式的优化策略(渐进式 rehash、惰性删除、后台线程化),保证了服务的平滑运行。

相关推荐
爱吃烤鸡翅的酸菜鱼2 小时前
Java【缓存设计】定时任务+分布式锁实战:Redis vs Redisson实现状态自动扭转以及全量刷新预热机制
java·redis·分布式·缓存·rabbitmq
我科绝伦(Huanhuan Zhou)2 小时前
Redis 生产环境安全基线配置指南:从风险分析到实操加固
数据库·redis·安全
彩旗工作室2 小时前
如何在自己的服务器上部署 n8n
开发语言·数据库·nodejs·n8n
小白起 v2 小时前
自动更新工期触发器(MYSQL)
数据库·sql·oracle
JIngJaneIL2 小时前
数码商城系统|电子|基于SprinBoot+vue的商城推荐系统(源码+数据库+文档)
java·前端·数据库·vue.js·论文·毕设·数码商城系统
堕落年代4 小时前
Spring三级缓存通俗易懂讲解
java·spring·缓存
~我爱敲代码~5 小时前
使用XSHELL远程操作数据库
数据库·adb
资深web全栈开发10 小时前
如何正确使用缓存:常见陷阱与最佳实践
redis·缓存·golang
春风霓裳11 小时前
sql-窗口函数
大数据·数据库·sql