一、单点 Redis 的问题

  • 数据丢失问题。Redis 是内存存储,一旦服务宕机重启,数据就有可能会丢失。
  • 并发能力问题。单节点的 Redis 并发能力虽然不错,但也无法满足如 618、双 11 这样的高并发场景。
  • 故障恢复问题。如果 Redis 宕机,则服务不可用,需要一种自动的故障恢复手段。
  • 存储能力问题。Redis 是基于内存存储,但是内存存储是有上限的,而需要被缓存的数据会越来越多,那么单节点的 Redis 则难以满足海量数据的需求。

解决方案:

redis 内存不够 宕机 redis rdb内存过半_分布式

二、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 命令:

redis 内存不够 宕机 redis rdb内存过半_分布式_02


save 命令是由 Redis 主进程来执行的,一旦主进程执行 RDB,就会阻塞所有命令。如果数据量比较大,那么执行 RDB 的时间就会比较久,若此时有其他命令,那么就需要等待 RDB 执行结束。这种方式一般不推荐使用,一般适用于在停止 Redis 服务前执行。

2)bgsave 命令

一般推荐使用 bgsave,该命令会开启一个子进程,由子进程执行 RDB,主进程则不受影响,可继续执行其他命令。比较适合于在 Redis 运行过程中使用。

redis 内存不够 宕机 redis rdb内存过半_Redis_03

3)Redis 停机时

一般 Redis 在停机时会自动执行一次 RDB。

redis 内存不够 宕机 redis rdb内存过半_redis_04


Redis 重启后会自动加载 RDB 中保存的数据。

4)触发 RDB 条件时

Redis 内部有触发 RDB 的机制,可以在 redis.conf 文件中找到,格式如下:

redis 内存不够 宕机 redis rdb内存过半_Redis_05


RDB 的其他配置也可以在 redis.conf 文件中设置:

redis 内存不够 宕机 redis rdb内存过半_Redis_06


dir 默认为Redis启动时,命令行所在的目录下。

2.2 RDB 的 fork 原理

bgsave 开始时会 fork 主进程得到子进程,子进程共享主进程的内存数据。完成 fork 后读取内存数据并写入 RDB 文件。

Redis 主进程要在内存中实现对数据的读写。在 Linux 系统中,所有的进程都无法直接操作物理内存,而是操作系统给每个进程分配一个虚拟内存。Redis 中的主进程只能操作虚拟内存,操作系统会维护一个虚拟内存与物理内存之间的映射表,这个表被称之为页表。主进程操作虚拟内存,而虚拟内存基于页表的映射关系到物理内存,这样就可以实现对物理内存的读写。而在执行 fork 的时候,主进程会创建一个子进程,fork 的过程并不会将内存数据做拷贝,而仅仅只是将页表进行了拷贝,即将映射关系拷贝给了子进程。这样子进程就有了与主进程相同的映射关系,当子进程在操作自己的虚拟内存时,因为映射关系与主进程相同,最终就会映射到相同的物理内存,这样也就实现了子进程与主进程之间的内存空间共享,因而无需拷贝内存中的数据,而是直接实现内存共享,这样 fork 的速度就会变得非常快,阻塞的时间也就尽可能地缩短了。之后,子进程通过读取自己内存中的数据,再将这些数据写入到磁盘当中,去替换旧的 rdb 文件。

redis 内存不够 宕机 redis rdb内存过半_缓存_07


子进程在写 rdb 文件的过程中,主进程是可以接收用户的请求,修改内存中的数据,如果此时主进程在修改数据,而子进程同时在写数据,那么读与写之间就有可能产生冲突,产生脏数据。为了避免这种情况的发生,fork 的底层采用了一种 copy-on-write 的技术:

  • 当主进程执行读操作时,访问共享内存;
  • 当主进程执行写操作时,则会拷贝一份数据,执行写操作。

当主进程需要写数据的时候,fork 首先会将共享内存标记为 read-only,并将需要操作的数据拷贝一份出来,对其进行写操作。

redis 内存不够 宕机 redis rdb内存过半_分布式_08

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 文件中,可以看做是命令日志文件。

redis 内存不够 宕机 redis rdb内存过半_缓存_09

3.2 AOF 配置

AOF 默认是关闭的,需要修改 redis.conf 配置文件来开启 AOF:

redis 内存不够 宕机 redis rdb内存过半_分布式_10


AOF 的命令记录的频率也可以通过 redis.conf 文件来配:

redis 内存不够 宕机 redis rdb内存过半_分布式_11


三种配置对比:

redis 内存不够 宕机 redis rdb内存过半_redis 内存不够 宕机_12

3.3 AOF 文件重写

因为是记录命令,AOF 文件会比 RDB 文件大的多。而且 AOF 会记录对同一个 key 的多次写操作,但只有最后一次写操作才有意义。通过执行 bgrewriteaof 命令,可以让 AOF 文件执行重写功能,用最少的命令达到相同效果。

redis 内存不够 宕机 redis rdb内存过半_分布式_13


set num 命令执行了两次,但是由于执行了 berewriteaof 命令,只有最后一次的命令才有意义,那么就可以将 set num 123 抛弃不要,而只保留最后两条,而最后两条由于都是 set 命令,可以合并为 MSET 执行。

redis 内存不够 宕机 redis rdb内存过半_缓存_14


可以看出在执行bgrewriteaof命令后,aof 的重写动作是异步执行的。Redis 也会在触发阈值时自动去重写 AOF 文件。阈值也可以在 redis.conf 中配置:

redis 内存不够 宕机 redis rdb内存过半_redis 内存不够 宕机_15

四、RDB 与 AOF 对比

RDB 和 AOF 各有自己的优缺点,如果对数据安全性要求较高,在实际开发中往往会结合两者来使用。两者同时使用时,在 Redis 重启后,会以 AOF 优先来做恢复。

redis 内存不够 宕机 redis rdb内存过半_分布式_16