Redis持久化双雄
Redis持久化
Redis 的持久化是指将内存中的数据保存到硬盘,以防止服务器宕机导致数据丢失的机制。
redis 提供了两种持久化的方式,分别是RDB(Redis DataBase)和AOF(Append Only File)。
RDB,简而言之,就是在不同的时间点,将 redis 存储的数据生成快照并存储到磁盘等介质上;
AOF,则是换了一个角度来实现持久化,那就是将 redis 执行过的所有写指令记录下来,在下次 redis 重新启动时,只要把这些写指令从前到后再重复执行一遍,就可以实现数据恢复了。
其实 RDB 和 AOF 两种方式也可以同时使用,在这种情况下,如果 redis 重启的话,则会优先采用 AOF 方式来进行数据恢复,这是因为 AOF 方式的数据恢复完整度更高。
如果你没有数据持久化的需求,也完全可以关闭 RDB 和 AOF 方式,这样的话,redis 将变成一个纯内存数据库,就像 memcache 一样。
持久化双雄
RDB(Redis DataBase)
RDB 持久性以指定的时间间隔执行数据集的时间点快照。
实现类似照片记录效果的方式,就是把某一时刻的数据和状态以文件的形式写到磁盘上,也就是快照。这样一来即使故障宕机,快照文件也不会丢失,数据的可靠性也就得到了保证。
这个快照文件就称为RDB文件(dump.rdb),其中,RDB就是Redis DataBase的缩写。
RDB快照原理
我们知道 Redis 是单线程程序,这个线程要同时负责多个客户端套接字的并发读写操作和内存数据结构的逻辑读写。
在服务线上请求的同时,Redis 还需要进行内存快照,内存快照要求 Redis 必须进行文件 IO 操作,这意味着单线程同时在服务线上的请求还要进行文件 IO 操作,文件 IO 操作会严重拖垮服务器请求的性能。还有个重要的问题是为了不阻塞线上的业务,就需要边持久化边响应客户端请求。持久化的同时,内存数据结构还在改变,比如一个大型的 hash 字典正在持久化,结果一个请求过来把它给删掉了,还没持久化完呢,这要怎么搞?
Redis 使用操作系统的多进程 COW(Copy On Write) 机制来实现快照持久化,这个机制很有意思,也很少人知道。多进程 COW 也是鉴定程序员知识广度的一个重要指标。
fork(多进程)
Redis 在持久化时会调用 glibc 的函数 fork 产生一个子进程,快照持久化完全交给子进程来处理,父进程继续处理客户端请求。子进程刚刚产生时,它和父进程共享内存里面的代码段和数据段。这时你可以将父子进程想像成一个连体婴儿,共享身体。这是 Linux 操作系统的机制,为了节约内存资源,所以尽可能让它们共享起来。在进程分离的一瞬间,内存的增长几乎没有明显变化。 子进程做数据持久化,它不会修改现有的内存数据结构,它只是对数据结构进行遍历读取,然后序列化写到磁盘中。但是父进程不一样,它必须持续服务客户端请求,然后对内存数据结构进行不间断的修改。
这个时候就会使用操作系统的 COW 机制来进行数据段页面的分离。数据段是由很多操作系统的页面组合而成,当父进程对其中一个页面的数据进行修改时,会将被共享的页面复制一份分离出来,然后对这个复制的页面进行修改。这时子进程相应的页面是没有变化的,还是进程产生时那一瞬间的数据。
dump文件-保存路径:
自定义修改路径:dir/xxx/xxx
dump文件-保存名称:
快照禁用:
手动触发
命令 | 作用 |
---|---|
SAVE | 在主程序中执行会阻塞当前redis服务器,直到持久化工作完成,在执行save命令期间,redis不能处理其它的命令,线上禁止使用 |
BGSAVE | redis会在后台异步进行快照操作,不阻塞,快照同时还可以响应客户端的请求,该触发方式会fork一个子进程,由子进程复制持久化过程 |
LASTSAVE:可以通过last save命令获取最后一次成功执行快照的时间
自动触发
修改redis.conf里面的配置文件,设置配置save <seconds> <changes>,来覆盖系统默认配置
修改dump文件保存路径
修改dump文件的名称
redis默认是分别在一个小时内有一次变化,五分钟内有100次变化,一分钟内有10000次变化,就会自动启动快照。如果要配置自己的规则,可以在配置文件中写一下语法:
save (time) (changes)
time指的是在多少时间内,单位是秒。
changes指的是变化次数,单位是次。
也可以在一行配置多个规则:
save (time) (changes) (time) (changes) (time) (changes)……
只要redis数据库中存在一定的变化满足了规则,就会进行一次快照
#配置文件模板语法
#这表示在指定的seconds秒内,如果至少有changes个键被修改,则自动触发一次快照保存。你可以配置多个save指令,Redis会满足其中任何一个条件时触发快照。
save <seconds> <changes>
=============================================================================save 900 1 # 如果在900秒内,至少有1个键被修改,则触发快照
save 300 10 # 如果在300秒内,至少有10个键被修改,则触发快照
save 60 10000 # 如果在60秒内,至少有10000个键被修改,则触发快照
触发RDB快照的几种情况:
①配置文件中默认的快照配置
②手动执行save/bgsave命令
③执行flushall/flushdb命令也会生成dump.rdb文件
④执行shutdown且没有开启AOF持久化
⑤主从复制时,主节点自动触发
RDB优化配置项
默认yes |
---|
如果配置成no,表示你不在乎数据不一致或者有其他的手段发现和控制这种不一致,那么在快照写入失败时,也能确保redis继续接受新的写请求 |
默认yes |
---|
对于存储到磁盘中的快照,可以设置是否进行压缩存储。如果是的话,redis会采用LZF算法进行压缩。 如果你不想消耗CPU来进行压缩的话,可以设置为关闭此功能 |
默认yes |
---|
在存储快照后,还可以让redis使用CRC64算法来进行数据校验,但是这样做会增加大约10%的性能消耗,如果希望获取到最大的性能提升,可以关闭此功能 |
rdb-del-sync-files:在没有持久性的情况下删除复制中使用的RDB文件启用。默认情况下no,此选项是禁用的。
优势:
适合大规模数据恢复
对数据完整性和一致性要求不高更适合使用
节省磁盘空间
基于二进制存储的,恢复速度快
劣势:
Fork的时候,内存中的数据会被克隆一份,大致2倍的膨胀,需要考虑
虽然Redis在fork的时候使用了写时拷贝技术,但是如果数据庞大时还是比较消耗性能
在备份周期在一定间隔时间做一次备份,所以如果Redis意外down的话,就会丢失最后一次快照后所有修改
AOF(Append Only File)
引入:如果你对数据的完整性非常敏感,那么 RDB 方式就不太适合你,因为即使你每 5 分钟都持久化一次,当 redis 故障时,仍然会有近 5 分钟的数据丢失。所以,redis 还提供了另一种持久化方式,那就是 AOF。
AOF(append only file)是以日志的形式来记录每个写操作,将Redis执行过的所有写的指令记录下来(读操作不记录),只许追加文件但是不可以更改文件,redis启动后会读取改文件重新构建数据,换言之,redis重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作。
默认情况下,redis并没有开启AOF的开启AOF的功能需要设置配置文件中的appendonly为yes
工作流程
1 | Client作为命令的来源,会有多个源头以及源源不断的请求命令。 |
---|---|
2 | 在这些命令到达Redis Server 以后并不是直接写入AOF文件,会将其这些命令先放入AOF缓存中进行保存。这里的AOF缓冲区实际上是内存中的一片区域,存在的目的是当这些命令达到一定量以后再写入磁盘,避免频繁的磁盘IO操作。 |
3 | AOF缓冲会根据AOF缓冲区同步文件的三种写回策略将命令写入磁盘上的AOF文件。 |
4 | 随着写入AOF内容的增加为避免文件膨胀,会根据规则进行命令的合并(又称AOF重写),从而起到AOF文件压缩的目的。 |
5 | 当Redis Server 服务器重启的时候会从AOF文件载入数据。 |
三种写回策略:
Always:同步写回,每个命令执行完立刻同步的将日志写回到磁盘
everysec:每秒写回,每个写命令执行完,只是先把日志写到AOF文件的内存缓冲区,每间隔1秒把缓冲区中的内容写入磁盘
no:操作系统控制的写回,每个写命令执行完只是先把日志写到AOF文件的内存缓冲区,由操作系统来决定何时将缓冲区内容写回磁盘
AOF文件-保存路径
在原有的dir路径下生成一个appenddirname文件夹来统一管理AOF文件,其中包含基础AOF
增量AOF,以及历史AOF
AOF文件-保存名称
AOF重写机制
由于AOF持久化是Redis不断将写命令记录到 AOF 文件中,随着Redis不断的进行,AOF 的文件会越来越大,文件越大,占用服务器内存越大以及 AOF 恢复要求时间越长。为了解决这个问题,Redis新增了重写机制,当AOF文件的大小超过所设定的峰值时,Redis就会自动启动AOF文件的内容压缩,只保留可以恢复数据的最小指令集或者,可以手动使用命令 bgrewriteaof 来重写。
原理:
1:在重写开始前,redis会创建一个“重写子进程”,这个子进程会读取现有的AOF文件,并将其包含的指令进行分析压缩并写入到一个临时文件中。
2:与此同时,主进程会将新接收到的写指令一边累积到内存缓冲区中,一边继续写入到原有的AOF文件中,这样做是保证原有的AOF文件的可用性,避免在重写过程中出现意外。
3:当“重写子进程”完成重写工作后,它会给父进程发一个信号,父进程收到信号后就会将内存中缓存的写指令追加到新AOF文件中
4:当追加结束后,redis就会用新AOF文件来代替旧AOF文件,之后再有新的写指令,就都会追加到新的AOF文件中
5:重写aof文件的操作,并没有读取旧的aof文件,而是将整个内存中的数据库内容用命令的方式重写了一个新的aof文件,这点和快照有点类似
自动触发:
当同时满足配置文件中的选项(默认配置是当AOF文件大小是上次rewrite后大小的一倍且文件大于64M时)后,redis会启动重写机制
手动触发:
客户端向服务器发送bgrewriteaof命令
AOF优化配置项
优势:
①更加持久,当使用每秒读入的方式时出现异常,只会出现1秒的数据丢失,可以接受
②AOF日志是一个仅附加日志,不会出现寻道问题,不会因为断电出现损坏,如果因为一些原因出现写到一半结尾了,可以使用redis-check-aof工具来修复文件
③当AOF变的太大时,redis可以在后台自动重写AOF(相当于是文件瘦身处理)
④AOF文件易于理解和解析,其中包含所有的操作日志,可以轻松的导出AOF文件,在发生误写操作指令时,可以通过AOF文件删除最新命令来恢复数据
劣势:
①相同数据集的数据而言AOF文件要远远大于RDB文件,恢复速度慢于rdb
②AOF运行效率要慢于rdb,每秒同步的策略效率较好,不同步效率于rdb相同
RDB+AOF混合持久化
先使用RDB进行快照存储,然后使用AOF持久化记录所有的写操作,当重写策略满足或手动触发重写的时候,将最新的数据存储为新的RDB记录。这样的话,重启服务的时候会从RDB和AOF两部分恢复数据,既保证了数据完整性,又提高了恢复数据的性能。简单来说:混合持久化方式产生的文件一部分是RDB格式,一部分是AOF格式。----》AOF包括了RDB头部+AOF混写