当前位置: 首页 > news >正文

《Redis核心机制解析》

一、Redis 简介

(一)Redis 是什么

Redis是一款开源的、高性能的键值对存储系统。它以内存作为主要数据存储介质,兼具数据持久化能力,支持丰富的数据结构,能充当数据库、缓存和消息中间件等多种角色。

(二)Redis 常见的五种数据类型

1. String

String 是 Redis 最基础的数据类型,一个键对应一个字符串值。其底层常通过动态字符串(SDS)实现,既保证字符串操作的高效性,又规避了 C 语言原生字符串的缺陷。

String 能存普通文本,图片等二进制数据(经序列化后存储)。如存储用户昵称、商品库存数量,或者进行简单计数(如文章阅读量)。

2. List

List 是基于双向链表结构的列表,每个元素小于64字节,元素个数小于512用压缩列表否则用双向链表存储。它支持从链表两端进行操作,如左推(LPUSH)、右弹(RPOP)等。

List 适合实现消息队列。生产者用LPUSH将消息推到队列左端,消费者用 RPOP从队列右端取消息。

3. Hash

Hash 是键值对的集合,每个元素小于64字节,元素个数小于512用压缩列表,否则用哈希表存储,类似 “字典的字典”,适合存储对象。比如存储用户信息时,用户 ID 作为外层键,“name”“age”“email” 等作为内层键,对应的值为用户具体信息。

4. Set

Set 是无序的字符串集合,元素都是整数且元素个数小于512用整数集合否则用哈希表。

Set 支持交集、并集、差集等集合运算,在社交应用中,可求两个用户的共同好友(通过两个好友 Set 的交集);统计网站独立访客数时,用 Set 存储访客 ID,自动过滤重复 ID。

5. ZSet

ZSet(Sorted Set)是有序的字符串集合元素个数小于128每个元素值小于64字节用压缩列表否则用调表,跳表保障元素有序性和范围查询高效性,压缩列表在数据量小时节省内存。

(三)Redis 与 Memcached 的区别

1. 相同点

  • 基于内存:二者数据主要存储在内存,都有极高的读写性能,适合作为缓存加速数据访问。
  • 过期策略:都支持为数据设置过期时间,数据过期时会从内存删除,实现缓存自动淘汰。

2. 不同点

  • 数据类型Redis 支持 String、List、Hash、Set、ZSet 等丰富数据类型,能满足复杂业务场景;Memcached 仅支持简单键值对(String 类型),处理复杂数据结构能力不足。
  • 持久化Redis 支持 RDB 和 AOF 两种持久化方式,可将数据保存到磁盘,服务器重启后数据能恢复;Memcached 不支持持久化,服务器重启数据全部丢失。
  • 数据一致性Redis 支持主从复制、哨兵模式和集群模式,能一定程度保证数据高可用性与一致性;Memcached 无内置复制机制,分布式环境下数据一致性保障较弱。
  • 集群模式Redis 支持原生集群模式,无需依赖客户端即可实现数据分片与高可用;Memcached 无原生集群模式,需依靠客户端实现数据分布式存储。
  • 发布 / 订阅Redis 支持发布 / 订阅模式,可实现消息多播;Memcached 不支持此功能

(四)为何用 Redis 而非 MySQL 缓存

1. 高性能

MySQL 是关系型数据库数据存储在磁盘,磁盘读写速度远慢于内存。Redis 数据存储在内存,读写操作接近内存级速度,能极大提升数据访问效率。对于热点数据(如网站首页热门商品信息),用 Redis 缓存后,用户请求可直接从 Redis 获取,无需每次查询 MySQL,减轻 MySQL 压力,提高系统响应速度。

2. 高并发

Redis 采用高效事件处理机制和单线程(或多线程,不同版本有优化)模型,能轻松应对高并发请求。MySQL 在高并发场景下,受锁机制、磁盘 I/O 等因素影响,性能明显下降。例如秒杀活动中,大量用户同时请求商品库存信息,Redis 可快速响应,避免 MySQL 因并发过高出现瓶颈。

二、Redis 线程模型

(一)为何是单线程

Redis 采用单线程模型,主要原因如下:

  • 内存操作高效:Redis 大部分操作在内存中完成,内存操作速度极快,单线程足以处理多数场景请求。相比多线程,单线程避免了线程切换的上下文切换开销与多线程间锁竞争问题,保证操作高效性。
  • 避免线程竞争:多线程环境下,为保证数据一致性往往需引入锁机制,锁的使用会带来性能损耗。单线程模型天然无线程竞争问题,无需使用锁,简化程序设计,提升性能。
  • 采用 I/O 多路复用:Redis 使用 I/O 多路复用技术 ,单线程可同时监听多个客户端的连接请求与数据读写请求。当有客户端请求到达时,I/O 多路复用机制通知 Redis 处理,实现单线程处理多客户端并发请求的能力。

(二)单线程与多线程的区别 

1. Redis 6.0 前(纯单线程)

Redis 6.0 之前,主要采用纯单线程模型处理客户端请求。所有网络 I/O 操作(如客户端连接建立、数据读写)与命令执行都由一个主线程完成。

这种模型的优点是简单、无锁竞争,能保证命令执行的原子性。但缺点是处理耗时操作(如大键删除、数据持久化)时,会阻塞主线程,导致其他客户端请求无法及时响应,影响系统吞吐量。

2. Redis 6.0 及以后(I/O 多线程优化)

Redis 6.0 引入 I/O 多线程特性,将网络 I/O 操作(如客户端的读取和写入)与命令执行分离。具体而言,Redis 会创建多个 I/O 线程专门处理客户端的网络 I/O 操作,命令执行仍由主线程负责。

这样做的好处是,将耗时的网络 I/O 操作从主线程剥离,交给专门的 I/O 线程处理,减少主线程阻塞时间,提升系统并发处理能力。例如,大量客户端同时发送请求时,多个 I/O 线程可并行读取客户端数据,再将数据交给主线程执行命令,主线程执行完命令后,由 I/O 线程将结果写回客户端。

(三)形象比喻理解 Redis 线程模型

可将 Redis 比作 “仓库管理员” 来理解其线程模型:

  • 纯单线程(Redis 6.0 前):一个人既当 “快递员”(接收客户端网络 I/O 请求),又当 “仓库管理员”(执行命令、操作数据)。所有 “顾客”(客户端)的命令必须排队,前一个人办理完,下一个人才能办。若 “柜员”(主线程)处理耗时 “业务”(如大键删除),后面的 “顾客” 只能等待。
  • I/O 多线程(Redis 6.0 及以后)把 “网络 I/O 操作”(接收和发送数据)拆分为专门的 “多线程处理”,比如安排 3 个 “快递员”(I/O 线程)负责接收 “顾客” 请求和返回结果,“仓库管理员”(主线程)只负责处理 “业务”(执行命令)。“快递员” 可并行接收多个 “顾客” 请求,再交给 “仓库管理员” 处理,“仓库管理员” 处理完后,“快递员” 再把结果返回给 “顾客”,从而提高整体效率,减少 “顾客” 等待时间。

三、Redis 持久化

Redis 提供 RDB(Redis DataBase)和 AOF(Append Only File)两种主要持久化方式,可将内存数据保存到磁盘,防止数据丢失。

(一)RDB 持久化

1. 原理

RDB 持久化通过创建快照,将 Redis 某一时刻的数据集保存到磁盘的二进制文件(通常为 dump.rdb)。

Redis 执行 RDB 持久化的过程:

  • 触发快照可手动执行 SAVE或 BGSAVE命令触发。SAVE命令在主线程执行快照操作,会阻塞所有客户端请求,直到快照完成;BGSAVE命令创建子进程,由子进程执行快照操作,主线程仍可处理客户端请求,不会阻塞。
  • 生成 RDB 文件:子进程先将数据写入临时文件,快照完成后,再用临时文件替换原来的dump.rdb文件,保证 dump.rdb文件的完整性,避免写入过程中文件损坏。

2. 优点

  • 性能好:BGSAVE命令在子进程执行快照操作,不阻塞主线程,对 Redis 正常服务影响小。
  • 恢复速度快:RDB 文件为二进制格式,加载时无需复杂解析操作,数据恢复速度比 AOF 快很多,适合大规模数据恢复场景。

3. 缺点

  • 数据完整性不足:RDB 是定时快照,若两次快照之间 Redis 宕机,这段时间内的数据会丢失。例如,快照间隔设为 5 分钟,Redis 在快照后的 3 分钟宕机,这 3 分钟内的数据就会丢失。
  • 对大内存不友好:Redis 内存数据量很大时,BGSAVE命令创建子进程需复制父进程内存页表,会消耗较多系统资源,可能导致 Redis 暂时卡顿。

(二)AOF 持久化

1. 原理

AOF 持久化通过记录 Redis 服务器执行的所有写命令实现数据持久化。这些命令会追加到 AOF 文件末尾,Redis 重启时,重新执行 AOF 文件中的命令即可恢复数据。

AOF 持久化的工作流程:

  • 命令追加:Redis 执行写命令时,会将该命令以协议格式追加到 AOF 缓冲区。
  • 文件同步:AOF 缓冲区中的命令会根据配置的同步策略(always、everysec、no)同步到磁盘的 AOF 文件.always表示每次写命令都同步到磁盘,数据安全性最高,但性能影响最大;everysec表示每秒同步一次,在性能和数据安全性间取得平衡;no 表示由操作系统决定何时同步,性能最好,但数据安全性最低。
  • AOF 重写:随着时间推移,AOF 文件会因记录大量重复或可合并的命令而越来越大。AOF 重写通过扫描当前 Redis 内存数据,生成一组新的、更简洁的命令替代原命令序列,减小 AOF 文件大小。AOF 重写可通过 BGREWRITEAOF命令手动触发,也可根据配置自动触发。

2. 优点

  • 数据完整性高:AOF 实时或准实时记录写命令,数据丢失可能性小
  • 文件可读性好:AOF 文件是纯文本格式,记录的是 Redis 命令,方便查看、编辑,甚至可手动修改 AOF 文件修复数据。

3. 缺点

  • 文件体积大:AOF 文件记录所有写命令,相比 RDB 文件,体积通常更大,占用磁盘空间更多。
  • 恢复速度慢:AOF 文件需重新执行所有命令恢复数据,数据量较大时,恢复速度比 RDB 慢很多。

(三)两种持久化方式的选择

实际应用中,需根据业务需求选择持久化方式:

  • 若业务对数据完整性要求不高,追求高性能和快速恢复,可选择 RDB 持久化。如一些缓存场景,部分数据丢失可从后端数据库重新加载。
  • 若业务对数据完整性要求高,不能容忍大量数据丢失应选择 AOF 持久化,或同时开启 RDB 和 AOF 持久化(Redis 支持同时开启,重启时优先加载 AOF 文件恢复数据)。如金融交易系统等对数据一致性要求极高的场景。

四、Redis 删除策略

Redis 内存不足时,需淘汰数据释放内存空间,提供了基于过期时间的删除策略和基于内存淘汰的删除策略。

(一)基于过期时间的删除策略

1. 定时删除

设置键的过期时间时,创建定时器,键的过期时间到达时,定时器立即触发,执行对该键的删除操作。

优点是能保证过期键尽快被删除,释放内存空间,数据时效性好。缺点是若有大量键设置过期时间,会创建大量定时器,消耗系统资源,影响 Redis 性能。

2. 惰性删除

只有当客户端访问某个键时,才会检查该键是否过期,若过期则删除

优点是不会在过期键上浪费过多系统资源,对 Redis 性能影响小。缺点是过期键若长期不被访问,会一直占用内存空间,导致内存浪费。

3. 定期删除

Redis 会定期(默认每秒 10 次)随机抽取一定数量设置了过期时间的键,检查并删除其中过期的键。

这种策略是定时删除和惰性删除的折中,既不会像定时删除那样消耗过多系统资源,也能一定程度上避免惰性删除导致的内存浪费问题。

(二)基于内存淘汰的删除策略

Redis 使用内存存储数据,执行每个命令前,会调用freeMemoryIfNeeded()检测内存是否充足。若内存不满足新加入数据的最低存储要求,Redis 会临时删除一些数据为当前指令清理存储空间。基于内存淘汰的删除策略又可分为检测易失数据(设置了过期时间的数据)和检测全库数据(所有数据)两类,具体有以下几种:

1. 检测易失数据

  • volatile - lru:从设置了过期时间的键中,挑选最近最少使用的数据淘汰。
  • volatile - lfu:从设置了过期时间的键中,挑选最近使用次数最少的数据淘汰。
  • volatile - ttl:从设置了过期时间的键中,挑选将要过期(剩余过期时间最短)的数据淘汰。
  • volatile - random:从设置了过期时间的键中,任意选择数据淘汰

2. 检测全库数据

  • allkeys - lru:从所有键中,挑选最近最少使用的数据淘汰。
  • allkeys - lfu:从所有键中,挑选最近使用次数最少的数据淘汰。
  • allkeys - random:从所有键中,任意选择数据淘汰。
  • no - eviction禁止驱逐数据(Redis 4.0 中默认策略),内存不足时会引发 “Out Of Memory”(OOM)错误。

实际应用中,需根据业务场景选择合适的内存淘汰策略。例如,若业务中缓存的是热点数据,可选择 allkeys - lru策略,优先淘汰最近最少使用的非热点数据;若业务对数据访问频率更敏感,可选择 策略。


文章转载自:

http://BOgAbqh0.ctLjs.cn
http://kVLJmX6x.ctLjs.cn
http://QEPkLz8H.ctLjs.cn
http://AOZC4upF.ctLjs.cn
http://Hq0zYNpV.ctLjs.cn
http://pFvh2PL4.ctLjs.cn
http://3ygJ9raO.ctLjs.cn
http://WwYmvtoo.ctLjs.cn
http://OiMmilJZ.ctLjs.cn
http://Ad3ODFI4.ctLjs.cn
http://WgaFa9D6.ctLjs.cn
http://BOVC9dfw.ctLjs.cn
http://fbzRErZd.ctLjs.cn
http://zLxwbJ3z.ctLjs.cn
http://DYZGtGHF.ctLjs.cn
http://2j0VbPqv.ctLjs.cn
http://RYeHSczs.ctLjs.cn
http://1Nu94luy.ctLjs.cn
http://K3Fs3GXZ.ctLjs.cn
http://Ehvjjlip.ctLjs.cn
http://YEf3ZBLv.ctLjs.cn
http://oi16stmi.ctLjs.cn
http://2rU3eElD.ctLjs.cn
http://zq9UDS0p.ctLjs.cn
http://yZ4nr6Nj.ctLjs.cn
http://FdXBtMwk.ctLjs.cn
http://6pa72r43.ctLjs.cn
http://uB4ckBWl.ctLjs.cn
http://rOvT7OpX.ctLjs.cn
http://7Yxdrow5.ctLjs.cn
http://www.dtcms.com/a/379808.html

相关文章:

  • Netty 在 API 网关中的应用篇(请求转发、限流、路由、负载均衡)
  • 金蝶云星空插件开发记录(一)
  • Knockout-ES5 入门教程
  • 基于 Art_DAQ、InfluxDB 和 PyQt 的传感器数据采集、存储与可视化
  • 【图像处理基石】图像压缩有哪些经典算法?
  • C语言实战:简单易懂通讯录
  • youte-agent部署(windows)
  • Python实现点云法向量各种方向设定
  • Linnux IPC通信和RPC通信实现的方式
  • apache实现LAMP+apache(URL重定向)
  • MongoDB 与 GraphQL 结合:现代 API 开发新范式
  • k8s-临时容器学习
  • uni-app 根据用户不同身份显示不同的tabBar
  • ubuntu18.04安装PCL1.14
  • Ubuntu 系统下 Anaconda 完整安装与环境配置指南(附常见问题解决)
  • 网络链路分析笔记mtr/traceroute
  • 在 Ubuntu 系统中利用 conda 创建虚拟环境安装 sglang 大模型引擎的完整步骤、版本查看方法、启动指令及验证方式
  • 基带与射频的区别与联系
  • 《企业安全运营周报》模板 (极简实用版)​
  • opencv基于SIFT特征匹配的简单指纹识别系统实现
  • Node.js 操作 Elasticsearch (ES) 的指南
  • 使用tree命令导出文件夹/文件的目录树( Windows 和 macOS)
  • Spring缓存(二):解决缓存雪崩、击穿、穿透问题
  • LabVIEW加载 STL 模型至 3D 场景 源码见附件
  • Tessent_ijtag_ug——第 4 章 ICL 提取(2)
  • 前端WebSocket实时通信实现
  • 2025年- H133-Lc131. 反转字符串(字符串)--Java版
  • 萨顿四条原则
  • NumPy 2.x 完全指南【三十八】伪随机数生成器
  • GitHub 热榜项目 - 日榜(2025-09-12)