redis实际上也是一种数据库,就需要考虑到数据的持久化。redis提供了两种持久化方式:AOF,RDB
1. RDB
1.1 定义
RDB持久化是指在指定的时间间隔内将内存中的数据集快照写入磁盘。RDB持久化形成的文件dump.rdb文件是一个经过压缩的二进制数据,通过该文件可以在redis服务器启动时自动恢复数据库中的数据状态。
1.2 RDB文件保存过程
RDB保存命令有两个:SAVE,BGSAVE
SAVE的实现方式
redis的SAVE命令会阻塞线程,一直等到RDB文件保存完为止。
BGSAVE的实现方式
- redis单独fork出一个子线程,现在有了子进程和父进程。
- 父进程继续处理业务,而子进程进行持久化,将数据持久化到一个临时文件中。
- 等到持久化完毕,用临时文件替代上次持久化的文件。方便redis重启的时候还原数据。
每次快照持久化都是将内存数据完整写入到磁盘一次,并不 是增量的同步数据。如果数据量大的话,而且写操作比较多,必然会引起大量的磁盘io操作,会严重影响性能。
1.3 数据恢复过程
redis的RDB持久化方式,并没有直接的命令进行数据的恢复。就是说从rdb文件到数据库的过程,只有在redis配置了开启了持久化方式是RDB的时候,redis服务器在重启的时候会加载rdb文件恢复数据。Redis 服务器在载入 RDB 文件期间,会一直处于阻塞状态,直到载入工作完成为止。恢复数据过程如下所示:
1.4 什么情况下对数据进行快照
-
根据配置规则进行快照
redis.windows.conf默认配置:
save 900 1
save 300 10
save 60 10000
他们之间的关系是或。就是说每隔900s,如果数据库有至少一个键值对变化,则进行rdb持久化。或者每隔300s,如果数据库有至少10个键值对变化,则进行rdb持久化。或者每隔60s,如果有至少10000个键值对变化,则进行rdb持久化。
-
用户执行SAVE或者GBSAVE命令
除了让redis自动快照之外,有时候我们在数据库迁移或者服务器重启的时候需要手动执行rdb持久化。
redis提供了两条命令来完成这个任务。
同步数据到磁盘上:save
SAVE 命令执行一个同步操作,以RDB文件的方式保存所有数据的快照,很少在生产环境直接使用SAVE 命令,因为它会阻塞所有的客户端的请求。
异步数据到磁盘上:bgsave
后台保存DB。会立即返回 OK 状态码。 Redis forks, 父进程继续提供服务以供客户端调用,子进程将DB数据保存到磁盘然后退出。如果操作成功,可以通过客户端命令LASTSAVE来检查操作结果。默认快照方式为异步。 -
执行FLUSHALL命令
该命令在前面讲过,会清除redis在内存中的所有数据。执行该命令后,只要redis中配置的快照规则不为空,也就是save 的规则存在。
redis就会执行一次快照操作。不管规则是什么样的都会执行。如果没有定义快照规则,就不会执行快照操作 -
执行复制(replication)时
该操作主要是在主从模式下,redis会在复制初始化时进行自动快照。当执行复制操作时,即使没有定义自动快照规则,并且没有手动执行过快照操作,它仍然会生成RDB快照文件。
1.5 RDB的持久化配置
redis.windows.conf配置如下:
# 时间策略
save 900 1
save 300 10
save 60 10000
# 文件名称
dbfilename dump.rdb
# 文件保存路径
dir /home/work/app/redis/data/
# 如果持久化出错,主进程是否停止写入
stop-writes-on-bgsave-error yes
# 是否压缩
rdbcompression yes
# 导入时是否检查
rdbchecksum yes
1.6 停止 RDB 持久化
有些时候,我们并不想redis服务器进行RDB持久化,比如redis服务器只用作缓存的时候,怎么停止RDB持久化呢?
- 通过上面讲的在配置文件 redis.conf 中,可以注释掉所有的 save 行来停用保存功能
- 执行save命令
save " "
1.7 RDB持久化原理
- redis.windows.conf配置:
save 900 1
save 300 10
save 60 10000
- 设置保存条件
struct redisService{
//1、记录保存save条件的数组
struct saveparam *saveparams;
//2、修改计数器
long long dirty;
//3、上一次执行保存的时间
time_t lastsave;
}
主要看看saveparam :
struct saveparam{
//秒数
time_t seconds;
//修改数
int changes;
};
每一个saveparam都记录了间隔秒数,以及修改次数。比如:save 900 10 ,这里的saveparam就是{seconds:900,changes:10}
- 检查条件是否满足
redis的周期性函数serverCron默认每隔100ms执行一次,去检查设置条件是否满足,如果满足,则执行BGSAVE命令,其伪代码如下:
def serverCron():
//遍历所有设置的条件
...
//如果满足条件开始执行
BGSAVE;
1.8 RDB的特点
- rdb文件是经过压缩的二进制数据,适合备份和迁移。
- RDB 在恢复大数据集时的速度比 AOF 的恢复速度要快。
- RDB 可以最大化 Redis 的性能:父进程在保存 RDB 文件时唯一要做的就是 fork 出一个子进程,然后这个子进程就会处理接下来的所有保存工作,父进程无须执行任何磁盘 I/O 操作。
- RDB 文件需要保存整个数据集的状态,如果快照规则设置的不合适,主线程过多的fork子线程,可能会消耗相对较长的时间,影响Redis对外提供服务的能力。
- 快照是定期生成的,所以如果redis意外down掉的话,就会丢失最后一次快照后的所有修改(数据有丢失)。
2. AOF
2.1 定义
redis会将每一个写请求都通过write函数追加到文件中(默认是 appendonly.aof)。当redis重启时会通过重新执行文件中保存的写命令来在内存中重建整个数据库的内容。AOF默认是关闭的,如要开启,进行如下配置:
appendonly yes
H71AGTJ8K$C8FH[H3$E0W4A.png
2.2 AOF文件保存过程
H71AGTJ8K$C8FH[H3$E0W4A.png-
第一步是命令的实时写入(如果是 appendfsync everysec 配置,会有1s损耗
实时写入时与RDB不一样的是,增量的追加写入到文档中:命令写入=》追加到aof_buf =》同步到aof磁盘
写入buf在同步到磁盘呢?如果实时写入磁盘会带来非常高的磁盘IO,影响整体性能。 -
第二步是对aof文件的重写
为什么要对aof文件重写呢?
aof重写是为了减少aof文件的大小,可以手动或者自动触发。我们知道,有些数据可能会存在大量的写操作,这样有可能出现冗余,随着时间和业务的推进,aof文件会越来越大,会对服务器造成性能损耗,而且在数据恢复时也增大了难度。就需要将aof文件进行整理,重写,使aof文件保存最新的写命令。
重写的流程如下所示:
图片.png
2.3 数据恢复过程
图片.png2.4 AOF的持久化配置
redis.windows.conf文件中配置:
appendonly yes
# 文件名称
appendfilename "appendonly.aof"
# 同步方式
appendfsync everysec
# aof重写期间是否同步
no-appendfsync-on-rewrite no
# 重写触发配置
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
# 加载aof时如果有错如何处理
aof-load-truncated yes
# 文件重写策略
aof-rewrite-incremental-fsync yes
如果redis目录中没有生成appendonly.aof,则请参考http://www.pianshen.com/article/8293214148/
127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> set msg hello
OK
127.0.0.1:6379> flushall
OK
127.0.0.1:6379> rpush numbers 1 2 3 4 5
(integer) 5
127.0.0.1:6379> get msg
(nil)
127.0.0.1:6379>
aof文件如下所示:
*2
$6
SELECT
$1
0
*1
$8
FLUSHALL
*3
$3
set
$3
msg
$5
hello
*1
$8
flushall
*7
$5
rpush
$7
numbers
$1
1
$1
2
$1
3
$1
4
$1
5
可以看到值记录了我们写命令相关信息。
2.5 AOF的重写
Redis 可以在 AOF 文件体积变得过大时,自动地在后台对 AOF 进行重写: 重写后的新 AOF 文件包含了恢复当前数据集所需的最小命令
集合。
重写的流程是这样,主进程会fork一个子进程出来进行AOF重写,这个重写过程并不是基于原有的aof文件来做的,而是有点类似于快照的方式,全量遍历内存中的数据,然后逐个序列到aof文件中。在fork子进程这个过程中,服务端仍然可以对外提供服务,那这个时候重写的aof文件的数据和redis内存数据不一致了怎么办?不用担心,这个过程中,主进程的数据更新操作,会缓存到aof_rewrite_buf中,也就是单独开辟一块缓存来存储重写期间收到的命令,当子进程重写完以后再把缓存中的数据追加到新的aof文件。当所有的数据全部追加到新的aof文件中后,把新的aof文件重命名为,此后所有的操作都会被写入新的aof文件。
如果在rewrite过程中出现故障,不会影响原来aof文件的正常工作,只有当rewrite完成后才会切换文件。因此这个rewrite过程是比较可靠
的。
2.6 AOF的特点
- 最安全,在启用appendfsync always时,任何已写入的数据都不会丢失,使用在启用appendfsync everysec也至多只会丢失1秒的数据。
- AOF文件在发生断电等问题时也不会损坏,即使出现了某条日志只写入了一半的情况,也可以使用redis-check-aof工具轻松修复。
- AOF文件易读,可修改,在进行了某些错误的数据清除操作后,只要AOF文件没有rewrite,就可以把AOF文件备份出来,把错误的命令删除,然后恢复数据。
- AOF文件通常比RDB文件更大
- 性能消耗比RDB高
- 数据恢复速度比RDB慢
网友评论