持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第20天,点击查看活动详情
我们已经使用redis存取数据,是不是需要做好灾备处理呢。如果我们的redis发生故障宕机怎么办?我们都知道,redis的数据是存储在内存中的,并没有存储在磁盘上,这也是redis性能高的主要原因。所以,如果redis宕机了,那redis中的数据也会消失,这就可能导致我们的数据发生丢失。显然,这并不是我们希望的结果。那怎样解决呢?那就是对redis中的数据进行持久化。
redis的持久化方式有两种:RDB和AOF。
1)RDB方式 (redis默认默认持久化方法)
RDB方式的持久化是通过快照(snapshotting)完成的,当符合一定条件时Redis会自动将内存中的所有数据进行快照并存储在硬盘上。进行快照的条件可以由用户在配置文件中自定义,由两个参数构成:时间和改动的键的个数。当在指定的时间内被更改的键的个数大于指定的数值时就会进行快照。
RDB是redis默认采用的持久化方式,在配置文件中已经预置了3个条件:
- save 900 1 900秒内有至少1个键被更改则进行快照
- save 300 10 300秒内有至少10个键被更改则进行快照
- save 60 10000 60秒内有至少10000个键被更改则进行快照
可以存在多个条件,条件之间是"或"的关系,只要满足其中一个条件,就会进行快照。 如果想要禁用自动快照,只需要将所有的save参数删除即可。
Redis默认会将快照文件存储在当前目录(可CONFIG GET dir来查看)的dump.rdb文件中,可以通过配置dir和dbfilename两个参数分别指定快照文件的存储路径和文件名。
Redis实现快照的过程
-
- Redis使用fork函数复制一份当前进程(父进程)的副本(子进程);
-
- 父进程继续接收并处理客户端发来的命令,而子进程开始将内存中的数据写入硬盘中的临时文件;
-
- 当子进程写入完所有数据后会用该临时文件替换旧的RDB文件,至此一次快照操作完成。
-
- 在执行fork的时候操作系统(类Unix操作系统)会使用写时复制(copy-on-write)策略,即fork函数发生的一刻父子进程共享同一内存数据,当父进程要更改其中某片数据时(如执行一个写命令 ),操作系统会将该片数据复制一份以保证子进程的数据不受影响,所以新的RDB文件存储的是执行fork一刻的内存数据。
Redis在进行快照的过程中不会修改RDB文件,只有快照结束后才会将旧的文件替换成新的,也就是说任何时候RDB文件都是完整的。这使得我们可以通过定时备份RDB文件来实 现Redis数据库备份。RDB文件是经过压缩(可以配置rdbcompression参数以禁用压缩节省CPU占用)的二进制格式,所以占用的空间会小于内存中的数据大小,更加利于传输。
除了自动快照,还可以手动发送SAVE或BGSAVE命令让Redis执行快照,
两个命令的区别在于,前者是由主进程进行快照操作,会阻塞住其他请求,后者会通过fork子进程进行快照操作。 Redis启动后会读取RDB快照文件,将数据从硬盘载入到内存。根据数据量大小与结构和服务器性能不同,这个时间也不同。通常将一个记录一千万个字符串类型键、大小为1GB的快照文件载入到内 存中需要花费20~30秒钟。 通过RDB方式实现持久化,一旦Redis异常退出,就会丢失最后一次快照以后更改的所有数据。这就需要开发者根据具体的应用场合,通过组合设置自动快照条件的方式来将可能发生的数据损失控制在能够接受的范围。如果数据很重要以至于无法承受任何损失,则可以考虑使用AOF方式进行持久化。
2)AOF方式
默认情况下Redis没有开启AOF(append only file)方式的持久化,可以在redis.conf中通过appendonly参数开启:
appendonly yes
在启动时Redis会逐个执行AOF文件中的命令来将硬盘中的数据载入到内存中,载入的速度相较RDB会慢一些。
开启AOF持久化后每执行一条会更改Redis中的数据的命令,Redis就会将该命令写入硬盘中的AOF文件。AOF文件的保存位置和RDB文件的位置相同,都是通过dir参数设置的,默认的文件名是appendonly.aof,可以通过appendfilename参数修改:
appendfilename appendonly.aof
配置redis自动重写AOF文件的条件
auto-aof-rewrite-percentage 100
当目前的AOF文件大小超过上一次重写时的AOF文件大小的百分之多少时会再次进行重写,如果之前没有重写过,则以启动时的AOF文件大小为依据。
auto-aof-rewrite-min-size 64mb # 允许重写的最小AOF文件大小 配置写入AOF文件后,要求系统刷新硬盘缓存的机制。
appendfsync always
每次执行写入都会执行同步,最安全也最慢
appendfsync everysec
每秒执行一次同步操作
appendfsync no
不主动进行同步操作,而是完全交由操作系统来做(即每30秒一次),最快也最不安全
Redis允许同时开启AOF和RDB,既保证了数据安全又使得进行备份等操作十分容易。此时重新启动Redis后Redis会使用AOF文件来恢复数据,因为AOF方式的持久化可能丢失的。
save 900 1
RDB快照会阻塞当前redis服务器,redis不能处理其他命令,直到RDB执行完成;不会修改老的rdb文件,只会再完成后替换老的dump.rdb文件,利于备份dump文件。
bgsave命令异步执行快照存储,快照同时服务器可以接收和执行其他命令;
redis进程fork子线程执行RDB持久化,完成快照后自动结束;
子线程会阻塞,一半时间很短,redis一般都是使用bgsave命令。
RDB可以最大优化redis性能,再恢复大数据集时,比AOF恢复速度更快。
全量备份,存储的内存数据结构时二进制序列化形式,存储非常紧凑;子进程执行快照期间,父进程的内存数据变更不会反应出来,所以再快照持久化期间修改的数据不会被保存,一旦redis挂掉,导致数据丢失。
AOF缓存追加:同步命令到AOF文件需要经历三个阶段:
-
命令传播:Redis将执行完的命令、命令的参数、命令的参数个数等信息发送到AOF程序中。
-
缓存追加:AOF程序根据接收到的命令数据,将命令转换为网络通讯协议的格式,然后将协议内容追加到服务器的AOF缓存中。
-
文件写入和保存:AOF缓存中的内容被写入到AOF文件末尾,如果设定的AOF保存条件被满足的话,fsync函数或者fdatasync函数会被调用,将写入的内容真正地保存到磁盘中
AOF保存模式
Redis目前支持三种AOF保存模式,它们分别是:
-
不保存、每秒钟保存一次、每执行一个命令保存一次。
-
AOF_FSYNC_NO(不保存):在这种模式下,每次调用ushAppendOnlyFile函数,WRITE都会被执行,但SAVE会被略过。在这种模式下,SAVE只会在以下情况中被执行: 1.Redis被关闭; 2.AOF功能被关闭; 3.系统的写缓存被刷新(可能是缓存已经被写满,或者定期保存操作被执行)。 这三种情况下的SAVE操作都会引起Redis主进程阻塞。
-
AOF_FSYNC_EVERYSEC(每一秒钟保存一次):在这种模式中,SAVE原则上每隔一秒钟就会执行一次,因为SAVE操作是由后台子线程调用的,所以它不会引起服务器主进程阻塞。
-
AOF_FSYNC_ALWAYS(每执行一个命令保存一次(不推荐)):在这种模式下,每次执行完一个命令之后,WRITE和SAVE都会被执行。另外,因为SAVE是由Redis主进程执行的,所以在SAVE执行期间,主进程会被阻塞,不能接受命令请求。
对于三种AOF保存模式,它们对服务器主进程的阻塞情况如下:
-
AOF_FSYNC_NO:写入和保存都由主进程执行,两个操作都会阻塞主进程。
-
AOF_FSYNC_EVERYSEC:写入操作由主进程执行,阻塞主进程。保存操作由子线程执行,不直接阻塞主进程,但保存操作完成的快慢会影响写入操作的阻塞时长。
-
AOF_FSYNC_ALWAYS:和AOF_FSYNC_NO模式一样。
因为阻塞操作会让Redis主进程无法持续处理请求,所以一般说来,阻塞操作执行得越少,完成得越快,Redis的性能就越好。
AOF 重写
AOF 持久化是通过保存被执行的写命令来记录数据库状态的,所以AOF文件的大小随着时间的流逝一定会越来越大。影响包括但不限于:对于Redis服务器,计算机的存储压力;AOF还原出数据库状态的时间增加。
为了解决AOF文件体积膨胀的问题,Redis提供了AOF重写功能:Redis服务器可以创建一个新的AOF文件来替代现有的AOF文件,新旧两个文件所保存的数据库状态是相同的,但是新的AOF文件不会包含任何浪费空间的冗余命令,通常体积会较旧AOF文件小很多。
tip:两种机制全部开启的时候,Redis在重启的时候会默认使用AOF去重新构建数据,因为AOF的数据是比RDB更完整的。