Redis(四)redis持久化RDB&AOF

redis持久化

http://redis.cn/topics/persistence.html
redis作为缓存时,一般数据只会放在内存中,断电等意外情况发生时,丢了数据也无所谓;
但是作为数据库使用时,数据时绝对不能丢的,追求速度的同时还要追求持久性,这时候一版两个思路:

  1. 快照/副本,RDB
  2. 操作日志,AOF

RDB

记录一份快照,redis会通过fork开启一个子进程记录快照,fork中用到了copy on write 来保证父进程的修改不会影响子进程,不会产生时点混乱问题.

redis-check-rdb dump.rdb可以检查rdb文件的完整性

RDB的优缺点

缺点

  • 不支持拉链,没有历史记录,只有一个dump,rdb
  • 丢失数据相对较多
    时点与时点之间窗口数据容易丢失:还没备份好快照,挂机了.所有全量备份都有这样的问题

拍快照的两种方式:

  1. 阻塞,记录快照时不对外提供服务;那么这个快照一定是8点的
  2. 非阻塞,记录快照的同时对外提供服务(包括修改); 这个时候记录的快照就可能会时点混乱
    比如有两个key:a和s,当8点时候记录快照,先记录了a,还没记录s,这时候a和s都发生了变化(可能是一次事务),那么会记录下变化后的s的状态,但是a还是旧的值.这就是时点混乱.
    redis怎么解决这问题呢? fork子进程记录快照, 当父进程修改值时 copy on write,不影响子进程

怎么记录快照

  1. 手动触发
    • save 客户端输入该命令执行,阻塞;关机维护等场景用到
    • bgsave 客户端输入该命令,fork创建子进程执行
  2. 配置文件中指定bqsave规则.配置文件中虽然用的save标识,但是用的是bgsave
    redis默认开启RDB

RDB相关的配置

  • 配置记录的策略:
    配置文件中SNAPSHOTTING那块:save <seconds> <changes>
    默认:
    save 900 1 900秒(15分钟)内发生了至少1个key的变化
    save 300 10 300秒(5分钟) 发生了了至少10个key的变化
    save 60 10000 60秒(1分钟) 发生了了至少1000个key的变化
    如果想关闭RDB的话,就只写个空字符串 save “”
  • rdbcompress yes 开启压缩
  • dbfilename dump.db RDB快照文件的名字
  • dir RDB快照文件的存放目录

快照的时点混乱问题(fork)

假如每个小时记录1个快照,假设8点时候开始记录,8点10分快照记录完成,那么这个快照是8点,还是8点10分,还是某个中间时刻的快照呢?
先说结论,是8点的,因为redis通过 fork子进程记录快照,父进程修改数据时copy on write 互不影响

linux中有父子进程的概念,进程间是数据隔离的,但是父进程可以让子进程看到自己的数据(export)
export的环境变量,子进程的修改不会破坏父进程;父进程的修改也不会破坏子进程;这是咋实现的呢?创建了数据副本?
创建子进程,如果是把父进程的环境变量创建个副本的话,可能有速度和空间的问题;
fork()的特点:速度快,占用空间小.创建子进程后,有个类似虚拟内存的概念,子进程和父进程中的变量指向物理内存中的同一个位置.
fork中有copy on write机制,当发生修改时复制(根据经验,基本不可能把所有数据都改一遍)
copy on write:当需要修改时,先开辟一块内存,写完新值后,把原指针指向新地址
man 2 fork 查看fork()的描述,fork是系统调用,copy on write是内核机制

Linux中的管道 | , 1.衔接前一个命令的输出作为后一个命令的输入;2.管道会创建子进程,左右两边是新创建的独立进程
[root@instance-3myjwcaa ~]# export num=0 设置一个变量
[root@instance-3myjwcaa ~]# echo $num 打印这个变量
0
[root@instance-3myjwcaa ~]# ((num++)) 变量自增1
[root@instance-3myjwcaa ~]# echo $num 打印变量
1
[root@instance-3myjwcaa ~]# ((num++)) | echo ok 在管道符左边num++,然后观察下bash中num的值
ok
[root@instance-3myjwcaa ~]# echo $num 可以看出还是1,因为管道两边创建了子进程,不会改变父进程中的变量
1
但是 echo $$ | cat 和 echo $BASHPID | cat 结果不一样;
$$优先级高于管道, 会先把$$替换成pid号,再执行官道,开启俩进程;而$BASHPID优先级低于管道.

优点

  • 类似Java中的序列化内存和磁盘之间的序列化和反序列化,速度很快

AOF

AOF,append only
redis的写操作记录到文件中
优点: 丢失数据少.
缺点: 体量无限变大,恢复慢
RDB和AOF可以同时开启,但是如果开启了AOF,重启时只会用AOF恢复;

AOF中可能会有很多可以抵消掉的操作,比如频繁的修改一个元素,其实只有最后一个修改有效.
4.0以前,AOF只记录操作日志,采用重写的方式去删除抵消的指令,合并重复的指令,最终仍是一个纯指令的日志文件
4.0以后做了个优化,重写时,先将老的数据RDB到AOF文件中,然后将时间窗口内的操作 增量的记录其指令;相当于结合了RDB和老版AOF.(类似hdfs中,fsimage+edit.log)

redis内输入: BGREWRITEAOF 手动触发重写,重写之后AOF文件才会变为RDB+AOF的混合体
Redis 2.4 后可以自动触发 AOF 重写

AOF相关的配置

  1. no
  2. always
  3. 每秒

配置文件再APPEND ONLY MODE那块

  • appendonly yes/no 是否开启AOF,默认no;
  • appendfilename AOF文件名,文件会记录在RDB的dir目录下
  • appendfsync always/everysec/no 默认everysec
    linux中的写操作, 都要经过内核,新建一个fd,内核会给该fd开启一个buffer, buffer满了后内核会批量刷写到磁盘,或由程序调用flush批量刷写到磁盘;
    appendfsync no: 不调用flush,内核buffer啥时候满了啥时候刷;这样可能丢失最后一个buffer的内容
    appendfsync always: 每一次写操作,就调用flush,刷写到磁盘
    appendfsync everysec: 每秒调用flush,有概率丢失1秒内最后一个buffer的内容;但也最多丢失1秒的东西了
  • no-appendfsync-on-rewrite no 如果有子进程在(bgsave等)写数据,就不会调用flush,减少IO争抢,同时也带来丢数据风险
  • aof-load-truncated yes
  • aof-use-rdb-preamble yes 开启RDB和AOF混合体;当开启时,AOF文件会以"REDIS"开头;
  • auto-aof-rewrite-percentage 100 当AOF文件增加了指定百分比时,满足重写条件;redis会记录上一次重写后的AOF文件大小,用来比较; 这个值设为0就是不自动重写
  • auto-aof-rewrite-min-size 64mb AOF文件到达一定size后触发重写;这是为了防止达到上面百分比后,文件仍然很小的情况
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值