Redis持久化
前言
Github:https://github.com/HealerJean
1、Redis持久化
Redis
支持RDB
和AOP
两种持久化模式,持久化功能有效避免进程退出造成的数据丢失问题。下次重启的时候利用之前持久化的文件即可实现数据恢复。
1.1、RDB
RDB持久化是将当前进程数据生成快照保存到硬盘的过程
RDB持久化的过程分为手动触发和自动触发
1.1.1、触发机制
1.1.1.1、手动触发
1.1.1.1.1、save
命令(已经被丢弃)
save
命令,阻塞当前的Redis服务器,直到RDB
过程完成为止,对于内存比较大的实例会造成长时间阻塞。线上环境不建议使用,save
命令已经被丢弃。运行save命令Redis日志如下:
DB saved on disk
1.1.1.1.2、bgsave
命令
Redis
进程执行fork
操作创建子进程,RDB
持久化的过程由子进程负责,完成后自动结束,阻塞只发送在fork
阶段,一般时间很短。因此Redis
内部所有涉及RDB
的操作都是bgsave
命令的方式,save
命令已经被丢弃。
Background saving started
1.1.1.2、自动触发
1、执行
shutdown
命令的时候,如果没有开启AOF持久化,则自动执行bgsave2、执行
debug relod
命令的时候也会自动触发save
操作3、如果从节点执行全量复制操作,主节点自动执行
bgsave
生成RDB
文件并发送给从节点
4、自动触发
bgsave
,使用save
相关配置,如“save m n
”,表示m秒内数据集存在n次修改时,
#Redis默认配置文件中提供了三个条件:
save 900 1
save 300 10
save 60 10000
1.1.2、bgsave
流程
1、执行bgsave
命令,Redis
父进程判断当前是否存在正在执行的子进程,如RDB
/AOF
子进程,如果存在bgsave
命令直接返回。
2、父进程执行fork
操作创建子进程,fork
操作过程中父进程会阻塞,通过info stats
命令查看latest_fork_usec
选项,可以获取最近一个fork
操作的耗时,单位为微秒。
3、父进程fork
完成后,bgsave
命令返,“Background saving started
信息并不再阻塞父进程,可以继续响应其他命令
4、子进程创建RDB
文件,根据父进程内存生成临时快照文件,完成后对原有文件进行原子替换。执行lastsave
命令可以获取最后一次生成RDB
的时间,对应info
统计的rdb_last_save_time
选项。
127.0.0.1:6379> lastsave
(integer) 1523876908
127.0.0.1:6379>
5、进程发送信号给父进程表示完成,父进程更新统计信息,具体见info Persistence
下的rdb_*
相关选项
1.1.3、RDB
文件的处理
RDB
文件保存在dir
配置指定的目录下,文件名通过dbfilename
配置指定。可以通过执行
config set dir{newDir}
和config set dbfilename{newFileName}
运行期动态执行,当下次运行时RDB
文件会保存到新目录。
127.0.0.1:6379> config set dir /usr/local/redis-4.0.8/myrdb
OK
127.0.0.1:6379> config set dbfilename myrdb.rdb
OK
127.0.0.1:6379> bgsave
Background saving started
127.0.0.1:6379>
1.1.4、RDB
的优缺点
优点:
1、RDB
是一个紧凑压缩的二进制文件,代表某个时间点的数据快照,远远小于内存大小,非常适用于备份,全量复制等场景,比如每6个小时执行bgsave
备份,并把RDB
文件拷贝到远程机器等位置,用于灾难恢复
2、Redis
加载RDB
恢复数据比AOF
快多了
缺点:
1、RDB无法做到实时持久化/秒级持久化,因为每次bgsave
都要执行fork
操作创建子进程,属于重量级操作,频繁执行成本过高
1.2、AOF
AOF(append only file)持久化,
AOF
主要就是解决数据持久化的实时性,目前是Redis
持久化的主流方式。 以独立日志的方式记录每次写命令,重启时再重新执行AOF
文件中的命令达到数据恢复的目的开启AOF功能需要进行配置,默认是不开启的,
appendonly yes
,观察redis.conf
文件,默认文件名appendonly.aof
(因为默认是关闭的所以没有写),保存路径同RDB持久化方式一致,通过dir配置指定
# 指定 AOF 文件名
appendfilename appendonly.aof
#修改为守护模式
daemonize yes
#设置进程锁文件
pidfile /usr/local/redis-4.0.8/redis.pid
#端口
port 6379
#客户端超时时间
timeout 300
#日志级别
loglevel debug
#日志文件位置
logfile /usr/local/redis-4.0.8/log-redis.log
#设置数据库的数量,默认数据库为0,可以使用SELECT <dbid>命令在连接上指定数据库id
databases 16
##指定在多长时间内,有多少次更新操作,就将数据同步到数据文件,可以多个条件配合
#save <seconds> <changes>
#Redis默认配置文件中提供了三个条件:
save 900 1
save 300 10
save 60 10000
#指定存储至本地数据库时是否压缩数据,默认为yes,Redis采用LZF压缩,如果为了节省CPU时间,
#可以关闭该#选项,但会导致数据库文件变的巨大
rdbcompression yes
#指定本地数据库文件名
dbfilename dump.rdb
#指定本地数据库路径
dir /usr/local/redis-4.0.8/db/
#指定是否在每次更新操作后进行日志记录,Redis在默认情况下是异步的把数据写入磁盘,如果不开启,可能
#会在断电时导致一段时间内的数据丢失。因为 redis本身同步数据文件是按上面save条件来同步的,所以有
#的数据会在一段时间内只存在于内存中
appendonly no
#指定更新日志条件,共有3个可选值:
#no:表示等操作系统进行数据缓存同步到磁盘(快)
#always:表示每次更新操作后手动调用fsync()将数据写到磁盘(慢,安全)
#everysec:表示每秒同步一次(折衷,默认值)
appendfsync everysec
1.2、命令写入
1.2.1、AOF
的工作流程
1、所有写命令会被追加aof_buf
(缓冲区)中
2、AOF
缓冲区根据对应的策略向硬盘做同步操作
3、随着AOF
文件越来越大,需要定期对AOF
文件进行重写,达到压缩的目的
4、当redis
服务器进行重启时,可以加载AOF
文件进行数据恢复
1.2.2、为什么要用文本协议格式
AOF命令写入的内容直接是文本协议格式,例如set hello world这条命令,在AOF缓存中会追加如下文本
1、文本协议有很好的兼容性。可读性,,方便直接修改和处理
2、开启AOF
后,所有写入命令都包含追加操作,直接采用文本协议格式,避免了字符转换带来的二次开销。
1.2.3、AOF
为什么会把命令放到aoc_buf
缓存中
Redis
使用单线程响应命令,如果每次AOF
文件命令都直接追加到硬盘,那么性能完全取决于当前硬盘负载,还有好处,就是Redis
提供了多种缓冲区到硬盘的同步的策略。在性能和安全性方面做出平衡
1.2、缓冲区到硬盘的同步的策略
Redis提供了AOF多种缓冲区同步文件策略,由参数appendfsync控制,不同值的含义如下
可配置值 | 说明 |
---|---|
always : |
命令写入aof_buf后调用系统fsync操作同步到AOF文件,fsync完成后线程返回(慢,安全) |
everysec : |
命令写入aof_buf后调用系统write操作,write完成后线程返回,fsync同步文件操作由专门的线程每秒调用一次(折衷,默认值) |
no : |
命令写入aof_buf后调用系统write操作,不对AOF文件做fsync同步,同步硬盘操作由操作系统负责,通常同步周期最长30秒,(快) |
系统化调用write
和fsync
说明:
write
会触发延迟写机制,write
操作在写入系统缓冲区后直接返回,同步硬盘操作依赖于系统调度机制,例如缓冲区写满了,同步文件之前,系统突然死机了,缓存区内数据将丢失
fsync
针对单个文件操作(比如AOF
文件)、做强制硬盘同步,fsync
将阻塞直到写入硬盘完成后返回
配置为always
,每次写入都要同步AOF文件,在一般的SATA硬盘上,Redis
只能支持大约几百TPS写入,显然跟Redis
高性能背道而驰,不建议配置
配置为everysec
,是建议的同步策略,也是默认配置,做到监控性能,理论上只有在系统死机的情况下丢失1秒的数据。
配置为no
,由于操作系统每次同步AOF的周期不可控,而且会加大每次同步硬盘的数据量,虽然提升了性能,但是数据安全性无法保证
1.3、AOF
重写机制
随着AOF
文件越来越大Redis
引入AOF
重写机制,压缩文件体积。AOF
文件重新就是讲Redis
进程内的数据,转化为写命令同步到新的AOF文件的过程
1.3.1、重写后的AOF
文件为什么可以变小
1、进程内已经超时的数据不再写入文件
2、旧的AOF
文件含有无效命令,如del key1
,hdel key2
等,重写使用进程内数据直接生成,这样新的AOF
文件只保留最终数据的写入命令,不会包含这些无用的命令。
3、多条写命令可以合并成一个,如:lpush list a
,lpush list b
,转化为 lpush list a b
,同时防止单挑命令多大造成客户端缓冲区溢出。
1.3.2、AOF重写过程的触发
1.3.2.1、手动触发
直接调用
bgerwriteaof
命令,不管有没有开启AOF
都会执行
127.0.0.1:6379> bgrewriteaof
Background append only file rewriting started
127.0.0.1:6379>
1.3.2.2、自动触发
设置参数值 服务器在
AOF
功能开启的情况下,会维持以下三个变量:
1、记录当前`AOF`文件大小的变量`aof_current_size`。
2、记录最后一次`AOF`重写之后,`AOF`文件大小的变量`aof_rewrite_base_size`。
3、增长百分比变量`aof_rewrite_perc`。
以下条件是否全部满足,如果全部满足的话,就触发自动的AOF重写操作:
1、没有bgsave
命令(RDB
持久化)/AOF
持久化在执行;
2、没有bgrewriteao
命令f在进行;
3、当前AOF
文件大小要大于server.aof_rewrite_min_size
(默认为1MB),或者在redis.conf
配置了auto-aof-rewrite-min-size
大小。当前AOF
文件大小和最后一次重写后的大小之间的比率等于或者等于指定的增长百分比(在配置文件设置了auto-aof-rewrite-percentage
参数,不设置默认为100%)
2、重启加载
AOF
和RDB
文件都可以用于服务器重启时的数据恢复
1、AOF
持久化开启且存在AOF
文件的时,优先加载AOF
文件,打印如下日志:
* DB loaded from append only file : 5.841 seconds
2、AOF
关闭或者AO
F持久化虽然开启但是AOF
文件不存在的时候,加载RDB
文件,打印如下日志
* DB loaded from disk : 5586 seconds
3、加载 AOF
或者RDB
成功之后,Redis
启动成功,如果AOF
或者RDB
文件存在错误,则Redis
启动失败并报错