zoukankan      html  css  js  c++  java
  • 探究Redis两种持久化方式下的数据恢复

        对长期奋战在一线的后端开发人员来说,都知道redis有两种持久化方式RDB和AOF,虽说大家都知道这两种方式大概运作方式,但想必有实操的人不会太多。

        这里是自己实操两种持久化方式的一点点记录。 

        先看以下摘录自redis官网原文解释(原文是English,这里用google翻译。)

     Redis持久性

     Redis提供了不同的持久性选项范围:

     

     RDB持久性按指定的时间间隔执行数据集的时间点快照。

     AOF持久性会记录服务器接收的每个写入操作,这些操作将在服务器启动时再次播放,以重建原始数据集。 使用与Redis协议本身相同的格式记录命令,并且仅采用追加方式。 当日志太大时,Redis可以在后台重写日志。

     如果希望,只要您的数据在服务器运行时就一直存在,则可以完全禁用持久性。

     可以在同一实例中同时合并AOFRDB 请注意,在这种情况下,当Redis重新启动时,AOF文件将用于重建原始数据集,因为它可以保证是最完整的。

     要理解的最重要的事情是RDBAOF持久性之间的不同权衡。 让我们从RDB开始:

     

     RDB的优势

     RDBRedis数据的非常紧凑的单文件时间点表示。 RDB文件非常适合备份。 例如,您可能希望在最近的24小时内每小时存档一次RDB文件,并在30天之内每天保存一次RDB快照。 这使您可以在发生灾难时轻松还原数据集的不同版本。

     RDB对于灾难恢复非常有用,它是一个紧凑的文件,可以传输到远程数据中心或Amazon S3(可能已加密)上。

     RDB最大限度地提高了Redis的性能,因为Redis父进程为了持久化所需要做的唯一工作就是分叉一个孩子,其余的都将做。 父实例将永远不会执行磁盘I / O或类似操作。

     与AOF相比,RDB允许大型数据集更快地重启。

      

     RDB的缺点

     如果您需要在Redis停止工作(例如断电后)的情况下最大程度地减少数据丢失的机会,则RDB不好。 您可以在生成RDB的位置配置不同的保存点 (例如,在至少五分钟之后,对数据集进行100次写入,但是您可以有多个保存点)。

     但是,通常会每隔五分钟或更长时间创建一次RDB快照,因此,如果Redis出于任何原因在没有正确 关闭的情况下停止工作,则应该准备丢失最新的数据分钟。

     RDB需要经常使用fork()才能使用子进程将其持久化在磁盘上。 如果数据集很大,Fork()可能很耗时,并且如果数据集很大且CPU性能不佳,则可能导致Redis停止为客户端服务几毫秒甚至一秒钟。 AOF还需要fork(),但您可以调整要重写日志的频率,而无需在持久性上进行权衡。

     

     AOF的优势

     使用AOF Redis更加持久:您可以有不同的fsync策略:完全没有fsync,每秒fsync,每个查询fsync 使用默认策略fsync时,每秒的写入性能仍然很好(fsync是使用后台线程执行的,并且在没有进行fsync的情况下,主线程将尽力执行写入操作。)但是您只能损失一秒钟的写入时间。

     AOF日志仅是一个追加日志,因此,如果断电,也不会出现寻道或损坏问题。 即使由于某种原因(磁盘已满或其他原因)以半写命令结束日志,redis-check-aof工具也可以轻松修复它。

     Redis太大时,Redis可以在后台自动重写AOF 重写是完全安全的,因为Redis继续追加到旧文件时,会生成一个全新的文件,其中包含创建当前数据集所需的最少操作集,一旦准备好第二个文件,Redis会切换这两个文件并开始追加到新的那一个。

     AOF以易于理解和解析的格式包含所有操作的日志。 您甚至可以轻松导出AOF文件。 例如,即使您使用FLUSHALL命令刷新了所有错误文件 ,如果在此期间未执行任何日志重写操作,您仍然可以保存数据集,只是停止服务器,删除最新命令并重新启动Redis

     

     AOF的缺点

     对于相同的数据集,AOF文件通常大于等效的RDB文件。

     根据确切的fsync策略,AOF可能比RDB慢。 通常,在将fsync设置为每秒的情况下,性能仍然很高,并且在禁用fsync的情况下,即使在高负载下,它也应与RDB一样快。 即使在巨大的写负载情况下,RDB仍然能够提供有关最大延迟的更多保证。

     

     过去,我们在特定命令中遇到过罕见的错误(例如,其中有一个涉及阻塞命令,例如BRPOPLPUSH ),导致生成的AOF在重载时无法重现完全相同的数据集。

     这些错误很少见,我们在测试套件中进行了测试,自动创建了随机的复杂数据集,然后重新加载它们以检查一切是否正常。 但是,RDB持久性几乎是不可能的。 更明确地说:Redis AOF通过增量更新现有状态来工作,就像MySQLMongoDB一样,而RDB快照一次又一次地创建所有内容,从概念上讲更健壮。

     但是 1应该注意的是,每次Redis重写AOF时,都会从数据集中包含的实际数据开始从头开始重新创建AOF,与始终附加AOF文件相比(或重写后的读数),对错误的抵抗力更强旧的AOF,而不是读取内存中的数据)。

            2)我们从未收到过有关真实环境中检测到的AOF损坏的用户报告。

     

        以上所述就是RDB会根据配置文件的配置信息定时全量备份时间点的数据; AOF则是根据同步策略追加写入备份文件。

       一. RDB快照持久化

    #首先我们看下配置文件的信息
    [root@guangzhou data]# systemctl status redis
    ● redis.service - Redis 6379
       Loaded: loaded (/usr/lib/systemd/system/redis.service; enabled; vendor preset: disabled)
       Active: active (running) since 六 2020-01-18 16:26:42 CST; 18h ago
      Process: 344 ExecStop=/usr/local/redis/bin/redis-cli -h 127.0.0.1 -p 6379 -a jcon shutdown (code=exited, status=0/SUCCESS)
      Process: 348 ExecStart=/usr/local/redis/bin/redis-server /usr/local/redis/etc/redis.conf (code=exited, status=0/SUCCESS)
     Main PID: 349 (redis-server)
       CGroup: /system.slice/redis.service
               └─349 /usr/local/redis/bin/redis-server *:6379
    
    1月 18 16:26:42 guangzhou systemd[1]: Starting Redis 6379...
    1月 18 16:26:42 guangzhou systemd[1]: Started Redis 6379.
    
    #更改/usr/local/redis/etc/redis.conf中配置
    #10秒钟内2次更改写入RDB二进制文件
    save 10 2
    # RDB持久化文件名
    dbfilename dump.rdb
    
    # 数据持久化文件存储目录
    dir /usr/local/redis/data
    
    # bgsave发生错误时是否停止写入,通常为yes
    stop-writes-on-bgsave-error yes
    
    # rdb文件是否使用压缩格式
    rdbcompression yes
    
    # 是否对rdb文件进行校验和检验,通常为yes
    rdbchecksum yes

    #重启redis
    [root@guangzhou data]# systemctl restart redis

    #为便于观察先把redis数据清空,生产环境请慎重.

      127.0.0.1:6379> flushdb
      OK
      127.0.0.1:6379> keys *
      (empty list or set)

     

      #操作前清空RDB文件

      [root@guangzhou data]# pwd && ll

      /usr/local/redis/data
      总用量 0

     

     #set两条数据

     127.0.0.1:6379> set a 100

     OK
     127.0.0.1:6379> set b 200
     OK

     #重命名RDB文件

     [root@guangzhou data]# pwd && mv dump.rdb dump.rdb2 && ll
     /usr/local/redis/data
     总用量 4
     -rw-r--r-- 1 root root 108 1月  19 15:42 dump.rdb2

     #再次set两条数据

     127.0.0.1:6379> set c 300
     OK
     127.0.0.1:6379> set d 400
     OK

     #查看RDB文件,可以发现新的dump.rdb文件大于dump.rdb2,因为RDB是全量备份,dump.rdb比dump.rdb2多了key=c和key=d

     [root@guangzhou data]# ll

     总用量 8
     -rw-r--r-- 1 root root 120 1月 19 16:59 dump.rdb
     -rw-r--r-- 1 root root 108 1月 19 15:42 dump.rdb2

     #现在我们将文件重命名

     [root@guangzhou data]# pwd && mv dump.rdb dump.rdb3 &&  ll
     /usr/local/redis/data
     总用量 8

     -rw-r--r-- 1 root root 108 1月 19 15:42 dump.rdb2
     -rw-r--r-- 1 root root 120 1月 19 16:59 dump.rdb3

     #清空数据

     127.0.0.1:6379> flushdb
     OK

     #停止redis服务

     [root@guangzhou data]# systemctl stop redis

     #删除最新生成的rdb文件,重命名仅含有key=a和key=b的dump.rdb2为dump.rdb

     [root@guangzhou data]# pwd && rm -rf dump.rdb && mv dump.rdb2 dump.rdb && ll
     /usr/local/redis/data
     总用量 8
     -rw-r--r-- 1 root root 108 1月 19 15:42 dump.rdb
     -rw-r--r-- 1 root root 120 1月 19 16:59 dump.rdb3

     #重启redis服务(正常的话重启后redis仅含有key=a和key=b两个数据)

     [root@guangzhou data]# systemctl restart redis
     [root@guangzhou data]#

     #重连redis列出所有key,果然如我们所料,只有a和b

     127.0.0.1:6379> keys *
     1) "a"
     2) "b"
     127.0.0.1:6379>

     #如果对数据完整性要求较高,可以采用RDB快照,启用定时任务备份指定时间点的数据文件,这样一旦发生生产事故,可以很方便数据回滚;另外单个RDB二进制文件,方便文件分散存储,数据迁移挪到其他服务器。

         二. AOF方式持久化

    #更改/usr/local/redis/etc/redis.conf中配置
    #注释上面RDB快照持久方式的配置,并更改aof配置
    
    #开启AOF日志追加
    appendonly yes
    #日志追加的文件名
    appendfilename "appendonly.aof"
    #写入频率,为了便于观察,这里使用更新立即更新日志文件
    appendfsync always
    
    #redis服务重启
    [root@guangzhou etc]# systemctl restart redis
    [root@guangzhou etc]# systemctl status redis
    ● redis.service - Redis 6379
       Loaded: loaded (/usr/lib/systemd/system/redis.service; enabled; vendor preset: disabled)
       Active: active (running) since 一 2020-01-20 15:40:17 CST; 9s ago
      Process: 5493 ExecStop=/usr/local/redis/bin/redis-cli -h 127.0.0.1 -p 6379 -a jcon shutdown (code=exited, status=0/SUCCESS)
      Process: 5497 ExecStart=/usr/local/redis/bin/redis-server /usr/local/redis/etc/redis.conf (code=exited, status=0/SUCCESS)
     Main PID: 5498 (redis-server)
       CGroup: /system.slice/redis.service
               └─5498 /usr/local/redis/bin/redis-server 127.0.0.1:6379
    
    1月 20 15:40:17 guangzhou systemd[1]: Starting Redis 6379...
    1月 20 15:40:17 guangzhou systemd[1]: Started Redis 6379.
    
    #转到/usr/local/redis/data目录,自动生成空文件,appendonly.aof
    [root@guangzhou data]# ll
    总用量 0
    -rw-r--r-- 1 root root 0 1月  20 15:42 appendonly.aof
    
    #命令行下录入数据
    127.0.0.1:6379> keys *
    (empty list or set)
    127.0.0.1:6379> set a 1
    OK
    127.0.0.1:6379> set b 2
    OK
    127.0.0.1:6379> set c 3
    OK
    127.0.0.1:6379>
    
    #打印日志文件
    [root@guangzhou data]# ll
    总用量 8
    -rw-r--r-- 1 root root 104 1月  20 15:43 appendonly.aof
    [root@guangzhou data]# cat appendonly.aof
    *2
    $6
    SELECT
    $1
    0
    *3
    $3
    set
    $1
    a
    $1
    1
    *3
    $3
    set
    $1
    b
    $1
    2
    *3
    $3
    set
    $1
    c
    $1
    3
    #文件输出可见每次操作详情,
    #现在我们模拟异常情况,先重命名appendonly.aof文件为appendonly.aof2,停止redis服务
    [root@guangzhou data]# pwd && mv appendonly.aof appendonly.aof2 && systemctl stop redis && rm -rf ./appendonly.aof && ll
    /usr/local/redis/data
    总用量 8
    -rw-r--r-- 1 root root 104 1月  20 15:43 appendonly.aof2
    #在更改appendonly.aof2文件中c的数值为999, appendonly.aof2重命名为appendonly.aof,重启redis服务
    127.0.0.1:6379> keys *
    1) "c"
    2) "b"
    3) "a"
    127.0.0.1:6379> get c
    "993"
    #可见key=c的数据已改变
    $3
    set
    $1
    c
    $3(更改时这里需要从1变为3)
    993

     生产环境我们可以RDB快照和AOF两种方式结合起来使用,RDB快照文件可以定时备份

    注意:

    1)    auto-aof-rewrite-percentage 100

         auto-aof-rewrite-min-size 64mb

        意思启用AOF时,redis会在AOF比上次完成重写AOF时的容量大至少100%时开启一个BGREWRITEAOF,并且AOF容量至少在64MB时发生;

    2)  只配置 AOF ,重启时加载 AOF 文件恢复数据

        同时配置了 RDB 和 AOF ,启动是只加载 AOF 文件恢复数据

        只配置 RDB,启动是将加载 dump 文件恢复数据

    3) 命令行下save命令保存当前时间点全量数据快照, bgsave异步保存快照  

  • 相关阅读:
    一些鲜为人知的编程真相
    一些鲜为人知的编程真相
    Ruby 1.9不会杀死Python
    Boost.Asio和ACE之间关于Socket编程的比较
    Effective C++第17条:要在单独的语句中使用智能指针来存储由new创建的对象
    Ruby 1.9不会杀死Python
    Boost智能指针——weak_ptr
    对象生死劫 - 构造函数和析构函数的异常
    Protocol Buffers:Google 的数据交换格式
    根据出生日期计算年龄
  • 原文地址:https://www.cnblogs.com/wscsq789/p/12209993.html
Copyright © 2011-2022 走看看