redis系列整体栏目
内容 | 链接地址 |
---|---|
【一】redis基本数据类型和使用场景 | https://zhenghuisheng.blog.csdn.net/article/details/142406325 |
【二】redis的持久化机制和原理 | https://zhenghuisheng.blog.csdn.net/article/details/142441756 |
如需转载,请输入:https://blog.csdn.net/zhenghuishengq/article/details/142441756
redis的持久化机制和原理
redis_10">一,redis的持久化机制和原理
在平常开发中,redis一般是做为缓存使用,但是在很多大型互联网公司中,都是很依赖redis,将数据存储在redis中,如果redis挂了,那么在重启之后内部的数据就会丢失,因此在redis层面,需要对内部的数据进行持久化。在redis持久化中,主要有两种方式:rdb和aof
1,RDB持久化
1.1,save方式实现
在redis中,默认使用的就是rdb这种持久化方式,可以通过redis中安装的redis.conf配置文件查看。redis配置的策略如下,可以通过配置save命令来实现持久化的的操作,在一定的时间段,配置一定的阈值,当触发到阈值时,将内存中的数据进行持久化。
save 900 1 # 在 900 秒内至少有 1 次写操作,进行快照
save 300 10 # 在 300 秒内至少有 10 次写操作,进行快照
save 60 10000 # 在 60 秒内至少有 10000 次写操作,进行快照
接下来通过详细案例测试一下,为了测试这个快照,我这边先修改一下配置,在一分钟内,只要有一次写入,那么就会触发这个快照机制
save 60 1 # 在 60 秒内至少有 1 次写操作,进行快照
CONFIG SET save "60 1" //直接在客户端里面操作,和上面这种方式2选1
随后先清空原有的dump.rdb文件,此时redis中的rdb文件被清空,或者为了测试的话,可以直接先清空所有的key-value,通过 FLUSHALL 命令即可,但是如果是线上环境需谨慎操作
truncate -s 0 dump.rbd
随后执行几条插入操作的命令,插入完之后,最后在执行以下save命令。在执行命令如果报错error的话,那是因为没满足阈值触发的条件,最好和我一样,改成60s有一次写入就触发存储的机制
set zhenghuisheng:age 18
set zhenghuisheng:height 18
set zhenghuisheng:sex 18
随后可以直接查看这个dumo.rdb文件,可以发现数据已经全部存进rdb文件中
通过数据可以得知,rdb文件是一种二进制文件,更加的适配与操作系统,如果宕机了想要数据恢复的话,那么使用这种二进制文件恢复肯定是效率最高的。
但是如果是使用这种save的方式进行持久化,也会带来部分性能问题,因为save这种方式是采用的 同步 的方式进行数据存储,安全性高,但是如果来了一个 大key,就是一个大对象,如果存一个大对象就要5s,那么此时整个redis都会被阻塞5s,跟内部的反应堆模式有关,那么就会严重影响redis的性能
1.2,bgsave的实现
既然上面的save会由于同步带来一些性能的问题,因此redis也给出了另一份解决思路,就是通过bgsave异步的方式来实现这个rdb快照,从而提高整体的性能的吞吐量。bgsave,即background,后台存储的意思
接下来依旧先演示一下bgsave的使用,先执行三条插入数据的命令,随后执行 bgsave 进行数据存储
set bgsave:001 test1
set bgsave:002 test2
set bgsave:003 test3
结果如下图,此时三条命令也已二进制的方式存入到dump.db的配置文件中
bgsave通过 写时复制(copy-on-write) 的方式实现异步操作,就是执行bgsave的主线程,在执行bgsave命令的那一刻,会fork出一个子线程来copy主线程中的所有数据,并且此时如果还有数据写入进来,会同时操作原主线程中的内存数据和新fork出现的子线程中的数据。
既然是使用异步的方式进行数据的持久化,那么就有可能会不安全,数据丢失等问题。
rdb_87">1.3,rdb的优缺点
优点
使用rdb的优点在于,内部采用的是二进制的方式进行数据存储,存储效率较高,如果宕机了要进行数据恢复的话,那么数据恢复也相对较快
缺点
缺点也很明显,首先就是选择存储的方式,即save和bgsave的方式,就是经典的高性能和高可用之间做选择。采用save方式可用保证高可用,数据相对安全,但是可能会出现整个系统出现阻塞问题;采用bgsave方式,通过写时复制的异步方式进行数据的存储,性能相对较快,但是可能造成数据丢失等不安全问题。
还有一个主要的问题,rdb是通过某种阈值触发的条件实现rdb存储,假设5分钟达到1000条命令存储一次,那么如果在这5分钟内的数据刚好到达了阈值临界点,但是此时redis宕机了,导致这5分钟的数据没有进行rbd的持久化,那么就可能会丢失5分钟的数据,在重启redis进行数据恢复的时候,这5分钟的数据将不能恢复
2,AOF持久化
虽然说在redis中默认的是使用rdb这种方式进行持久化,但是rdb这种方式很明显,可能会造成数据丢失比较多的情况,比如一个1w qps/s的系统,假设丢5分钟数据,那么就会丢失掉300万条数据,显然使用默认的方式是不太合理的
100000 * 60 * 5 = 300 0000
aof_109">2.1,aof原生命令
因此redis引入了aof文件日志写入的这种操作,在redis.conf配置文件中,打开 appendonly 设置为yes即可
appendonly yes
CONFIG SET appendonly yes //直接在客户端中操作,和上面这种方式的效果一样
set aof:test1 aof1
set aof:test2 aof2
set aof:test3 aof3
数据插入完成之后,接下来查看这个appendonly.aof文件里面到底存的是什么,由于前期aof一直是开着,因此这里只看后面几条命令即可,如果直接cat把数据直接全部的加载到内存里面,把内存撑爆,导致线上的redis服务器宕机了,那就得不偿失了
//查看尾部几条命令
tail -f appendonly.aof
可以发现里面就是一些原生执行命令。然后加一些redis内部的一些识别符,在数据进行恢复的时候,可以供内部的c++程序所识别,从而实现数据的恢复。实现数据恢复也比较简单,就是把这些命令从上往下的全部的执行一遍,然后就能将数据恢复。
aof持久化也有对应的策略,其持久化的方式有以下三种,默认采用 appendfsync everysec 每秒同步一次数据
appendfsync always
:每次写入操作都会立即将数据同步到磁盘。安全性最高,但性能最低。appendfsync everysec
:每秒同步一次数据,这是默认选项,性能和安全性之间的折中。appendfsync no
:由操作系统决定何时同步数据,这样性能最好,但在崩溃时可能丢失一些数据。
到这里为止,丢失问题的情况依旧存在,比如将1s内的数据再提交到对应的日志文件的时候,rdis宕机了,这就会导致可能丢失1秒钟的数据,相对于上面的rdb,已经属于是优化的操作。
但是aof也有属于自己的缺点,rdb采用的是二进制的压缩文件,文件大小相对较小,在做数据拷贝或者恢复的时候相对较快;而aof都是记录原生的命令,包括记录一些字符串长度等等,随着数据的增加,aof文件会越来越大,一次其数据拷贝或者做数据恢复会相对缓慢
aof_151">2.2,aof重写
上面谈到了aof的缺点,会随着时间的推移,文件变得很大,甚至可能不小心一个cat命令,直接把服务器的内存打满,导致redis宕机这种可能,因此aof内部添加了aof重写功能。
举个例子,假设一个减库存的操作,假设商品id为1001,数量有10000件,那么预扣减内存的命令就如下
set 1001:stock 9999
set 1001:stock 9998
set 1001:stock 9997
就是很明显,这个key不变,但是value在变,如果用aof存的话,可能要存10000条数据,那么aof重写的机制就是,只记录最终值。比如商品卖了5000件,常规的aof就存了5000条数据,但是通过aof重写优化之后,只存最终结果即可,这样在日志中只需要存一条,最后数据恢复时也只需要恢复这条最终的命令即可,其他的数据对于整个系统来讲都是垃圾数据。
set 1001:stock 5000
aof重写策略如下,如在文件达到32m时触发一次重写,在64m时又触发一次… 依次类推
auto-aof-rewrite-percentage:100% 触发AOF重写时,文件大小相对于上一次重写时的百分比阈值
auto-aof-rewrite-min-size:32m 触发AOF重写时,AOF文件的最小大小 //可以通过命令方式设置
CONFIG SET auto-aof-rewrite-percentage 100
CONFIG SET auto-aof-rewrite-min-size 32mb
除了上面的设置之外,也可以手动的方式触发aof重写,就是通过执行这个 BGREWRITEAOF命令
BGREWRITEAOF
通过aof重写的方式,减少aof存储文件的大小,从而提高在数据做主从架构或者恢复时的效率
rdbaof_188">3,rdb和aof优缺点
通过上面的分析,接下来可以对rdb和aof二者之前做一个全面的对比。
rdb | aof | |
---|---|---|
实现方式 | save、bgsave | 原生方式、aof重写 |
存储方式 | 二进制压缩存储 | 文本命令存储 |
宕机恢复 | 恢复速度快 | 恢复速度慢 |
数据安全 | 安全性较低 | 安全性高,最多丢1s数据 |
启动优先级 | 低,优先级低 | 高,优先使用 |
主从同步 | 不使用,同步数据少 | 使用,可以同步更多数据 |
在实际开发中,也是可以优先的考虑使用aof的方式来设计持久化问题,并且不管是在数据做同步上,还是数据恢复上,aof的优势还是占优,都能获取到更多的数据,从而保证系统的高可用。
rdbaof_203">4,rdb和aof混合持久化
在redis4.0之后,引入了一个新的持久化方式,就是可以让rdb持久化和aof持久化结合使用。rdb的优点是采用二进制存储,存储内容效,aof的优点是存储的数据量多,数据丢失量少,因此结合二者优点,让rbd和aof混合持久化。
在使用这个混合持久化之前,分别需要开启aof持久化和混合持久化的命令。
# 启用AOF持久化
appendonly yes
# 启用混合持久化
aof-use-rdb-preamble yes
以aof的维度来讲,肯定是想减少文件的容量大小,并且恢复速度快点,以rdb的维度来讲,肯定是想多存点数据,因此根据这二者维度,可以在aof文件重写之后,将数据转成二进制的格式存到文件中,通过这种方式,通过aof来解决数据丢失问题,又通过rdb文件格式来减少空间存储,并且能再宕机之后更快的恢复数据。
还是通过上面的库存例子详细的说明一下到底什么是混合持久化,首先是开启aof持久化和混合持久化,其次是开启aof的重写功能
auto-aof-rewrite-percentage:100 触发AOF重写时,文件大小相对于上一次重写时的百分比阈值
auto-aof-rewrite-min-size:32m 触发AOF重写时,AOF文件的最小大小
随后扣减10次库存,为了演示这个文件中的数据,先将 appendonly.aof 文件先清空
truncate -s 0 appendonly.aof
随后执行10条扣减库存的操作,如下图,每次对库存进行减1的操作
执行完成之后,由于此时并没有触发到aof的重写机制,因此需要手动命令进行触发
BGREWRITEAOF
最后直接查看这个 appendonly.aof 文件,可以发现有部分的二进制文件,有部分的原生命令文件。
就是说那1s的数据会通过rdb的二进制文件进行持久化,在持久化的时候依旧有命令进来,那么暂时先用aof文件进行存储,在下一秒又将前一秒的数据转换成二进制文件存储,通过这种方式最多也只会丢一秒的数据。