一、单点 Redis 的问题
- 数据丢失问题。Redis 是内存存储,一旦服务宕机重启,数据就有可能会丢失。
- 并发能力问题。单节点的 Redis 并发能力虽然不错,但也无法满足如 618、双 11 这样的高并发场景。
- 故障恢复问题。如果 Redis 宕机,则服务不可用,需要一种自动的故障恢复手段。
- 存储能力问题。Redis 是基于内存存储,但是内存存储是有上限的,而需要被缓存的数据会越来越多,那么单节点的 Redis 则难以满足海量数据的需求。
解决方案:
二、RDB 持久化
RDB 全称 Redis Database Backup file(Redis 数据备份文件),也被叫做 Redis 数据快照。简单来说,就是把内存中的所有数据都记录到磁盘中。当 Redis 实例故障后,从磁盘读取快照文件,恢复数据。
快照文件称为 RDB 文件,默认是保存在当前运行目录,即当前在哪个目录下运行 Redis 就保存在哪个目录下。
2.1.执行时机
RDB持久化在四种情况下会执行:
- 执行save命令
- 执行bgsave命令
- Redis停机时
- 触发RDB条件时
1)save命令
要想让 Redis 执行 RDB,可以使用 redis-cli 命令连接 Redis 客户端,然后执行 save 命令:
save 命令是由 Redis 主进程来执行的,一旦主进程执行 RDB,就会阻塞所有命令。如果数据量比较大,那么执行 RDB 的时间就会比较久,若此时有其他命令,那么就需要等待 RDB 执行结束。这种方式一般不推荐使用,一般适用于在停止 Redis 服务前执行。
2)bgsave 命令
一般推荐使用 bgsave,该命令会开启一个子进程,由子进程执行 RDB,主进程则不受影响,可继续执行其他命令。比较适合于在 Redis 运行过程中使用。
3)Redis 停机时
一般 Redis 在停机时会自动执行一次 RDB。
Redis 重启后会自动加载 RDB 中保存的数据。
4)触发 RDB 条件时
Redis 内部有触发 RDB 的机制,可以在 redis.conf 文件中找到,格式如下:
RDB 的其他配置也可以在 redis.conf 文件中设置:
dir 默认为Redis启动时,命令行所在的目录下。
2.2 RDB 的 fork 原理
bgsave 开始时会 fork 主进程得到子进程,子进程共享主进程的内存数据。完成 fork 后读取内存数据并写入 RDB 文件。
Redis 主进程要在内存中实现对数据的读写。在 Linux 系统中,所有的进程都无法直接操作物理内存,而是操作系统给每个进程分配一个虚拟内存。Redis 中的主进程只能操作虚拟内存,操作系统会维护一个虚拟内存与物理内存之间的映射表,这个表被称之为页表。主进程操作虚拟内存,而虚拟内存基于页表的映射关系到物理内存,这样就可以实现对物理内存的读写。而在执行 fork 的时候,主进程会创建一个子进程,fork 的过程并不会将内存数据做拷贝,而仅仅只是将页表进行了拷贝,即将映射关系拷贝给了子进程。这样子进程就有了与主进程相同的映射关系,当子进程在操作自己的虚拟内存时,因为映射关系与主进程相同,最终就会映射到相同的物理内存,这样也就实现了子进程与主进程之间的内存空间共享,因而无需拷贝内存中的数据,而是直接实现内存共享,这样 fork 的速度就会变得非常快,阻塞的时间也就尽可能地缩短了。之后,子进程通过读取自己内存中的数据,再将这些数据写入到磁盘当中,去替换旧的 rdb 文件。
子进程在写 rdb 文件的过程中,主进程是可以接收用户的请求,修改内存中的数据,如果此时主进程在修改数据,而子进程同时在写数据,那么读与写之间就有可能产生冲突,产生脏数据。为了避免这种情况的发生,fork 的底层采用了一种 copy-on-write 的技术:
- 当主进程执行读操作时,访问共享内存;
- 当主进程执行写操作时,则会拷贝一份数据,执行写操作。
当主进程需要写数据的时候,fork 首先会将共享内存标记为 read-only,并将需要操作的数据拷贝一份出来,对其进行写操作。
2.3 总结
RDB 方式 bgsave 的基本流程?
- fork 主进程得到一个子进程,共享内存空间
- 子进程读取内存数据并写入新的 RDB 文件
- 用新的 RDB 文件替换旧的 RDB 文件。
RDB会在什么时候执行?save 60 1000 代表什么含义?
- 默认服务停止时
- 代表 60 秒内至少执行 1000 次修改则触发 RDB
RDB 的缺点?
- RDB 执行间隔时间长,两次 RDB 之间写入数据有丢失的风险
- fork 子进程、压缩、写出 RDB 文件都比较耗时
三、AOF 持久化
3.1 AOF 原理
AOF 全称为 Append Only File(追加文件)。Redis 处理的每一个命令都会记录在 AOF 文件中,可以看做是命令日志文件。
3.2 AOF 配置
AOF 默认是关闭的,需要修改 redis.conf 配置文件来开启 AOF:
AOF 的命令记录的频率也可以通过 redis.conf 文件来配:
三种配置对比:
3.3 AOF 文件重写
因为是记录命令,AOF 文件会比 RDB 文件大的多。而且 AOF 会记录对同一个 key 的多次写操作,但只有最后一次写操作才有意义。通过执行 bgrewriteaof 命令,可以让 AOF 文件执行重写功能,用最少的命令达到相同效果。
set num 命令执行了两次,但是由于执行了 berewriteaof 命令,只有最后一次的命令才有意义,那么就可以将 set num 123
抛弃不要,而只保留最后两条,而最后两条由于都是 set 命令,可以合并为 MSET 执行。
可以看出在执行bgrewriteaof
命令后,aof 的重写动作是异步执行的。Redis 也会在触发阈值时自动去重写 AOF 文件。阈值也可以在 redis.conf 中配置:
四、RDB 与 AOF 对比
RDB 和 AOF 各有自己的优缺点,如果对数据安全性要求较高,在实际开发中往往会结合两者来使用。两者同时使用时,在 Redis 重启后,会以 AOF 优先来做恢复。