简介redis之持久化
前言
为避免因服务器宕机,导致内存数据全部丢失的情况,Redis提供了AOF日志和RDB快照的持久化机制
思考
1.AOF的特点,三种解决aof日志阻塞问题策略的缺点,如何重写AOF日志
2.RDB快照时数据能修改吗
AOF(Append Only File)
mysql的innodb引擎在记录日志时先写redolog再写binlog,其中redolog为写前日志(Write Ahead Log,WAL),在写实际数据前,先把修改的数据记录到日志文件中。
而redis的AOF日志为写后日志,在命令执行后再记录日志
开启AOF:
–appendonly yes
实验如下:
vim redis.sh
//内容如下
#! /bin/bash
docker run -d -p 6379:6379 --name redis -v /home/docker/redis/redis.conf:/etc/redis/redis.conf -v /home/docker/redis/data:/data redis:5.0.5 redis-server /etc/redis/redis.conf
//启动脚本,运行docker容器
./redis.sh
//进入容器
docker exec -it redis redis-cli
//进入容器执行set操作并退出容器
set name z3
quit
//查看是否生成aof后缀文件
ll ./data && cat ./data/*.aof
//停止并删除当前redis容器
docker stop redis
docker rm -f $(docker ps -aq) //不推荐这样操作因为我当前只有一个容器
//重新运行脚本生成全新的redis容器
./redis.sh
docker exec -it redis redis-cli
get name //结果为z3
通过上述实验我们知道aof日志记录的是redis收到的每一条命令且以文本形式存在,当重启redis时会自动读取加载aof里的内容
虽然aof不会阻塞当前操作,但是会对下一个操作带来阻塞风险(aof也在主线程中执行,把日志写入磁盘 ,磁盘写压力大时,导致写盘慢,后续操作被阻塞)
对于这个问题aof提供了三个选项
appendfsync的值
always:同步写回,顾名思义,执行完命令立即写
everysec:每秒,先写缓冲区,隔一秒写入
no: 操作时间由系统决定
但三种策略都不是完美无缺
aof日志文件过大怎么办
aof是以文件形式记录并追加所有命令,随着时间的推移,文件会越来越大,文件太大,除了追加命令的效率也低,也会造成恢复redis数据非常缓慢的现象
aof提供了重写机制
在重写时会创建新的AOF文件,同时为了缩小文件体积,会将旧文件中的多条命令合并成一条(当一个键被反复修改时,重写只用一条)
重写日志和aof主日志不同,为避免阻塞由后台bgrewriteaof完成,重写过程为“一个拷贝,两处日志”
一个拷贝:主线程fork出后台进程,并将内存拷贝给它,用于重写
两处日志:主线程未阻塞,当有写操作,第一处日志指正在使用的aof日志,redis会把操作写到缓冲区;第二处指新的aof重写日志,这个操作也会写道重写日志缓冲区,拷贝完后写入
RDB(Redis DataBase)
与AOF记录所有命令相比,RDB记录的是某一时刻的数据,所以在做恢复的时候,可以直接把RDB文件读入内存,很快完成恢复(rdb是redis默认的持久化方案,会生成dump.rdb文件),同时conf文件内的save配置可设置快照的时间
主动生成RDB文件命令
save:在主线程中执行,会阻塞(这肯定不能接受)
bgsave:创建子进程用于写rdb文件
快照时数据能修改吗
为了保证快照的完整性,暂停写操作,这redis肯定不能接受,所以这个时候,redis会借助操作系统提供的写时复制技术(copy-on-write,COW)
bgsave子进程由主线程fork生成,共享主线程内的所有内存数据。
此时某个时间点主线程要修改一块数据(set name a),那么这块数据就会被复制一份生成该数据的副本,bgsave子进程把这个副本数据写入文件,这个过程中主线程仍可直接修改原数据。
混合方案
虽然RDB比aof恢复快,但是快照的频率很难把握(过多会增加磁盘写压力),因此redis4.0提出了混合使用的方案
aof-use-rdb-preamble yes