Redis的数据是保存在内存中的,所以能保证很快的读写速度。但是如果发生不可抗的如断电,系统崩溃等因素,redis中的数据就会丢失。Redis支持将内存中的数据保存到硬盘来减少内存数据丢失带来的损失。这就是Redis的持久化
Redis有两种持久化的方式,一种是通过屏幕快照(Snapshotting),一种是AOF(Append-Only-File)。
-
RDB
RDB 持久化可以在指定的时间间隔内生成数据集的时间点快照(point-in-time snapshot),将内存中的数据以快照的数据写入到二进制文件(默认是dump.rdb,可在配置文件中修改,或者通过config set dir
设置路径,通过config set dbfilename
设置文件名称)中。-
快照规则
快照的规则可以配置为,在n秒内如果超过m个key被修改,就自动快照,下边是配置文件中默认的规则:save 900 1 #900 秒内如果超过 1 个 key 被修改,则发起快照保存
save 300 10 #300 秒内容如超过 10 个 key 被修改,则发起快照保存
save 60 10000 #60 秒内容如超过 10000 个 key 被修改,则发起快照保存 -
快照过程
- redis调用fork,创建子进程(子进程继承了父进程的整个地址空间,包括进程上下文,堆栈地址,内存信息进程控制块)。
- 父进程继续处理请求,子进程负责将内存内容写到临时文件。
由于os的实时复制机制(copy on write),父子进程享有相同的物理页面,父进程处理写请求时,os会为其要修改的页面创建副本,而不是共享的页面。所以子进程地址空间内的数据是fork时整个数据库的一个快照。 - 子进程写入完毕后,用临时文件替换原来的快照文件,然后子进程退出
-
手动写入快照
可以通过save或者bgsave命令,通知redis做一次快照持久化。
save操作是在主线程中保存快照的,而redis是单线程的,因此save操作会阻塞redis处理其他请求,因此不建议使用。 -
数据丢失
注意: 每次快照持久化都是将内存完整数据写入磁盘一次,而不是增量的同步变更数据,因此数据量大的时候,必然引起大的磁盘IO,可能会严重影响性能。
-
-
AOF
由于快照的方式是隔一段时间做一次的,因此如果redis意外down掉的话,就会丢失最后一次快照之后的所有修改。
如果应用不允许丢失任何修改的话,就可以采用AOF的方式。-
过程原理
使用AOF持久化时,Redis会把所有的写请求都通过write函数追加到文件中(默认是appendonly.aof),Redis重启时,通过执行文件中的写命令,将数据重新加载到内存中。 -
数据丢失
由于os会在内核中,缓存write做的修改,所以可能不会立即将写命令写入到磁盘文件中,从而可能会丢失部分修改。
但是我们可以通过配置appendfsync,强制告诉os写入磁盘的时机。有以下三种方式:appendfsync always # 每一次的写操作都写入到磁盘,最慢,但是能保证完全的持久化 appendfsync everysec # 每秒钟写入磁盘一次,在性能和持久化方面做了折中 appendfsync no # 完全以来os的写入时机,性能最好,但持久化没保证
-
问题
持久化文件会越来越大。
假如我们调用incr test
100次,持久化文件中就会保存了100条incr命令,但是其中99条都是多余的,因为要恢复这个状态,我们只需要执行一次set test 100
就可以了。使用bgrewriteaof命令,可以压缩aof持久化文件。这个命令的过程,类似于RDB方式写入快照的方式,会将内存中的数据以命令的方式写入临时文件,然后替换原来的持久化文件。具体过程如下:
- Redis fork出子进程。
- 子进程根据内存中的数据库快照,往临时文件中写入重建数据库状态的命令。(这个命令不是client的写命令)
- 父进程继续处理client请求,除了把新的写请求写入到原来的aof文件中外,还把这些命令缓存起来。保证如果子进程重写失败后,原来的aof文件还能用。
- 子进程把快照写入到临时文件完成后,通知主进程把缓存的命令也写入到临时文件。
- 主进程用临时文件替换原来的aof文件,并重命名,后面收到的写命令也追加到新的aof文件中。
:::: bgrewriteaof并没用读取旧的aof文件,而是将内存中的数据库内容用命令的方式重写了一份
-
网友评论