Redis 是一个基于内存的键值存储 系统,它使用内存存储数据,以提供快速读写访问。内存存储的数据是容易丢失的,这就意味着如果Redis一旦奔溃或者重启,所有数据都将丢失。为了解决这个问题,Redis引入了持久化机制,它允许Redis将内存中的数据异步或同步地写入磁盘中,以便在Redis重启时能够从磁盘中恢复数据。
Redis支持两种持久化机制:RDB和AOF 。快照是一次全量备份,AOF 日志是连续的增量备份 。快照是内存数据的二进制序列化形式,在存储上非常紧凑,而 AOF 日志记录的是内存数据修改的指令记录文本。
RDB快照
RDB(Redis DataBase) 可以在指定的时间间隔内生成数据集的时间点快照(point-in-time snapshot) ,以二进制的方式写入磁盘。它是Redis默认的持久化方式。使用RDB持久化方式会生成一个名为 dump.rdb 的文件,文件名是可以通过配置文件修改的。RDB持久化分为两种方式:手动触发和自动触发。
手动触发是指手动执行 save 、bgsave 、flushall 命令
-
save :使 Redis 处于阻塞状态,直到 RDB 持久化完成,才会响应其他客户端发来的命令,所以在生产环境一定要慎用。
-
bgsave :Redis会fork出一个子进程执行持久化生成dump.rdb 文件,主进程只在fork过程中有短暂的阻塞,子进程创建之后,主进程就可以响应客户端请求了。
-
flushall :该命令会删除Redis的所有数据并清空dump.rdb 文件,相当于删库,如果没有dump.rdb 文件会生成一个空的dump.rdb文件。
因为BGSAVE命令可以在不阻塞服务器进程的情况下执行,所以推荐使用BGSAVE命令。
我们可以通过save选项设置多个保存条件,只要其中任意一个条件被满足,服务器就会执行BGSAVE命令。
save选项设置的默认条件如下所示:
save 900 1
save 300 10
save 60 10000
默认的配置条件表示,只要满足以下3个条件中的任意1个,BGSAVE命令就会被执行:
- 服务器在900s(即15分钟)之内,对数据库进行了至少1次修改
- 服务器在300s(即5分钟)之内,对数据库进行了至少10次修改
- 服务器在60s(即1分钟)之内,对数据库进行了至少10000次修改
Redis载入RDB文件并没有专门的命令,而是在Redis服务器启动时自动执行的。
Redis服务器启动时是否会载入RDB文件还取决于服务器是否启用了AOF持久化功能,具体判断逻辑为:
- 只有在AOF持久化功能处于关闭状态时,服务器才会使用RDB文件来还原数据。
- 如果服务器开启了AOF持久化功能,那么服务器会优先使用AOF文件来还原数据。
默认情况下,Redis服务器的AOF持久化功能是关闭的,所以Redis服务器在启动时会载入RDB文件。
服务器状态
创建和载入RDB文件,可能存在的服务器状态有以下3种:
- 当执行SAVE命令时,Redis服务器会被阻塞,此时客户端发送的所有命令请求都会被阻塞,只有在服务器执行完SAVE命令,重新开始接受命令请求之后,客户端发送的命令请求才会被处理。
- 当执行BGSAVE命令时,Redis服务器不会被阻塞,Redis服务器仍然可以继续处理客户端发送的命令请求。
- 服务器在载入RDB文件期间,会一直处于阻塞状态,直到RDB文件载入成功。
优点
- RDB文件小,非常适合定时备份,用于灾难恢复
- Redis加载RDB文件的速度比AOF快很多,因为RDB文件中直接存储的时内存数据,而AOF文件中存储的是一条条命令,需要重演命令。
缺点
- RDB无法做到实时持久化,若在两次bgsave间宕机,则会丢失区间(分钟级)的增量数据,不适用于实时性要求较高的场景
- RDB的cow机制中,fork子进程属于重量级操作,并且会阻塞redis主进程
- 存在老版本的Redis不兼容新版本RDB格式文件的问题
AOF日志
AOF日志是持续增量的备份 ,是基于写命令存储的可读的文本文件 。AOF日志会在持续运行中持续增大,由于Redis重启过程需要优先加载AOF日志进行指令重放以恢复数据,恢复时间会无比漫长。所以需要定期进行AOF重写,对AOF日志进行瘦身。目前AOF是Redis持久化的主流方式。AOF持久化也分为手动触发和自动触发。AOF类似于MySQL的binlog
AOF持久化的实现
AOF默认是关闭的,通过redis.conf配置文件进行开启
bash
appendonly yes #yes开启AOF日志,no关闭
appendfilename "appendonly.aof"# aof文件名
appendfsync everysec ## 指定aof操作中文件同步策略
手动触发
可以使用BGREWRITEAOF命令手动触发持久化机制。
BGREWRITEAOF :Redis在后台异步进行AOF重写操作,即将AOF文件重写为一个新的、更加紧凑的AOF文件,不会阻塞Redis服务器进程。
自动触发
通过auto-aof-rewrite-percentage 和auto-aof-rewrite-min-size 参数配置AOF文件重写触发条件 ,当AOF文件大小达到auto-aof-rewrite-min-size 并且AOF文件增长率超过了auto-aof-rewrite-percentage 时,Redis会自动启动AOF重写 操作。默认配置为auto-aof-rewrite-percentage 100 和auto-aof-rewrite-min-size 64mb ,也就是说当AOF文件大小达到原先文件的2倍,并且超过64mb将对AOF文件进行重写。
修改配置文件中AOF的写入策略。
AOF是文件操作,对于变更操作比较密集的server,那么将造成磁盘IO的负荷加重。此外linux对文件操作采取了"延迟写入"手段,即并非每次write操作都会触发实际磁盘操作,而是进入了buffer中,当buffer数据达到阀值时触发实际写入(也有其他时机),这是linux对文件系统的优化。
Linux 的glibc
提供了fsync(int fd)
函数可以将指定文件的内容强制从内核缓存刷到磁盘。只要 Redis 进程实时调用 fsync 函数就可以保证 aof 日志不丢失。但是 fsync 是一个磁盘 IO 操作,它很慢!如果 Redis 执行一条指令就要 fsync 一次,那么 Redis 高性能的地位就不保了。
因此在上述配置文件中,可观察到Redis中提供了3中AOF记录同步选项:
-
always: 每次执行写命令时都立即将命令同步到磁盘,这种方式数据最可靠,但写入性能最差。
-
everysec: 每秒钟同步一次,性能和数据可靠性折中。AOF 默认使用的策略
-
no: 完全依赖操作系统来决定何时同步磁盘,性能最好,但数据可靠性最差
载入AOF文件
因为AOF文件包含了重建数据库所需的所有写命令,所以Redis服务器只要读入并重新执行一遍AOF文件里面保存的写命令,就可以还原Redis服务器关闭之前的数据。
Redis读取AOF文件并还原数据库的详细步骤如下:
- 创建一个不带网络连接的伪客户端
因为Redis的命令只能在客户端上下文中执行,而载入AOF文件时所使用的命令直接来源于AOF文件而不是网络连接,所以服务器使用了一个没有网络连接的伪客户端来执行AOF文件保存的写命令。
伪客户端执行命令的效果和带网络连接的客户端执行命令的效果完全一样。 - 从AOF文件中分析并读取出一条写命令。
- 使用伪客户端执行被读取出的写命令。
- 一直执行步骤2和步骤3,直到AOF文件中的所有写命令都被执行完毕。
AOF重写机制
因为AOF持久化是通过保存被执行的写命令来记录数据库数据的,所以随着Redis服务器运行时间的增加,AOF文件中的内容会越来越多,文件的体积会越来越大,如果不做控制,会有以下2点坏处:
- 过多的占用服务器磁盘空间,可能会对Redis服务器甚至整个宿主计算机造成影响。
- AOF文件的体积越大,使用AOF文件来进行数据库还原所需的时间就越多。
Redis提供了AOF文件重写功能,即Redis服务器会创建一个新的AOF文件来替代现有的AOF文件,新旧两个AOF文件所保存的数据库数据相同,但新AOF文件不会包含任何浪费空间的冗余命令(用一条命令去记录键值对,代替之前记录这个键值对的多条命令),所以新AOF文件的体积通常会比旧AOF文件的体积要小很多。
AOF后台重写
Redis服务器使用单个线程来处理命令请求,AOF重写会进行大量文件写入操作长时间阻塞线程。Redis将AOF文件重写功能放到子进程里执行,这样做有以下2个好处:
- 子进程进行AOF文件重写期间,服务器进程(父进程)可以继续处理命令请求。
- 子进程带有服务器进程的数据副本,使用子进程而不是线程,可以在避免使用锁的情况下,保证数据的安全性。
AOF后台重写的步骤如下所示:
- 服务器进程创建子进程,子进程开始AOF文件重写
- 从创建子进程开始,服务器进程执行的所有写命令不仅要写入AOF缓冲区,还要写入AOF重写缓冲区
写入AOF缓冲区的目的是为了同步到原有的AOF文件。
写入AOF重写缓冲区的目的是因为子进程在进行AOF文件重写期间,服务器进程还在继续处理命令请求,
而新的命令可能会对现有的数据库进行修改,从而使得服务器当前的数据库数据和重写后的AOF文件所
保存的数据库数据不一致。 - 子进程完成AOF重写工作,向父进程发送一个信号,父进程在接收到该信号后,会执行以下操作:
1.将AOF重写缓冲区中的所有内容写入到新AOF文件中,这样就保证了新AOF文件所保存的数据库数据和服务器当前的数据库数据是一致的。
2.对新的AOF文件进行改名,原子地覆盖现有的AOF文件,完成新旧两个AOF文件的替换。
Redis提供了BGREWRITEAOF
命令来执行以上步骤。