Redis原理
Redis的持久化机制
Redis提供两种主要的持久化方式:RDB(Redis DataBase snapshot)和AOF(Append Only File)
RDB文件(全量)
-
RDB 是 Redis 的快照存储机制,即将某一时刻的数据以二进制格式保存到磁盘中。
-
工作原理:Redis 定期通过
fork
创建子进程,子进程将内存中的数据写入 RDB 文件。 主进程不会被阻塞,写入过程对客户端透明 -
触发方式:
- 手动触发:使用
SAVE
或BGSAVE
命令。 - 自动触发:根据
redis.conf
配置save
参数设定条件,比如 “某段时间内有多少次写操作”。
- 手动触发:使用
-
**优点:**Redis 直接加载 RDB文件,恢复到快照生成时的状态,这一步加载速度非常快,因为 RDB 是紧凑的二进制格式,内存映射效率高。
-
缺点:
-
数据可能丢失,最后一次快照后到服务器崩溃之间的数据无法恢复。
-
大数据量场景下,
fork
可能带来较大内存消耗。
-
AOF文件(增量)
-
AOF 是 Redis 的日志记录机制,通过记录每个写操作来实现持久化。
-
工作原理:
- 每次写命令(如
SET
、HSET
)都会被追加到 AOF 文件。 - AOF 文件会定期重写(rewrite),去除冗余命令以压缩文件大小。
- 每次写命令(如
-
触发方式:
- 自动触发:基于配置的
appendfsync
参数决定写入磁盘的频率。always
:每次写操作都同步到磁盘,最安全但性能较差。everysec
:每秒同步一次,性能和安全性平衡。no
:由操作系统自行决定同步时间,性能最佳但可能丢失数据。
- 自动触发:基于配置的
-
缺点:
- 文件体积大,比 RDB 更占磁盘空间。
- 恢复速度慢,需要逐条重放命令。
混合使用
- Redis 从 4.0 开始支持 RDB 和 AOF 混合持久化,结合两者优点,在重启时先加载 RDB 再重放 AOF 日志,既提高恢复速度又保证数据完整性。
**AOF 文件结构:**混合持久化生成的 AOF 文件可以分为两部分
-
RDB 部分: 前面的数据以 RDB 格式存储,表示当时内存状态的快照。
- RDB 提供初始快照数据,确保加载速度。
-
AOF 命令部分: 从快照生成后,记录的所有增量写操作命令。
- AOF 增量日志确保数据完整性。
-
这两部分共同组成一个文件,确保在恢复时,不会因重复加载数据而出错,同时Redis 的数据恢复速度和可靠性得到了显著提升。
独立的 RDB 文件:
- 即使启用了混合持久化模式,如果 Redis 配置文件中仍然开启了 RDB 自动生成(
save
参数配置),Redis 仍会按照配置的触发条件生成独立的 RDB 文件。 - 这些 RDB 文件与混合持久化文件分开存储,通常用于额外的快照备份。
AOF中的RDB文件与独立的RDB文件
- 混合持久化文件中的 RDB 数据主要用于辅助恢复时的快速加载。
- 独立的 RDB 文件是周期性快照存储,通常用于备份。
单线程
Redis 是一个 单线程 的高性能键值数据库。它通过使用单线程模型来处理所有的命令和操作,这意味着 所有客户端请求(命令)都通过一个线程来处理。单线程模型是 Redis 性能和响应速度的核心之
为什么要单线程?
- 减少上下文切换的开销: 在多线程程序中,操作系统需要频繁地切换不同线程的执行上下文。每次切换都会有额外的开销,特别是在高并发的情况下。而在 Redis 中,使用单线程就避免了这种上下文切换,程序的执行流非常简单且高效。
- 简化并发控制: 单线程避免了多线程编程中常见的同步和并发控制问题,例如锁竞争、死锁等。Redis 不需要额外的锁机制来保护数据的完整性,因为所有的操作都是按顺序执行的。
- 更高的缓存命中率: Redis 操作通常是基于内存的,单线程能够快速地访问内存,缓存命中率也因此提高。内存访问是现代计算机系统中最快的操作,单线程的操作能够保持其高效性。
Redis 单线程为何能处理高并发?
- 事件驱动: Redis 使用事件驱动模型来处理请求。它通过 I/O 多路复用机制,如
select()
、epoll()
、kqueue()
等,能够同时处理多个客户端请求。在这种模型下,Redis 能够快速地在一个线程内轮流处理多个客户端的 I/O 操作,而无需为每个连接创建独立的线程。 - 操作是原子的: Redis 命令在执行过程中是原子的,这意味着每个命令的执行都不会被其他命令中断。即使 Redis 是单线程的,每个操作依然能保证执行的一致性和完整性,不会受到其他命令的干扰。
为什么 Redis 仍然很快?
- 高效的内存操作:Redis 使用内存存储数据,内存的读写速度非常快,极大地提升了性能。
- 简单命令:Redis 的命令通常非常简单且执行时间短,因此即使是单线程,它依然能够在短时间内响应大量请求。
- 无锁设计:由于 Redis 的操作是单线程的,数据访问不需要加锁,因此避免了多线程程序中的竞争问题和同步开销。
- 无上下文切换:在 Redis 中,使用单线程就避免了上下文切换,程序的执行流非常简单且高效。