为什么需要持久化?
Redis是内存数据库, 宕机后, 数据会消失, 使其能够快速恢复数据, 提供俩种持久化操作,
RDB和AOF, 注意Redis持久化不能保证数据的完整性, 当作为DB使用时, 一定要有完整的数据源(文件、mysql)
RDB
快照的方式持久化, 只关心当前数据, 不关注过程!
触发快照的方式:
1. 符合自定义配置的快照规则
2. 执行 save 或 basave命令
3. 执行flushall命令
4. 执行主从复制命令(第一次)
配置参数定期执行快照: 漏斗设计 提高性能
在
redis.conf
中配置:
save
多少秒内 数据变了多少
save "" # 不适用RDB快照
save 900 1 # 表示15分钟(900秒钟)内至少1个键被更改则进行快照
save 300 10 # 表示5分钟(300秒)内至少10个键被更改则进行快照。
save 60 10000 # 表示1分钟内至少10000个键被更改则进行快照。
命令sava... 快照执行原理:
1. 首先由父进程判断当前是否在执行save等命令, 如果执行直接返回。
2. 这时父进程操作fork( 调用OS函数复制主进程), 创建子进程, 父进程这时会阻塞。
3. 父进程fork后, 直到basave命令返回”Background saving started”信息并不再阻塞父进程
4. 子进程创建RDB文件,根据父进程内存快照生成临时快照文件,完成后对原有文件进行原子替换。
5. 子进程发送信号给父进程表示完成,父进程更新统计信息。
RDB优缺点:
优点: RDB是二进制压缩文件,占用空间小,便于传输(传给slaver), 主进程fork子进程,可以最大化Redis性能,主进程不能太大,复制过程中主进程阻塞
缺点:不保证数据完整性,会丢失最后一次快照以后更改的所有数据
AOF
AOF
(
append only fifile
)是
Redis
的另一种持久化方式。
Redis
默认情况下是不开启的。开启
AOF
持久化后, Redis 将所有对数据库进行过写入的命令(及其参数)
(
RESP
)记录到
AOF
文件, 以此达到记录数据库状态的目的
AOF会记录过程,RDB只管结果
实现方式:配置
redis.conf
# 可以通过修改redis.conf配置文件中的appendonly参数开启
appendonly yes
# AOF文件的保存位置和RDB文件的位置相同,都是通过dir参数设置的。
dir ./
# 默认的文件名是appendonly.aof,可以通过appendfilename参数修改
appendfilename appendonly.aof
AOF原理:
AOF存储的是redis命令,同步命令道=到文件中需要三个步骤:
命令传播: Redis先将执行的命令、参数发送到AOF程序中
缓存追加: AOF程序把命令转换为网络通讯协议的格式, 将协议内容追加到服务器的AOF缓存中
写入文件和保存: AOF 缓存中的内容被写入到 AOF 文件末尾,如果设定的 AOF 保存条件被满足的话,fsync 函数或者 fdatasync 函数会被调用,将写入的内容真正地保存到磁盘中。
WRITE:根据条件,将 aof_buf 中的缓存写入到 AOF 文件。
SAVE:根据条件,调用 fsync 或 fdatasync 函数,将 AOF 文件保存到磁盘中。
AOF保存的三种模式:
AOF_FSYNC_NO
:不保存。
在这种模式下, 每次调用
flflushAppendOnlyFile
函数,
WRITE
都会被执行, 但
SAVE
会被略过。
在这种模式下,
SAVE
只会在以下任意一种情况中被执行:
Redis
被关闭
AOF
功能被关闭
系统的写缓存被刷新(可能是缓存已经被写满,或者定期保存操作被执行)
这三种情况下的
SAVE
操作都会引起
Redis
主进程阻塞。
AOF_FSYNC_EVERYSEC
:每一秒钟保存一次。(默认)
在这种模式中,
SAVE
原则上每隔一秒钟就会执行一次, 因为
SAVE
操作是由后台子线程(fork)调用 的, 所以它不会引起服务器主进程阻塞。
AOF_FSYNC_ALWAYS
:每执行一个命令保存一次。(不推荐)
在这种条件下,
WRITE 和 SAVE都会执行
另外,因为
SAVE
是由
Redis
主进程执行的,所以在
SAVE 执行期间,主进程会被阻塞,不能接受命令请求。 AOF
保存模式对性能和安全性的影响
AOF重写时, 并不会执行每一条数据, 对这个操作进行了优化, 只会执行最终那条命令。
Redis为了避免AOF重写时, 服务器阻塞, 决定将AOF从写程序放在后台, 好处是:
1.
子进程进行
AOF
重写期间,主进程可以继续处理命令请求。
2、子进程带有主进程的数据副本,使用子进程而不是线程,可以在避免锁的情况下,保证数据的安全性
但是可能会出现:
子进程在进行
AOF
重写期间, 主进程还需要继续处理
命令, 而新的命令可能对现有的数据进行修改, 这会让当前数据库的数据和重写后的
AOF
文件中的数 据不一致。
解决: 添加一个AOF重写缓存,
这个缓存在 fork
出子进程之后开始启用, Redis 主进程在接到新的写命令之后, 除了会将这个写命令的协议内容追加到现有的
AOF
文件之外, 还会追加到这个缓存中。 整个重写操作绝对安全
当子进程在执行
AOF
重写时, 主进程需要执行以下三个工作:
1. 处理命令请求。
2. 将写命令追加到现有的
AOF
文件中。
3. 将写命令追加到
AOF
重写缓存中。
触发条件:
1. 配置文件中修改
# 表示当前aof文件大小超过上一次aof文件大小的百分之多少的时候会进行重写。如果之前没有重写过,以 启# 动时aof文件大小为准
auto-aof-rewrite-percentage 100
# 限制允许重写最小aof文件大小,也就是文件大小小于64mb的时候,不需要进行优化
auto-aof-rewrite-min-size 64mb
2、执行bgrewriteaof命令
混合持久化:
RDB
和
AOF
各有优缺点,
Redis 4.0
开始支持 RDB和AOF 的混合持久化。如果把混合持久化打开,AOF rewrite 的时候就直接把RDB的内容写到AOF 文件开头。
RDB的头+AOF的身体
---->appendonly.aof
开启混合持久化 : aof-use-rdb-preamble yes
RDB和AOF的对比:
1
、
RDB
存某个时刻的数据快照,采用二进制压缩存储,
AOF
存操作命令,采用文本存储
(
混合
)
2
、
RDB
性能高、
AOF
性能较低
3
、
RDB
在配置触发状态会丢失最后一次快照以后更改的所有数据,
AOF
设置为每秒保存一次,则最多
丢
2
秒的数据
4
、
Redis
以主服务器模式运行,
RDB
不会保存过期键值对数据,
Redis
以从服务器模式运行,
RDB
会保
存过期键值对,当主服务器向从服务器同步时,再清空过期键值对。
AOF
写入文件时,对过期的
key
会追加一条
del
命令,当执行
AOF
重写时,会忽略过期
key
和
del
命令。