这是我参与8月更文挑战的第2天,活动详情查看:8月更文挑战
前言
redis是基于内存
的NoSQL数据库,一旦发生服务器宕机就会造成数据的丢失。为了防止数据丢失,redis采用了持久化技术
,分别是rdb
和aof
。
一、RDB持久化
RDB持久化指的是每隔一段时间
将内存中的数据集快照
写入磁盘中的二进制文件(dump.rdb)
。那redis是如何触发持久化快照的呢?
1.1 save
当其中一个客户端执行save
命令时,redis会进行快照持久化
时,redis进入阻塞状态,将不响应客户端的请求命令,直至持久化过程完成。当持久化完成后,会将新的rdb文件替换
旧的rdb文件。
很显然,阻塞式是有弊端的,如果redis内存中有大量的数据,持久化的过程将会消耗大量的时间,期间redis将不能响应客户端,降低用户体验。
1.2 bgsave
当客户端执行bgsave
命令时,redis会fork一个与主进程相同
的子进程,fork期间不能响应
客户端。当fork完成后,会通过子进程将内存数据进行快照持久化
,期间redis主进程依然可以响应
客户端。当持久化完成后,会将新的rdb文件替换
旧的rdb文件。
很显然,每次手动执行
bgsave
命令,还是非常麻烦的,毕竟我们不能时刻守在服务器旁边执行命令。所以引出了自动触发bgsave
命令。
# 900s内至少执行一条写命令,触发
save 900 1
# 300s内至少执行10条写命令,触发
save 300 10
# 60s内至少执行10000条写命令,触发
save 60 10000
相关参数
# 持久化 rdb文件遇到错误时,主进程是否接受写入,yes 表示停止写入,如果是no 表示redis继续提供服务。
stop-writes-on-bgsave-error yes
# 在进行快照镜像时,是否进行压缩。yes:压缩,但是需要一些cpu的消耗。no:不压缩,需要更多的磁盘空间。
rdbcompression yes
# 一个CRC64的校验就被放在了文件末尾,当存储或者加载rbd文件的时候
# 会有一个10%左右的性能下降,为了达到性能的最大化,你可以关掉这个配置项。
rdbchecksum yes
# 快照的文件名
dbfilename dump.rdb
# 存放快照的目录
dir /var/lib/redis
1.3 优缺点
(1)rbd文件是一个二进制文件
,是内存数据集快照
,存储上非常紧凑,文件小。所以适合备份和灾难恢复。恢复大量数据时比aof速度快。
(2)rdb文件是二进制文件
,所以适合主从复制
。
(3)如果服务器发生宕机,会造成一段时间
的数据丢失
。
二、AOF持久化
为了弥补rdb
会丢失一段时间数据的缺点
,redis引入了另一种方式,那就是aof
。redis服务器会将每一个写命令
通过write函数追加到文件最后位置。当redis重启时,会通过重新执行文件中保存的写命令来重建内存数据库数据。
- 客户端发出 bgrewriteaof命令
- fork一个和主进程相同的子进程。
- 父进程继续处理client请求,除了把写命令写入到原来的aof文件中。同时把收到的写命令缓存到 AOF重写缓冲区。这样就能保证如果子进程重写失败的话并不会出问题。
- 子进程根据内存快照,按照命令合并规则写入到新AOF文件中。
- 当子进程把内存快照写入临时文件中后,子进程发信号通知父进程。然后父进程把缓存的写命令也写入到临时文件。
- 现在父进程可以使用临时文件替换老的aof文件,并重命名,后面收到的写命令也开始往新的aof文件中追加。
# 是否开启AOF,默认关闭
appendonly yes
# 指定 AOF 文件名
appendfilename appendonly.aof
# Redis支持三种刷写模式:
# appendfsync always #每次收到写命令就立即强制写入磁盘,类似MySQL的sync_binlog=1,
# 是最安全的。但该模式下速度也是最慢的,一般不推荐使用。
appendfsync everysec # 每秒钟强制写入磁盘一次,在性能和持久化方面做平衡,推荐该方式。
# appendfsync no #完全依赖OS的写入,一般为30秒左右一次,性能最好但是持久化
# 最没有保证,不推荐。
#在日志重写时,不进行命令追加操作,而只是将其放在缓冲区里,避免与命令的追加
# 造成DISK IO上的冲突。设置为yes表示rewrite期间对新写操作不fsync,暂时存在内存中,
# 等rewrite完成后再写入,默认为no,建议yes
no-appendfsync-on-rewrite yes
#当前AOF文件大小是上次日志重写得到AOF文件大小的二倍时,自动启动新的日志重写过程。
auto-aof-rewrite-percentage 100
#当前AOF文件启动新的日志重写过程的最小值,避免刚刚启动Reids时由于文件尺寸较小导致频繁的重写。
auto-aof-rewrite-min-size 64mb
一般我们配置appendfsync everysec
,每秒持久化一次。如果服务器宕机,会造成1秒的数据丢失。
2.1 文件重写
由于aof文件存放一些写操作命令,那么会遇到文件过大的问题。如何解决这个问题呢?那就是去除一些无用的
命令。redis通过数据状态重新生成一个新的aof文件(不包含无用的命令
),用新的aof文件代替旧的aof文件。
// 重写前文件
incr k1 1
set k2 a
set k2 b
incr k1 2
incr k1 3
set k2 c
del k3
...
incr k1 100
// 重写后文件
incr k1 100
set k2 c
多条命令可以合并为一个命令,为了防止单个命令过大造成客户端缓冲区溢出,对于list,set,hash,zset 等类型的操作,以64个元素为界拆分为多条。