3、Redis数据持久化

337 阅读11分钟

3、Redis数据持久化

1、Redis持久化详解

1.1Redis不同持久化方式的优缺点

RDB优点

  • RDB是一个非常紧凑的二进制文件,它保存了某个时间点得数据集,比较适合做冷备,全量复制的场景。比如可以在每个小时报保存一下过去24小时内的数据,同时每天保存过去30天的数据,这样即使出了问题也可以根据需求恢复到不同版本的数据集。
  • RDB在保存RDB文件时父进程唯一需要做的就是fork出一个子进程,接下来的工作全部由子进程来做,父进程不需要再做其他IO操作,所以RDB持久化方式可以最大化redis的性能。
  • 与AOF相比,在恢复大的数据集的时候,RDB方式会更快一些。

RDB缺点

  • redis意外停止工作(例如电源中断)的情况下丢失的数据最少的话,RDB并不适合。虽然可以配置不同的save时间点(例如每隔5分钟并且对数据集有100个写的操作),是Redis要完整的保存整个数据集是一个比较繁重的工作,通常会每隔5分钟或者更久做一次完整的保存,万一在Redis意外宕机,可能会丢失几分钟的数据。
  • RDB 需要经常fork子进程来保存数据集到硬盘上,当数据集比较大的时候,fork的过程是非常耗时的,可能会导致Redis在一些毫秒级内不能响应客户端的请求。如果数据集巨大并且CPU性能不是很好的情况下,这种情况会持续1秒,AOF也需要fork,但是可以调节重写日志文件的频率来提高数据集的耐久度。

AOF优点

  • 使用AOF 会让Redis更加耐久,可以使用不同的fsync策略,无fsync,每秒fsync,每次写的时候fsync。使用默认的每秒fsync策略,Redis的性能依然很好(fsync是由后台线程进行处理的,主线程会尽力处理客户端请求),一旦出现故障,最多丢失1秒的数据。
  • AOF文件是一个只进行追加的日志文件,所以不需要写入seek,即使由于某些原因(磁盘空间已满,写的过程中宕机等等)未执行完整的写入命令,也也可使用redis-check-aof工具修复这些问题。
  • Redis 可以在 AOF 文件体积变得过大时,自动地在后台对 AOF 进行重写,重写后的新 AOF 文件包含了恢复当前数据集所需的最小命令集合。 整个重写操作是绝对安全的,因为 Redis 在创建新 AOF 文件的过程中,会继续将命令追加到现有的 AOF 文件里面,即使重写过程中发生停机,现有的 AOF 文件也不会丢失。 而一旦新 AOF 文件创建完毕,Redis 就会从旧 AOF 文件切换到新 AOF 文件,并开始对新 AOF 文件进行追加操作。

AOF缺点

  • 对于相同的数据集来说,AOF 文件的体积通常要大于 RDB 文件的体积。
  • 根据所使用的 fsync 策略,AOF 的速度可能会慢于 RDB 。 在一般情况下, 每秒 fsync 的性能依然非常高, 而关闭 fsync 可以让 AOF 的速度和 RDB 一样快, 即使在高负荷之下也是如此。 不过在处理巨大的写入载入时,RDB 可以提供更有保证的最大延迟时间。

可以同时开启两种持久化方式,在这种情况下, 当redis重启的时候会优先载入AOF文件来恢复原始的数据,因为在通常情况下AOF文件保存的数据集要比RDB文件保存的数据集要完整。

1.2相关配置文件

RDB

 rdbchecksum yes
 dbfilename "dump.rdb"
 dir "/home/redis/src"
 ​
 save 900 1      #在900秒(15分钟)之后,如果至少有1个key发生变化,则dump内存快照
 save 300 10     #在300秒(5分钟)之后,如果至少有10个key发生变化,则dump内存快照
 save 60 10000   #在60秒(1分钟)之后,如果至少有10000个key发生变化,则dump内存快照

AOF

 appendonly yes
 appendfilename "appendonly.aof"
 ​
 #只能使用一个
 # appendfsync always      #每次更新操作后手动调用fsync()将数据写到磁盘(慢,安全)
 # appendfsync everysec      每秒同步一次(折中,默认值)
 # appendfsync no        #等操作系统进行数据缓存同步到磁盘(快)等操作系统进行数据缓存同步到磁盘(快)

1.3工作方式

dump.rdb:

当 Redis 需要保存 dump.rdb 文件时, 服务器执行以下操作:

  • Redis 调用forks. 同时拥有父进程和子进程。
  • 子进程将数据集写入到一个临时 RDB 文件中。
  • 当子进程完成对新 RDB 文件的写入时,Redis 用新 RDB 文件替换原来的 RDB 文件,并删除旧的 RDB 文件。

这种工作方式使得 Redis 可以从写时复制(copy-on-write)机制中获益。

appendonly.aof:

AOF 重写和 RDB 创建快照一样,都巧妙地利用了写时复制机制:

  • Redis 执行 fork() ,现在同时拥有父进程和子进程。
  • 子进程开始将新 AOF 文件的内容写入到临时文件。
  • 对于所有新执行的写入命令,父进程一边将它们累积到一个内存缓存中,一边将这些改动追加到现有 AOF 文件的末尾,这样样即使在重写的中途发生停机,现有的 AOF 文件也还是安全的。
  • 当子进程完成重写工作时,它给父进程发送一个信号,父进程在接收到信号之后,将内存缓存中的所有数据追加到新 AOF 文件的末尾。
  • 最后 Redis 用新文件替换旧文件,之后所有命令都会直接追加到新 AOF 文件的末尾。

2、Redis通过AOF文件进行数据迁移

2.1 方案步骤

将redis的单实通过持久化AOF数据文件迁移到redis-cluster中

1、获取单实例 X 的持久化AOF数据文件

2、创建一个8个节点的redis集群(4主、4从)

3、将B、C、D三个主节点slot槽全部分片到A上

4、将A节点使用 X 的持久化AOF文件进行重新启动

5、验证A节点上的数据完整性

6、将A节点上0-16383的slot分配到B、C、D节点上,验证数据完整性和集群状态

单实例redis X: 10.224.192.210:8000

主节点A、B、C、D:

10.224.192.194:7001、7002

10.224.192.206:7004、7007

2.2 数据迁移过程

在redis单实例中的数据:

 10.224.192.210:8000> dbsize
 (integer) 920013

将appendonly.aof文件替换后重启redis-cluster: (省略了将B、C、D节点上的slot分配到A节点上的过程,与后面的A节点分配回的操作类似)

 [root@app1 src]# ./redis-cli -c -h 10.224.192.194 -p 7001 shutdown
 [root@app1 src]# ./redis-server ../redis-cluster/data1/redis.conf

节点7001未将哈希槽shard到其他主节点时 INFO Replication:

 10.224.192.194:7001> info Replication
 # Replication
 role:master
 connected_slaves:4
 slave0:ip=10.224.192.206,port=7006,state=online,offset=140,lag=1
 slave1:ip=10.224.192.206,port=7005,state=online,offset=140,lag=1
 slave2:ip=10.224.192.194,port=7003,state=online,offset=140,lag=1
 slave3:ip=10.224.192.194,port=7007,state=online,offset=140,lag=0
 master_replid:db5e7250ec4d61d18d0a74a79aa0e9793391441e
 master_replid2:0000000000000000000000000000000000000000
 master_repl_offset:140
 second_repl_offset:-1
 repl_backlog_active:1
 repl_backlog_size:1048576
 repl_backlog_first_byte_offset:1
 repl_backlog_histlen:140

节点分配情况:

 10.224.192.194:7001> cluster slots
 1) 1) (integer) 0
    2) (integer) 16383
    3) 1) "10.224.192.194"
       2) (integer) 7001
       3) "970dc5d12ab64ed3886d372aaa8789031f32ec87"
    4) 1) "10.224.192.194"
       2) (integer) 7007
       3) "4c2ff1548604dceac42bd8baec31f81c92ee143e"
    5) 1) "10.224.192.194"
       2) (integer) 7003
       3) "e2790b87aef36db0c78db175f4c27cd77344f4fe"
    6) 1) "10.224.192.206"
       2) (integer) 7005
       3) "cd93984f6a9f5c733a5d9ec9cd4d10e3bca66cbe"
    7) 1) "10.224.192.206"
       2) (integer) 7006
       3) "810894e4c100b0c25b00ae1bd003d0f38db59d75"

数据完整性对比:

 # redis单实例节点
 10.224.192.210:8000> dbsize
 (integer) 920013
 ​
 # redis-cluster
 10.224.192.194:7001> DBSIZE
 (integer) 920013
 ​
 # key的总数量和单实例中数量完全一致
 # 由此我们可以得出,在 Redis 同一个版本之间的迁移,只需要将 RDB或AOF 文件进行复制转移即可。

tips:Redis在创建集群的时候,Redis 会优先使用AOF来恢复服务,所以如果要使用RDB文件进行恢复Redis,需要将AOF文件提前删除干净。

将slot reshard回其他主节点中:

 [root@app1 src]# ./redis-cli  --cluster reshard 10.224.192.194:7002
 [root@app1 src]# ./redis-cli  --cluster reshard 10.224.192.206:7004
 [root@app1 src]# ./redis-cli  --cluster reshard 10.224.192.206:7008
 [root@app1 src]# ./redis-cli --cluster reshard 10.224.192.194:7002
 >>> Performing Cluster Check (using node 10.224.192.194:7002)
 M: 1618b798708811d45e233f3801c87faea2846d16 10.224.192.194:7002
    slots:[0-3999] (4000 slots) master
    1 additional replica(s)
 M: 138b47c6924e0224724235548ac46f1c6e200481 10.224.192.206:7008
    slots:[8000-11999] (4000 slots) master
    1 additional replica(s)
 S: 810894e4c100b0c25b00ae1bd003d0f38db59d75 10.224.192.206:7006
    slots: (0 slots) slave
    replicates 7ddbdeb7c925666f252d43a2d5d03a9a43e61f9f
 S: 4c2ff1548604dceac42bd8baec31f81c92ee143e 10.224.192.194:7007
    slots: (0 slots) slave
    replicates 1618b798708811d45e233f3801c87faea2846d16
 S: e2790b87aef36db0c78db175f4c27cd77344f4fe 10.224.192.194:7003
    slots: (0 slots) slave
    replicates 970dc5d12ab64ed3886d372aaa8789031f32ec87
 M: 970dc5d12ab64ed3886d372aaa8789031f32ec87 10.224.192.194:7001
    slots:[12000-16383] (4384 slots) master
    1 additional replica(s)
 M: 7ddbdeb7c925666f252d43a2d5d03a9a43e61f9f 10.224.192.206:7004
    slots:[4000-7999] (4000 slots) master
    1 additional replica(s)
 S: cd93984f6a9f5c733a5d9ec9cd4d10e3bca66cbe 10.224.192.206:7005
    slots: (0 slots) slave
    replicates 138b47c6924e0224724235548ac46f1c6e200481
 [OK] All nodes agree about slots configuration.
 >>> Check for open slots...
 >>> Check slots coverage...
 [OK] All 16384 slots covered.
 How many slots do you want to move (from 1 to 16384)? 4000
 What is the receiving node ID? 1618b798708811d45e233f3801c87faea2846d16
 Please enter all the source node IDs.
   Type 'all' to use all the nodes as source nodes for the hash slots.
   Type 'done' once you entered all the source nodes IDs.
 Source node #1: 970dc5d12ab64ed3886d372aaa8789031f32ec87
 Source node #2: done
 
 Ready to move 4000 slots.
   Source nodes:
     M: 970dc5d12ab64ed3886d372aaa8789031f32ec87 10.224.192.194:7001
        slots:[12000-16383] (4384 slots) master
        1 additional replica(s)
   Destination node:
     M: 1618b798708811d45e233f3801c87faea2846d16 10.224.192.194:7002
        slots:[0-3999] (4000 slots) master
        1 additional replica(s)
   Resharding plan:
 。。。。。
 
 yes

集群的哈希槽情况:

 10.224.192.194:7001> cluster slots
 1) 1) (integer) 12000
    2) (integer) 16383
    3) 1) "10.224.192.194"
       2) (integer) 7001
       3) "970dc5d12ab64ed3886d372aaa8789031f32ec87"
    4) 1) "10.224.192.194"
       2) (integer) 7003
       3) "e2790b87aef36db0c78db175f4c27cd77344f4fe"
 2) 1) (integer) 8000
    2) (integer) 11999
    3) 1) "10.224.192.206"
       2) (integer) 7008
       3) "138b47c6924e0224724235548ac46f1c6e200481"
    4) 1) "10.224.192.206"
       2) (integer) 7005
       3) "cd93984f6a9f5c733a5d9ec9cd4d10e3bca66cbe"
 3) 1) (integer) 4000
    2) (integer) 7999
    3) 1) "10.224.192.206"
       2) (integer) 7004
       3) "7ddbdeb7c925666f252d43a2d5d03a9a43e61f9f"
    4) 1) "10.224.192.206"
       2) (integer) 7006
       3) "810894e4c100b0c25b00ae1bd003d0f38db59d75"
 4) 1) (integer) 0
    2) (integer) 3999
    3) 1) "10.224.192.194"
       2) (integer) 7002
       3) "1618b798708811d45e233f3801c87faea2846d16"
    4) 1) "10.224.192.194"
       2) (integer) 7007
       3) "4c2ff1548604dceac42bd8baec31f81c92ee143e"