1.面试:请介绍下在单点Redis中数据缺失问题的解决方案:
针对这个问题,我们采用redis的数据持久化的方式来解决,
1.1.数据持久化的方式:
- 1.RDB方式
- 2.AOF方式
1.2.数据持久保存的是什么:
- 1.将当前
数据状态
进行保存,快照形式,存储数据结果,存储格式简单,关注点在数据;(RDB)
- 2.将数据的
操作过程进行保存
,日志形式,存储操作过程,存储格式复杂,关注点在数据的操作过程上(AOF)
2.RDB持久化方式
2.1.RDB介绍:
- 1.RDB官网介绍
- 2.RDB是什么:
- RDB全称:Redis Database Backup file
(Redis数据备份文件)
,也被叫做Redis数据快照
; - RDB就是:在指定的
时间间隔内
将内存中的数据集快照
写入磁盘, 也就是Snapshot快照
,当数据不存在的时候,要是想恢复,可以通过快照,将快照文件直接读到内存中
;
- RDB全称:Redis Database Backup file
2.2.两个命令:
a.RDB持久化中的两个命令如下:
- 1.save
- 2.bgsave
b.命令:save命令:
- 1.
save
:save是只管保存
,其它不管,是在主进程执行save
这个命令,那么就会导致所有任务全部阻塞。需要手动保存
。适合自己主动停机的时候使用这个命令
c.命令:bgsave:
- 1.Redis执行
bgsave
命令,是开启一个新线程执行RDB
,可以异步执行
RDB,不影响Redis主进程执行,不会阻塞其他命令执行 - 2.
bgsave
:Redis会在后台异步进行快照操作
,快照同时还可以响应客户端请求
。可以通过lastsave 命令获取最后一次成功执行快照的时间
d.bgsave的执行流程和原理:
1.bgsave流程:
- 1.fork主进程得到一个子进程,共享内存空间
- 2.子进程读取内存数据并写入新的RDB文件
- 3.用新RDB文件替换旧的RDB文件
2.bgsave原理:
- 1
.bgsave
开始时会fork主进程
得到子进程,子进程
共享主进程的内存数据。完成fork后读取内存数据并写入 RDB 文件
。 - 2.fork采用的是
copy-on-write
技术:- 当主进程执行读操作时,访问共享内存;
- 当
主进程执行写操作时,则会拷贝一份数据,执行写操作
,这样就不会影响子进程对数据的持久化
- 3.注意事项:
- bgsave是
几乎不阻塞
的,不是完全不阻塞
的。因为bgsave需要fork主进程到子进程,而fork主进程到子进程的时候,主进程是阻塞的
。 - fork(复刻)主进程得到子进程 的意思是,
主进程创建子进程,然后子进程复刻主进程中的页表
。因为Linux系统中进程操作物理内存都是通过页表来间接操作的,而页表是用来映射物理内存的
。采用页表的映射方式就只用复制映射物理内存的页表即可,不需要复制物理内存中的实际内存数据,非常的快捷和节省内存空间。
- bgsave是
- 4.解释Fork:
Fork的作用是复制一个与当前进程一样的进程
。新进程的所有数据(变量、环境变量、程序计数器等) 数值都和原进程一致,但是是一个全新的进程
,并作为原进程的子进程在Linux程序中,fork()会产生一个和父进程完全相同的子进程,但子进程在此后多会exec系统调用,出于效率考虑,Linux中引入了“写时复制技术
”- 一般情况
父进程和子进程会共用同一段物理内存
,只有进程空间的各段的内容要发生变化时,才会将父进程的内容复制一份给子进程
- 5.子进程对数据的持久化的时候,会
先
将数据写入到 一个临时文件
中,待持久化过程都结束了,再用这个临时文件替换上次持久化
好的文件。在整个过程中,主进程是不进行任何IO操作的,这就确保了极高的性能 如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感
,那RDB方式要比AOF方式更加的高效。RDB的缺点是最后一次持久化后的数据可能丢失
2.3.RDB执行的条件
- 1.用户手动输入save或bgsave命令
- save命令**:执行下面的命令,可以立即执行一次RDB:
- save命令会导致主进程执行RDB,这个过程中其它所有命令都会被阻塞。只有在数据迁移时可能用到。
- bgsave命令:下面的命令可以异步执行RDB:
- 这个命令执行后会开启独立进程完成RDB,主进程可以持续处理用户请求,不受影响。
- 2.Redis主动停机(关机)时:
会执行一次save命令,实现RDB持久化
- 注意!!!默认情况下,Redis正常停机(关机)时会执行一次RDB
。但是
突然宕机是来不及执行RDB,会造成数据的丢失。 - 这就完美解释了,为什么在没有手动配置Redis持久化的情况下,每次我们正常关机以后,重启电脑,Redis中的数据也还存在
- 注意!!!默认情况下,Redis正常停机(关机)时会执行一次RDB
- 3.触发RDB条件时
- 这个RDB配置条件是写在Redis配置文件中的,同时触发后发起的是bgsave命令,
默认情况下不开启RDB触发条件
,需要用户手动修改Redis配置文件
- 这个RDB配置条件是写在Redis配置文件中的,同时触发后发起的是bgsave命令,
# 900秒内,如果至少有1个key被修改,则执行bgsave , 如果是save "" 则表示禁用RDB
save 900 1
save 300 10
save 60 10000
2.4.RDB的恢复过程:
- 1.先通过config get dir 查询rdb文件的目录
- 2.将*.rdb的文件拷贝到别的地方
- 3.rdb的恢复
- 关闭Redis
- 先把备份的文件拷贝到工作目录下
cp dump2.rdb dump.rdb
- 启动Redis, 备份数据会直接加载
2.5.RDB优势与缺点:
a.RDB优点:
- 1.适合大规模的数据恢复
- 2.对数据完整性和一致性要求不高更适合使用
- 3.节省磁盘空间
- 4.恢复速度快
b.RDB缺点:
- 1.Fork的时候,
内存中的数据被克隆了一份,大致2倍的膨胀性需要考虑
- 2.虽然Redis在fork时使用了写时拷贝技术,但是如果数据庞大时还是比较消耗性能。在压缩、写出RDB文件都比较耗时
- 3.在备份周期
在一定间隔时间做一次备份,所以如果Redis意外down掉的话,就会丢失最后一次快照后的所有修改。
- 4.
RDB执行间隔时间长,两次RDB之间写入数据有丢失的风险
(及两者中间宕机了,那么中间的数据都没有了)
2.6.如何停止RDB
- 1.动态停止RDB:
redis-cli config set save ""
#save后给空值,表示禁用保存策略- 直接修改配置文件中的配置:
2.7.RDB总结:
3.4.配置文件说明:
- 1.rdb文件的保存路径:
Redis在哪个目录下启动,默认生成的RDB文件就在哪个目录下
, 默认名称是:dump.rdb
- 保存路径也可以修改。
默认为Redis启动时命令行所在的目录下
,可以修改:dir "/myredis/"
- 2.压缩文件:
- 对于存储到磁盘中的快照,
可以设置是否进行压缩存储
。如果是的话,redis会采用LZF算法进行压缩。 - 如果你
不想消耗CPU来进行压缩的话,可以设置为关闭此功能
。 - 这个字段的值:
推荐yes.
- 对于存储到磁盘中的快照,
- 3.检查完整性:
- 在存储快照后,还可以让redis使用
CRC64算法
来进行数据校验, - 但是这样做会增加大约10%的性能消耗,如果希望获取到最大的性能提升,可以关闭此功能
- 推荐yes.
- 在存储快照后,还可以让redis使用
- 4.停写与否:stop-writes-on-bgsave-error:
- 当Redis无法写入磁盘的话,后台存储出现错误的时候,是否要直接关掉Redis的写操作。推荐yes.
- 当Redis无法写入磁盘的话,后台存储出现错误的时候,是否要直接关掉Redis的写操作。推荐yes.
- 5.配置文件中默认的
快照配置生成的时间间隔
:- 如果3600秒至少有一个key改变,就会持久化操作,
执行bgsave
; - 如果300秒内至少100个key变化,就持久化操作,执行bgsave;
假设300秒内有103个key变化了,那么会先把前100个持久化,然后其余的再重新计算,不会一块把103个都出佳话
;60秒内有1万个key改变,就持久化操作,执行bgsave
- 禁用:如果
不设置save指令
,或者给save传入空字符串
,即save ""
- 如果3600秒至少有一个key改变,就会持久化操作,
- 6.重启redis,上述配置即可生效:
3.AOF持久化方式
3.1.什么是AOF:
- 1.AOF全称为
Append Only File(追加文件)
。Redis处理的每一个写命令都会记录在AOF文件
,可以看做是命令日志文件
- 2.AOF以日志的形式来记录每个写操作(增量保存),将Redis执行过的所有写指令记录下来(读操作不记录), 只许追加文件但不可以改写文件,redis启动之初会读取该文件重新构建数据,换言之,redis 重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作
3.2.AOF持久化流程
- 1.客户端的请求写命令会被append追加到AOF缓冲区内;
- 2.AOF缓冲区根据AOF持久化策略[always,everysec,no]将操作sync同步到磁盘的AOF文件中;
- 3.AOF文件大小超过重写策略或手动重写时,会对AOF文件rewrite重写,压缩AOF文件容量;
- 4.Redis服务重启时,会重新load加载AOF文件中的写操作达到数据恢复的目的;
3.3.AOF的配置:
- 1.AOF
默认是关闭的
,需要修改redis.conf
配置文件来开启AOF - 2.AOF文件的名称,文件名
后缀为.aof
,文件名默认为appendonly.aof,文件名可以随意指定
- 3.AOF文件的保存路径,同RDB的路径一致
- 4.AOF的命令
记录的频率
也可以通过redis.conf文件来配:
- 5.AOF同步频率三种策略对比
配置项 | 刷盘时机 | 优点 | 缺点 |
---|---|---|---|
Always | 同步刷盘 | 可靠性高,几乎不丢失数据 | 性能影响大 |
everysec | 每秒刷盘 | 性能适中 | 最多丢失1秒数据 |
no | 操作系统控制 | 性能最好 | 可靠性较差,可能丢失大量数据 |
3.4.AOF启动/修复
- AOF的备份机制和性能虽然和RDB不同, 但是备份和恢复的操作同RDB一样,都是拷贝备份文件,需要恢复时再拷贝到Redis工作目录下,启动系统即加载。
a.正常恢复
- 修改默认的appendonly no,改为yes
- 将有数据的aof文件复制一份保存到对应目录(查看目录:config get dir)
- 恢复:重启redis然后重新加载
b.异常恢复
- 修改默认的appendonly no,改为yes
- 如遇到AOF文件损坏,通过
/usr/local/bin/redis-check-aof--fix appendonly.aof
进行恢复 - 备份被写坏的AOF文件
- 恢复:重启redis,然后重新加载
3.5.Rewrite压缩
- 1.Rewrite是什么:
- AOF采用文件追加方式,文件会越来越大为避免出现此种情况,新增了重写机制, 当AOF文件的大小超过所设定的阈值时,Redis就会启动AOF文件的内容压缩, 只保留可以恢复数据的最小指令集.可以使用命令bgrewriteaof
3.6.重写:
a.重写概述:
- 1.因为是记录命令,
AOF文件会比RDB文件大的多
。而且AOF会记录对同一个key的多次写操作,但只有最后一次写操作才有意义
。通过执行bgrewriteaof
命令,可以让AOF文件执行重写功能,用最少的命令达到相同效果
b.AOF阈值
- 1.AOF阈值:Redis会在
触发阈值时自动去重写AOF文件
。阈值也可以在redis.conf
中配置:
c.重写触发机制,何时重写:
- 1.Redis会记录上次重写时的AOF大小,
默认配置是当AOF文件大小是上次rewrite后大小的一倍且文件大于64M时触发
- 2.重写虽然可以节约大量磁盘空间,减少恢复时间。但是每次重写还是有一定的负担的,因此设定Redis要满足一定条件才会进行重写。
- 3.
auto-aof-rewrite-percentage:
设置重写的基准值,文件达到100%时开始重写(文件是原来重写后文件的2倍时触发) - 4.
auto-aof-rewrite-min-size
:设置重写的基准值,最小文件64MB。达到这个值开始重写。- 例如:文件达到70MB开始重写,降到50MB,下次什么时候开始重写?100MB
- 系统载入时或者上次重写完毕时,Redis会记录此时AOF大小,设为base_size,
- 如果Redis的AOF当前大小>= base_size +base_size*100% (默认)且当前大小>=64mb(默认)的情况下,Redis会对AOF进行重写。
d.重写流程
- 1.bgrewriteaof触发重写,判断是否当前有bgsave或bgrewriteaof在运行,如果有,则等待该命令结束后再继续执行。
- 2.主进程fork出子进程执行重写操作,保证主进程不会阻塞。
- 3.子进程遍历redis内存中数据到临时文件,客户端的写请求同时写入aof_buf缓冲区和aof_rewrite_buf重写缓冲区保证原AOF文件完整以及新AOF文件生成期间的新的数据修改动作不会丢失。
- 4.子进程写完新的AOF文件后,向主进程发信号,父进程更新统计信息。2).主进程把aof_rewrite_buf中的数据写入到新的AOF文件。
- 5.使用新的AOF文件覆盖旧的AOF文件,完成AOF重写
e.重写原理,如何实现重写:
- 1.AOF文件持续增长而过大时,会fork出一条新进程来将文件重写(也是先写临时文件最后再rename),
redis4.0版本后的重写,是指上就是把rdb 的快照,以二级制的形式附在新的aof头部,作为已有的历史数据,替换掉原来的流水账操作
- 2.no-appendfsync-on-rewrite:
- 如果 no-appendfsync-on-rewrite=yes ,不写入aof文件只写入缓存,用户请求不会阻塞,但是在这段时间如果宕机会丢失这段时间的缓存数据。(降低数据安全性,提高性能)
- 如果 no-appendfsync-on-rewrite=no, 还是会把数据往磁盘里刷,但是遇到重写操作,可能会发生阻塞。(数据安全,但是性能降低)
3.7.AOF优缺点:
a.优点:
- 备份机制更稳健,丢失数据概率更低。
- 可读的日志文本,通过操作AOF稳健,可以处理误操作
b.缺点:
- 比起RDB占用更多的磁盘空间。
- 恢复备份速度要慢。
- 每次读写都同步的话,有一定的性能压力。
- 存在个别Bug,造成恢复不能
c.总结:
4.RDB和AOF的对比:
4.1.对比概述:
- 1.RDB和AOF各有自己的优缺点,如果
对数据安全性要求较高
,在实际开发中往往会结合两者来使用。 - 2.注意:
- RDB是完全的异步操作,
AOF除了频率为appendfsync always情况外,也都是异步操作
; - AOF和RDB
同时存在的混合模式也是可以的
,如果AOF和RDB同时存在的时候,RDB和AOF的写入互不干扰
,但是读取的话,Redis会优先使用从AOF文件来还原数据库状态
,如果AOF关闭状态时,则从RDB中恢复; - 在Redis版本更新的计划中,计划把RDB和AOF两者融合为一种,因为RDB和AOF混合使用非常常见;
- AOF的重写命令
BGREWRITEAOF会占用大量CPU和内存资源
;
- RDB是完全的异步操作,
- 3.AOF和RDB同时开启,redis听谁的?
- AOF和RDB同时开启,系统默认取AOF的数据(数据不会存在丢失)
4.2.用哪个好
- 1.官方推荐两个都启用。
- 如果对数据不敏感,可以选单独用RDB。
- 不建议单独用 AOF,因为可能会出现Bug。
- 如果只是做纯内存缓存,可以都不用。
4.3.官网建议
- RDB持久化方式能够在指定的时间间隔能对你的数据进行快照存储
- AOF持久化方式记录每次对服务器写的操作,当服务器重启的时候会重新执行这些命令来恢复原始的数据,AOF命令以redis协议追加保存每次写的操作到文件末尾.
- Redis还能对AOF文件进行后台重写,使得AOF文件的体积不至于过大
- 只做缓存:
- 如果你只希望你的数据在服务器运行的时候存在,你也可以不使用任何持久化方式.
- 同时开启两种持久化方式
- 在这种情况下,当redis重启的时候会优先载入AOF文件来恢复原始的数据, 因为在通常情况下AOF文件保存的数据集要比RDB文件保存的数据集要完整.
- RDB的数据不实时,同时使用两者时服务器重启也只会找AOF文件。那要不要只使用AOF呢?
- 建议不要,因为RDB更适合用于备份数据库(AOF在不断变化不好备份), 快速重启,而且不会有AOF可能潜在的bug,留着作为一个万一的手段
- 性能建议
- 因为RDB文件只用作后备用途,建议只在Slave上持久化RDB文件,而且只要15分钟备份一次就够了,只保留save 900 1这条规则。
- 如果使用AOF,好处是在最恶劣情况下也只会丢失不超过两秒数据,启动脚本较简单只load自己的AOF文件就可以了。
- 代价,一是带来了持续的IO,二是AOF rewrite的最后将rewrite过程中产生的新数据写到新文件造成的阻塞几乎是不可避免的。
- 只要硬盘许可,应该尽量减少AOF rewrite的频率,AOF重写的基础大小默认值64M太小了,可以设到5G以上。
- 默认超过原大小100%大小时重写可以改到适当的数值。