深入Redis学习教程之快照 rdb 和 日志 aof 进阶教程

作者 : IT 大叔 本文共3953个字,预计阅读时间需要10分钟 发布时间: 2020-10-20

什么是持久化

redis的数据时保存在内存中,持久化是将redis数据异步保存到磁盘上

持久化的方式
快照 rdb
日志 aof

RDB
rdb是快照文件(二进制文件),redis重启时会读取rdb文件载入之前保存的数据。

三种触发机制:
A.手动触发
a. save (同步)
b. bgsave (异步

PS: save是同步的,意味着在保存快照的过程中会阻塞其他操作。直到save执行完才能执行其他命令。如果要保存的数据很多就会阻塞的非常久。
如存在老的rdb文件,新替换老
save的复杂度为n

bgsave是异步的,他会使用Linux的fork()函数,这个函数作用是生成子进程,让子进程完成RDB快照的生成保存。此时客户端执行的其他命令的执行不会被阻塞(阻塞发生在fork)。当rdb快照生成以后,子进程会发送成功信号给主进程,让主进程关掉子进程。

除了要知道bgsave要用到fork之外,还要知道用到了cow(copy-on-write,写时复制),这意味着redis在fork出一个子进程之后,不会马上给子进程分配新的内存空间,而是和父进程共享同一个物理空间,只不过子进程的内存地址和父进程不同而已,但指向的是同一块物理空间。只有在bgsave过程中,父进程发生写操作修改内存数据时,才会真正去分配内存空间,并复制内存数据,而且也只是复制被修改的内存页中的数据,并不是全部内存数据;

举个例子:
主进程和子进程现在都指向同一块内存空间,这个内存空间是由一块块小的内存块组成的,假设一共有10000块。
当主进程在bgsave过程中写入新数据set k1 v1, 此时会开辟一个新的内存空间(现在就有10001块内存块了),新的key就存在这第10001个内存块中。主进程就一共指向了10001个内存块,而子进程还是只用到原来的10000个内存块。
如果k1原本就存在,我是修改数据而不是新增数据,假如k1在第5000个内存块上,系统会开辟一块新的空间,将第5000块内存块复制一份到这个新的空间里。此时也是有10001块内存块。只不过主进程指向的是旧的9999块内存块 和 新复制的那一块内存块,而子进程是指向旧的那10000块内存块。

深入Redis学习教程之快照 rdb 和 日志 aof 进阶教程插图

深入Redis学习教程之快照 rdb 和 日志 aof 进阶教程插图(2)

bgsave复杂度为n

save和bgsave的区别:
同步|异步
阻塞|fork子进程会阻塞
不会额外消耗内存|需要fork,额外消耗内存
阻塞客户端命令|不阻塞客户端命令

B.自动触发

a.按照配置文件定时触发
redis的配置文件有默认设置
save 900 1
save 300 10
save 60 10000

表示多少秒内执行了多少条写命令就会自动触发bgsave异步保存rdb

但是,redis的默认配置在实际开发中是不合适的。
因为60秒写10000条在稍微繁忙一点的系统中是很容易实现的。所以会造成频繁写入rdb的操作,给磁盘造成压力。

其他配置:
dbfilename dump.rdb     # rdb文件名
dir ./                  # rdb文件存放位置
stop-writes-on-bgsave-error yes # bgsave发生错误时是否停止
rdbcompression yes      # 是否对rdb压缩
rdbchecksum yes         # 重启时是否检查rdb文件是否正确

系统默认配置有很多是不合理的。

最佳配置:
注释掉save,表示不开启自动生成rdb,因为子进程生成rdb快照很消耗CPU和内存

# redis是单线程,但系统一般是多核,为了充分利用多核的资源,一台机器上一般会布置多个redis,此时需要以端口命名rdb文件一个redis对应一个rdb,以免多个redis共用一个rdb,造成数据覆盖
dbfilename dump-${port}.rdb

# rdb文件放在大磁盘的目录
dir /bigdiskpath

stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes

b.全量复制时触发 
进行主从复制时,主会自动生成rdb

c.执行debug reload时触发
这是一个重启命令,使用该命令重启时,内存的数据不会清空,并且会生成rdb

d.执行shutdown save关闭服务器时触发

rdb的问题
1 耗时耗性能
其时间复杂度为 n
fork生成子进程会消耗额外内存和CPU

2 部分数据易丢失
如果使用配置默认的save,那么如果在一段时间用户写入了数据但是还没达到触发条件,此时宕机,这段时间的数据没有存入rdb,会丢失

此时可以使用AOF

AOF

原理:将客户端执行的写命令写入aof日志文件,当重启redis时会读取日志文件的命令并执行一遍完成数据恢复

AOF的三种策略
always
每执行一条命令会立刻写入到aof
优点:不丢失数据
缺点:IO开销大

everysec
每秒执行一次写入aof
优点:IO开销没那么大
缺点:会丢1s的数据

no
由系统决定
优点:由操作系统自己决定,不用开发者操心
缺点:丢失的数据不可控

aof持久化原理和过程

每次执行客户端写命令的时候,redis不会直接将命令写入到aof日志文件中,而是先将命令写入到aof_buf缓冲区(每执行一条命令,就会将命令写入缓冲区),再按照上面三种策略从缓冲区fsync到磁盘文件中(fsync就是缓冲区把数据写入磁盘)。这个过程是redis主进程完成的,没有产生子进程,所以命令写入日志(appendfsync)过程中可能导致阻塞。

默认 everysec

AOF的问题
随着时间的推移,并发,执行的命令累积,aof文件会变的很大,造成的问题是使用aof恢复数据会很慢

解决方法:AOF重写
把过期的,没有用的,重复的命令化简,使得aof文件变小。
作用有二:减小磁盘占用,加快恢复数据速度

例如:
incr num   # 执行一亿次,会有一亿条命令
aof会简化为 set num 100000000

AOF重写的两种方式:

a.手动执行bgrewriteaof
原理和bgsave相似:client执行bgrewrite,redis会fork一个子进程进行aof重写,这里的重写不是读取aof文件再简化里面的命令,而是对内存的一个回溯,根据内存数据生成一个aof新文件。在这个过程中redis主进程会正常执行客户端其他写操作,并将这些操作写入aof_rewrite_buf这个缓冲,再从这个缓冲写入到新aof中。最后新aof替代旧的aof文件。

 

深入Redis学习教程之快照 rdb 和 日志 aof 进阶教程插图(4)

aof appendfsync(过程1) 和 aof rewrite(过程2)的流程图

b.根据配置文件自动触发
auto-aof-rewrite-min-size   # aof文件达到指定大小就会重写
auto-aof-rewrite-percentage # aof文件增长率达到指定值就会重写

必须两个条件同时触发才会重写。

当进行aof持久化(aof appendfsync)时会检测这两个条件,两个条件满足就会自动执行bgrewriteaof命令触发aof重写。

不要搞混了aof持久化(aof appendfsync)和aof重写,这是两个不同的独立的过程。但是他们一般会同时进行

aof的所有配置
appendonly yes  # 开启aof持久化
appendfilename "appendonly-${port}.aof"
appendfsync everysec
dir /bigdiskpath
no-appendfsync-on-rewrite yes  # 表示在进行aof重写时,停止命令写入(旧的)aof文件。可以节省性能。但是如果这段时间aof重写失败,旧的aof也没有更新命令,可能会丢失数据。需要作出权衡

auto-aof-rewrite-min-size 100
auto-aof-rewrite-percentage 64m

如果redis已经启动,可以使用 config set 动态配置。

AOF和RDB对比:
命令        RDB    AOF
启动优先级    低    高
体积        小    大
恢复速度    块    慢
数据安全    丢数据    根据策略
轻重        重    轻

RDB最佳策略
关闭自动rdb (但不代表不做rdb持久化,可以隔一段时间手动执行,隔天隔天的在夜深人静的时候手动执行bgsave,保存了数据同时避开了高峰期开销)
集中管理(意思是如果你有多台节点进行同步,只让其中一台节点进行rdb持久化,其他节点共用这个rdb文件)
主从复制时,从节点可以开

AOF最佳策略

AOF重写集中管理 ( 多节点同步时,只让一台节点进行重写,其他节点共用这个aof文件)
everysec

最佳策略:
小分片
缓存或存储 ( 将数据存到数据库中,这部分数据在redis中设置过期时间,这样redis进行持久化的时候就可以不将这部分数据写入rdb或aof)
监控
保持足够的内存给其他程序,如fork子进程

===============================

持久化的常见运维问题

fork操作
之前说做bgsave的时候,redis会fork出一个子进程,子进程进行rdb备份,主进程可以继续执行其他写操作。
但是这里又说fork是同步操作,如果子进程进行rdb持久化操作的时间太长还是会阻塞主进程,这里不是很理解。

子进程开销和优化

CPU
开销:RDB和AOF文件的生成属于CPU密集型,就是很耗CPU
优化:不要做CPU绑定,即不要将redis进程绑定到一个CPU上,不然redis的子进程和主进程都消耗这个CPU,相当于是争CPU,对主进程的操作不利。
不要和CPU密集型程序部署在一起。
尽量少做一些aof重写和bgsave操作,节省资源

内存
开销:fork内存开销,copy-on-write
优化:no-appendfsync-on-rewrite=yes

硬盘
开销:AOF和RDB文件的写入

免责声明:
1. 本站资源转自互联网,源码资源分享仅供交流学习,下载后切勿用于商业用途,否则开发者追究责任与本站无关!
2. 本站使用「署名 4.0 国际」创作协议,可自由转载、引用,但需署名原版权作者且注明文章出处
3. 未登录无法下载,登录使用金币下载所有资源。
IT小站 » 深入Redis学习教程之快照 rdb 和 日志 aof 进阶教程

常见问题FAQ

没有金币/金币不足 怎么办?
本站已开通每日签到送金币,每日签到赠送五枚金币,金币可累积。
所有资源普通会员都能下载吗?
本站所有资源普通会员都可以下载,需要消耗金币下载的白金会员资源,通过每日签到,即可获取免费金币,金币可累积使用。

发表评论