2022年8月,成都不再像以往一样突发暴雨,而是持续高温天气,最高温度42°,在8月第三周15号开始,陆陆续续成都多个写字楼限电,工业用电直接关停,空调不能使用,大多都居家远程办公或放假几天,政府的目标是优先保证生活用电,恰巧作者所在的写字楼中途有次突然断电,我们的多个服务下线,其中就有物理机单机redis数据和集群redis数据丢失的情况,接下来我就redis的存储方案做一个简单的介绍:
redis的数据都放在内存中,以速度快著称,那么当突然断电来临,如果没有把内存中的数据保存在物理磁盘上,那么下次重启redis就不会存在之前的数据了,势必就会引入持久化策略,redis的持久化策略是RDB和AOF,这两种策略都是将redis内存中的数据存储到磁盘上,保证数据不丢失,接下来我们就详细的聊一聊RDB和AOF各自的特征。
RDB(Redis DataBase)持久化是把当前进程数据生成快照保存到硬盘的过程,即快照模式,它是 Redis 默认的数据持久化方式,它会将数据的快照保存在 dump.rdb 这个二进制文件中。
引申:假设是你自己来设计RDB存储,你要怎么做?
此时redis对外服务不可用,我们用这30分钟来将数据写到磁盘。
redis自身是怎么做的呢?
思考:redis是单进程的,在bgsave的时候是怎么操作的呢,这个时候它是靠操作系统的的 COW(Copy On Write) 机制,这里不展开写时复制的讲解,大家可自行根据自身情况进行探索,写时复制机制实现了数据段分离且保证父子进程不受影响,父进程能持续对外提供服务,子进程自己去写磁盘。
RDB 持久化提供了两种触发策略:一种是手动触发,另一种是自动触发。
手动触发是通过SAVAE
命令或者BGSAVE
命令将内存中的数据保存到物理磁盘文件
127.0.0.1:6379> SAVE
OK
127.0.0.1:6379> BGSAVE
Background saving started
127.0.0.1:6379> LASTSAVE
(integer) 1159560
BGSAVE
优于SAVE
命令。
SAVE 命令会阻塞 Redis 服务进程,直到 dump.rdb 二进制文件创建完毕为止,在这个过程中,服务器不能处理任何的命令请求,对外不能提供服务。
BGSAVE
命令是非阻塞的,所谓非阻塞指的是在该命令执行的过程中,redis能正常对外提供服务。是因为 Redis 服务器会 fork() 开启一个子进程来进行持久化操作(创建新的 dunp.rdb 文件),而父进程则继续处理客户端请求。当子进程处理完毕之后后会告知向父进程已经处理完毕。此时,父进程会用新的 dump.rdb 文件覆盖掉原来的旧文件。
LASTSAVE 命令用于查看 BGSAVE 命令是否执行成功。
自动触发策略,是指 Redis 在指定的时间内,数据发生了多少次变化时,会自动执行BGSAVE命令。自动触发的条件包含在了 Redis 的配置文件中,如下所示:
上图所示, save x y 的含义是在时间 x 秒内,如果 Redis 数据至少发生了 y 次变化,那么就自动执行BGSAVE命令。配置策略说明如下:
上述三个条件任意满足一个,服务器就会自动执行BGSAVE命令。
RDB 数据持久化适合于大规模的数据恢复,并且恢复速度快,如果对数据的完整性要求不高(可能存在最后的一段时间丢失的情况),那么 RDB 持久化方式非常合适。
AOF(append only file)持久化:以独立日志的方式记录每次写命令,它和mysql的binlog比较类似,一直将命令挨个写入文件,redis在重启的时候,读取AOF文件中一行行的命令执行就能恢复数据。AOF它的主要作用是解决了实时存储数据,就是数据持久化的实时性,目前AOF持久化方式已经是Redis持久化的主流。
AOF 重写和 RDB 创建快照一样,都巧妙地利用了操作系统COW(Copy On Write)写时复制机制:
因为 AOF 的写命令方式是不断地将命令追加到文件的末尾, 所以随着写入命令的不断增加, AOF 文件会变得越来越大。举个例子, 如果你对一个计数器调用了 1000 次 INCR , 那么仅仅是为了保存这个计数器的当前值, AOF 文件就需要使用 1000 条记录(entry)。然而在实际上, 只使用一条 SET 命令已经足以保存计数器的当前值了, 其余 99 条记录实际上都是多余的。
为了处理这种情况, Redis 支持一种有趣的特性:可以在不打断服务客户端的情况下, 对 AOF 文件进行重建(rebuild),对应的命令式 BGREWRITEAOF 命令, Redis 将生成一个新的 AOF 文件, 将重复命令或者几个命令合并,这个文件包含重建当前数据集所需的最少命令。Redis 2.2 需要自己手动执行 BGREWRITEAOF 命令;Redis 2.4以后 则可以自动触发 AOF 重写。
你可以配置 Redis 多久才将数据 fsync 到磁盘一次。有三种方式:
注意:推荐(并且也是默认)的措施为每秒 fsync 一次, 配置成everysec,这种 fsync 策略可以兼顾速度和安全性。
服务器可能在程序正在对 AOF 文件进行写入时停机, 如果停机造成了 AOF 文件出错(corrupt), 那么 Redis 在重启时会拒绝载入这个 AOF 文件, 从而确保数据的一致性不会被破坏。当发生这种情况时, 可以用以下方法来修复出错的 AOF 文件:
,$数字>表示几个字符,*数字>表示后面取几行,比如这条指令就是选择0号库,设置一个k1,value为hello
,
,相应的aof文件中会有修改的操作记录
,这个时候其实就相当于给k1赋一个值,aof文件中就记录了很多垃圾,可以用BGREWRITEAOF命令压缩aof文件,压缩前160多,压缩后查看aof文件82,
,可以看见操作合并了
,vi appendonly.aof查看,可以看见这个aof文件前面也有个REDIS了
,前边是二进制的rdb,加快恢复速度,后边是明文操作
在 Redis 2.2 或以上版本,可以在不重启的情况下,从 RDB 切换到 AOF :
执行的第二条命令用于关闭 RDB 功能。这一步是可选的, 如果你愿意的话, 也可以同时使用 RDB 和 AOF 这两种持久化功能。
重要:别忘了在 redis.conf 中打开 AOF 功能!否则的话, 服务器重启之后, 之前通过 CONFIG SET 设置的配置就会被遗忘, 程序会按原来的配置来启动服务器。
在版本号大于等于 2.4 的 Redis 中, BGSAVE 执行的过程中, 不可以执行 BGREWRITEAOF 。反过来说, 在 BGREWRITEAOF 执行的过程中, 也不可以执行 BGSAVE。这可以防止两个 Redis 后台进程同时对磁盘进行大量的 I/O 操作。
如果 BGSAVE 正在执行, 并且用户显示地调用 BGREWRITEAOF 命令, 那么服务器将向用户回复一个 OK 状态, 并告知用户, BGREWRITEAOF 已经被预定执行:一旦 BGSAVE 执行完毕, BGREWRITEAOF 就会正式开始。当 Redis 启动时, 如果 RDB 持久化和 AOF 持久化都被打开了, 那么程序会优先使用 AOF 文件来恢复数据集, 因为 AOF 文件所保存的数据通常是最完整的,生成的文件是一个混合体,下面是二进制,上面是aof追加的命令
相信通过对RDB和AOF的了解,可以这样回答:在Redis单实例情况下,RDB方式最大丢失了从断电到上一次bgsava之间的数据,aof方式(默认配置)最多丢失1s的数据,在Redis集群情况下,如果都同单机一样全部挂掉丢失情况和单机一致,如果是集群中某个Redis实例挂掉,当它重新上线可以完全恢复数据,不丢失数据。
今天主要跟大家聊的是Redis持久化的策略以及对RBD和AOF的原理有简单的阐述,相信经过此篇文章你可以应对面试官对Redis持久化的相关问题,后续也会持续介绍Redis相关的知识,欢迎持续关注!