• redis持久化


    redis持久化意义

    redis是内存数据库,数据基本都存放在内存中,面临的问题就是一旦服务器进程退出,服务器中的数据库状态也会消失不见。所以需要将数据保存到磁盘中,甚至是远程云服务中,当需要数据恢复时,可以直接根据备份文件恢复数据。redis对于保存到磁盘的持久化提供了俩中方案:RDB和AOF。

    image-20201026205406912

    RDB

    RDB文件就是定期生成数据的快照文件。当redis进程重新启动时,会自动读取RDB文件实现数据还原。redis默认提供开启RDB文件的持久化方案。

    image-20201026204001423

    RDB文件生成和载入

    RDB文件生成

    1. save:SAVE命令会阻塞Redis服务器进程,直到RDB文件创建完毕为止,在服务器进程阻塞期间,服务器不能处理任何命令请求
    2. bgsave: BGSAVE命令会派生出一个子进程,然后由子进程负责创建RDB文件,服务器进程(父进程)继续处理命令请求
    image-20201026204636493

    生成流程

    • redis根据配置自己尝试去生成rdb快照文件
    • fork一个子进程出来
    • 子进程尝试将数据dump到临时的rdb快照文件中
    • 完成rdb快照文件的生成之后,就替换之前的旧的快照文件

    每次生成一个新的快照,都会覆盖之前的老快照

    RDB文件载入

    Redis并没有专门用于载入RDB文件的命令,只要Redis服务器在启动时检测到RDB文件存在,它就会自动载入RDB文件。并且服务器在载入RDB文件期间,会一直处于阻塞状态,直到载入工作完成为止。

    配置

    在redis.config文件中

    // 默认配置
    save 900 1
    save 300 10
    save 60 10000
    

    save n m

    服务器在n秒之内,对数据库进行了至少m次修改

    1. 可以手动调用save或者bgsave命令,同步或异步执行rdb快照生成。
    2. save可以设置多个,就是多个snapshotting检查点,每到一个检查点,就会去check一下,是否有指定的key数量发生了变更,如果有,就生成一个新的dump.rdb文件。

    原理

    saveparams

    当redis服务启动是时候会自动读取redis.config配置文件信息,将多个配置读取到一个saveparam的数组中。该数组为redisServer结构的saveparams属性对应的值。

    image-20201026211205725

    dirty和lastsave

    1. dirty计数器记录距离上一次成功执行SAVE命令或者BGSAVE命令之后,服务器对数据库状态(服务器中的所有数据库)进行了多少次修改(包括写入、删除、更新等操作)。当服务器成功执行一个数据库修改命令之后,程序就会对dirty计数器进行更新:命令修改了多少次数据库,dirty计数器的值就增加多少。
    2. lastsave属性是一个UNIX时间戳,记录了服务器上一次成功执行SAVE命令或者BGSAVE命令的时间。

    执行

    Redis的服务器周期性操作函数serverCron默认每隔100毫秒就会执行一次,该函数用于对正在运行的服务器进行维护,它的其中一项工作就是检查save选项所设置的保存条件是否已经满足,如果满足的话,就执行BGSAVE命令。

    流程:

    1. 计算当前时间和上次执行时间差。
    2. 遍历saveparams属性值数据,当满足其中一个条件执行RDB文件更新。
    3. 更新dirty和lastsave值。

    RDB优缺点

    优点

    1. RDB会生成多个数据文件,每个数据文件都代表了某一个时刻中redis的数据,这种多个数据文件的方式,非常适合做冷备,可以将这种完整的数据文件发送到一些远程的安全存储上去,比如说Amazon的S3云服务上去,在国内可以是阿里云的ODPS分布式存储上,以预定好的备份策略来定期备份redis中的数据。
    2. RDB对redis对外提供的读写服务,影响非常小,可以让redis保持高性能,因为redis主进程只需要fork一个子进程,让子进程执行磁盘IO操作来进行RDB持久化即可。
    3. 相对于AOF持久化机制来说,直接基于RDB数据文件来重启和恢复redis进程,更加快速。

    缺点

    1. 如果想要在redis故障时,尽可能少的丢失数据,那么RDB没有AOF好。一般来说,RDB数据快照文件,都是每隔5分钟,或者更长时间生成一次,这个时候就得接受一旦redis进程宕机,那么会丢失最近5分钟的数据。
    2. RDB每次在fork子进程来执行RDB快照数据文件生成的时候,如果数据文件特别大,可能会导致对客户端提供的服务暂停数毫秒,或者甚至数秒。

    AOF

    除了RDB持久化功能之外,Redis还提供了AOF(Append Only File)持久化功能.AOF持久化是通过保存Redis服务器所执行的写命令来记录数据库状态。

    AOF持久化实现

    对每一条写入命令作为日志,以append-only方式追加。

    image-20201026213000128

    流程

    1. redis每接受一条命令就会追加日志文件
    2. 将日志文件写入到OS cache缓存中
    3. 通过fsync将OS cache中的数据写入AOF文件

    配置

    AOF配置

    appendonly yes
    

    AOF持久化,默认是关闭的,默认是打开RDB持久化

    appendonly yes,可以打开AOF持久化机制,在生产环境里面,一般来说AOF都是要打开的,除非你说随便丢个几分钟的数据也无所谓

    AOF和RDB都开启了,redis重启的时候,也是优先通过AOF进行数据恢复的,因为aof数据比较完整

    AOF的fsync策略配置

    # appendfsync always
    appendfsync everysec
    # appendfsync no
    
    1. always: 每次写入一条数据,立即将这个数据对应的写日志fsync到磁盘上去,性能非常非常差,吞吐量很低; 确保说redis里的数据一条都不丢,选择该策略.
    2. everysec: 每秒将os cache中的数据fsync到磁盘,这个最常用的,生产环境一般都这么配置,性能很高,QPS还是可以上万.
    3. no: 仅仅redis负责将数据写入os cache就撒手不管了,然后后面os自己会时不时有自己的策略将数据刷入磁盘,不可控了.

    AOF的rewrite

    AOF文件是追加写入命令方式实现持久化,随着redis的持续使用,AOF文件会越来越大。面对这个问题的解决方案是AOF文件的rewrite。

    rewrite实现

    image-20201026225623326

    流程

    1. AOF文件膨胀到配置大小界限,触发AOF文件rewrite的命令BGREWEITEAOF。
    2. redis进程fork一个子进程,基于redis当前的内存结构,构建新的AOF文件。
    3. 在构建新的AOF文件与旧的AOF文件没有任何关系,是基于当前redis内存数据结构,并且会对写入命令进程重构,如:多条同一个键的写入重构成一条命令。
    4. 在rewrite期间,redis会继续接受新的写入命令,并把他们缓存在重新缓存区中。
    5. redis主进程收到rewrite写完信号后,把重新缓存池中的数据写入新的AOF文件,并用新的AOF文件替代旧的。删除旧的AOF文件。

    rewrite相关配置

    auto-aof-rewrite-percentage 100
    auto-aof-rewrite-min-size 64mb
    
    1. auto-aof-rewrite-percentage 100:比如说上一次AOFrewrite之后,是128mb然后就会接着128mb继续写AOF的日志,如果发现增长的比例,超过了之前的100%,256mb,就可能会去触发一次rewrite。
    2. auto-aof-rewrite-min-size 64mb:达到第一个100%的条件之后,还要去跟min-size:64mb去比较,256mb > 64mb,才会去触发rewrite

    AOF文件破损修复

    redis-check-aof --fix命令来修复破损的AOF文件,一般会把有问题的写入命令删除。

    实际使用

    AOF和RDB

    1. 不要仅仅使用RDB,因为那样会导致你丢失很多数据。
    2. 也不要仅仅使用AOF,因为那样有两个问题,第一,你通过AOF做冷备,没有RDB做冷备,来的恢复速度更快; 第二,RDB每次简单粗暴生成数据快照,更加健壮,可以避免AOF这种复杂的备份和恢复机制的bug
    3. 综合使用AOF和RDB两种持久化机制,用AOF来保证数据不丢失,作为数据恢复的第一选择; 用RDB来做不同程度的冷备,在AOF文件都丢失或损坏不可用的时候,还可以使用RDB来进行快速的数据恢复

    注意事项

    1. 默认开始RDB,AOF需要手动开启,俩者都开启,redis重启,数据恢复优先考虑AOF文件。
    2. 如果RDB在执行snapshotting操作,那么redis不会执行AOF rewrite; 如果redis再执行AOF rewrite,那么就不会执行RDB snapshotting。
    3. 如果RDB在执行snapshotting,此时用户执行BGREWRITEAOF命令,那么等RDB快照生成之后,才会去执行AOF rewrite。

    配置

    1. 在企业中,RDB的生成策略,用默认的也差不多。save 60 10000:如果你希望尽可能确保说,RDB最多丢1分钟的数据,那么尽量就是每隔1分钟都生成一个快照,低峰期,数据量很少,也没必要。10000->生成RDB,1000->RDB,这个根据你自己的应用和业务的数据量,实际决定。

    2. AOF一定要打开,fsync策略everysec。

    3. auto-aof-rewrite-percentage 100: 就是当前AOF大小膨胀到超过上次100%,上次的两倍。

      auto-aof-rewrite-min-size 64mb: 根据你的数据量来定,16mb,32mb。

    数据备份方案

    RDB非常适合做冷备,每次生成之后,就不会再有修改了。

    1. 写crontab定时调度脚本去做数据备份
    2. 每小时都copy一份rdb的备份,到一个目录中去,仅仅保留最近48小时的备份
    3. 每天都保留一份当日的rdb的备份,到一个目录中去,仅仅保留最近1个月的备份
    4. 每次copy备份的时候,都把太旧的备份给删了
    5. 每天晚上将当前服务器上所有的数据备份,发送一份到远程的云服务上去

    脚本:

    /usr/local/redis
    
    每小时copy一次备份,删除48小时前的数据
    crontab -e
    0 * * * * sh /usr/local/redis/copy/redis_rdb_copy_hourly.sh
    
    redis_rdb_copy_hourly.sh
    
    #!/bin/sh 
    cur_date=`date +%Y%m%d%k`
    rm -rf /usr/local/redis/snapshotting/$cur_date
    mkdir /usr/local/redis/snapshotting/$cur_date
    cp /var/redis/6379/dump.rdb /usr/local/redis/snapshotting/$cur_date
    del_date=`date -d -48hour +%Y%m%d%k`
    rm -rf /usr/local/redis/snapshotting/$del_date
    
    
    每天copy一次备份
    crontab -e
    0 0 * * * sh /usr/local/redis/copy/redis_rdb_copy_daily.sh
    
    redis_rdb_copy_daily.sh
    
    
    #!/bin/sh 
    
    cur_date=`date +%Y%m%d`
    rm -rf /usr/local/redis/snapshotting/$cur_date
    mkdir /usr/local/redis/snapshotting/$cur_date
    cp /var/redis/6379/dump.rdb /usr/local/redis/snapshotting/$cur_date
    del_date=`date -d -1month +%Y%m%d`
    rm -rf /usr/local/redis/snapshotting/$del_date
    
    每天一次将所有数据上传一次到远程的云服务器上去
    

    数据恢复方案

    1. 如果是redis进程挂掉,那么重启redis进程即可,直接基于AOF日志文件恢复数据,最多就丢一秒的数据。
    2. 如果是redis进程所在机器挂掉,那么重启机器后,尝试重启redis进程,尝试直接基于AOF日志文件进行数据恢复。AOF没有破损,也是可以直接基于AOF恢复的。如果AOF文件破损,那么用redis-check-aof fix方式修复破损文件。
    3. 如果redis当前最新的AOF和RDB文件出现了丢失/损坏,那么可以尝试基于该机器上当前的某个最新的RDB数据副本进行数据恢复
    4. 当前最新的AOF和RDB文件都出现了丢失/损坏到无法恢复,一般不是机器的故障,人为找到RDB最新的一份备份,小时级的备份可以了,小时级的肯定是最新的,copy到redis里面去,就可以恢复到某一个小时的数据。

    参考:

    1. redis设计与实现
    2. 中华石杉的亿级流量

    本文使用 mdnice 排版

    莫听穿林打叶声,何妨吟啸且徐行。竹杖芒鞋轻胜马,谁怕?一蓑烟雨任平生。
  • 相关阅读:
    11个Linux基础面试问题
    OSI模型
    戴文的Linux内核专题:10配置内核(6)
    面向对象实验四(输入输出流)
    计算机程序的思维逻辑 (2)
    计算机程序的思维逻辑 (1)
    java基础3.0:Java常用API
    java基础2.0:Object、Class、克隆、异常编程
    java基础1.0::Java面向对象、面向对象封装、抽象类、接口、static、final
    Ajax工作原理(转)
  • 原文地址:https://www.cnblogs.com/GGuoLiang/p/13889095.html
Copyright © 2020-2023  润新知