Redis持久化及复制

时间:2022-05-17 20:31:51

一、持久化的两种方式

1、RDB:

RDB是在指定时间间隔内生成数据集的时间点快照(point-in-time snapshot)持久化,它是记录一段时间内的操作,一段时间内操作超过多少次就持久化。
默认是会以快照的形式将数据持久化到磁盘的(一个二进制文件,dump.rdb,这个文件名字可以指定),在配置文件中的格式是:save N M表示在N秒之内,redis至少发生M次修改则redis抓快照到磁盘。当然也可以手动执行save或者bgsave(异步)做快照。
工作原理:
当redis需要做持久化时,redis会fork一个子进程;子进程将数据写到磁盘上一个临时RDB文件中;当子进程完成写临时文件后,将原来的RDB替换掉,这样的好处就是可以copy-on-write(写时复制技术)

2、AOF:

AOF持久化记录服务器执行的所有写操作命令,并在服务器启动时,通过重新执行这些命令来还原数据集,它可以实现每次操作都持久化。
AOF文件中的命令全部以redis协议的格式来保存,新命令会被追加到文件的末尾。 redis还可以在后台对AOF文件进行重写(rewrite),使得AOF文件的体积不会超出保存数据集状态所需的实际大小。redis还可以同时使用AOF持久化和RDB持久化。在这种情况下,当redis重启时,它会优先使用AOF文件来还原数据集, 因为AOF文件保存的数据集通常比RDB文件所保存的数据集更完整。也可以关闭持久化功能,让数据只在服务器运行时存在。

RDB方法在redis异常死掉时,最近的数据会丢失(丢失数据的多少视你save策略的配置),所以这是它最大的缺点,当业务量很大时,丢失的数据是很多的。
Append-only方法可以做到全部数据不丢失,但redis的性能就要差些。AOF就可以做到全程持久化,只需要在配置文件中开启(默认是no),appendonly yes开启AOF之后,redis每执行一个修改数据的命令,都会把它添加到aof文件中,当redis重启时,将会读取AOF文件进行“重放”以恢复到redis关闭前的最后时刻。

redis启动装载:
AOF优先于RDB 
RDB性能优于AOF,因为里面没有重复 
Redis一次性将数据加载到内存中,一次性预热

LOG Rewriting(重写)随着修改数据的执行AOF文件会越来越大,其中很多内容记录某一个key的变化情况。因此redis有了一种比较有意思的特性:在后台重建AOF文件,而不会影响client端操作。在任何时候执行bgrewriteaof命令,都会把当前内存中最短序列的命令写到磁盘,这些命令可以完全构建当前的数据情况,而不会存在多余的变化情况(比如状态变化,计数器变化等),缩小的AOF文件的大小。所以当使用AOF时,redis推荐同时使用bgrewriteaof。AOF 重写和 RDB 创建快照一样,都巧妙地利用了写时复制机制。

为了压缩AOF的持久化文件,Redis提供了bgrewriteaof命令。
收到此命令后Redis将使用与快照类似的方式将内存中的数据以命令的方式保存到临时文件中,最后替换原来的文件,以此来实现控制AOF文件的增长。
由于是模拟快照的过程,因此在重写AOF文件时并没有读取旧的AOF文件,而是将整个内存中的数据库内容用命令的方式重写了一个新的AOF文件。

AOF文件刷新的方式,有三种,参考配置参数appendfsync :
    appendfsync always:    每提交一个修改命令都调用fsync刷新到AOF文件,非常非常慢,但也非常安全;
    appendfsync everysec: 每秒钟都调用fsync刷新到AOF文件,很快,但可能会丢失一秒以内的数据;
    appendfsync no:           依靠OS进行刷新,redis不主动刷新AOF,这样最快,但安全性就差。默认并推荐每秒刷新,这样在速度和安全上都做到了兼顾。

redis默认的持久化方式是RDB。

可能由于系统原因导致了AOF损坏,redis无法再加载这个出错的AOF文件,可以按照下面步骤来修复:
    1、首先做一个AOF文件的备份,复制到其他地方;
    2、修复原始AOF文件,执行命令redis-check-aof –fix ;
    3、可以通过diff –u命令来查看修复前后文件不一致的地方;
    4、重启redis服务。

LOG Rewrite的工作原理:
同样用到了copy-on-write:首先redis会fork一个子进程;子进程将最新的AOF写入一个临时文件;父进程增量的把内存中的最新执行的修改写入(这时仍写入旧的AOF,rewrite如果失败也是安全的);当子进程完成rewrite临时文件后,父进程会收到一个信号,并把之前内存中增量的修改写入临时文件末尾;这时redis将旧AOF文件重命名,临时文件重命名,开始向新的AOF中写入。

为以防万一(机器坏掉或磁盘坏掉),最好定期把使用filesnapshotting 或 Append-only 生成的*rdb *.aof文件备份到远程机器上,然后可以用crontab定时(比如每半小时)scp一次。如果没有使用redis的主从功能 ,半小时备份一次应该是可以了;并且如果应用数据量不大的话,可以单机部署,做主从有点浪费。具体还是要根据应用而定。

接着具体解说下这两种持久化:

如果的内存中的数据量非常大的时候,rdb持久化的临时文件就会非常大,几乎是原文件的1倍,性能有所降低。
如果当写操作要立刻持久化的时候,可以执行命令:save
save是全阻塞的,bgsave是异步的。
snapshot快照首先将数据写入临时文件,当成功结束后,将临时文件重名为dump.rdb
 
使用RDB恢复数据:
自动的持久化数据存储到dump.rdb后。实际只要重启redis服务即可完成(启动redis的server时会从dump.rdb中先同步数据)
 
客户端使用命令进行持久化save存储:
   redis-cli -h ip -p port save
   redis-cli -h ip -p port bgsave
一个是在前台进行存储,一个是在后台进行存储。我的client就在server这台服务器上,所以不需要连其他机器,直接./redis-cli bgsave。
由于redis是用一个主线程来处理所有 client的请求,这种方式会阻塞所有client请求。所以不推荐使用。另一点需要注意的是,每次快照持久
化都是将内存数据完整写入到磁盘一次,并不是增量的只同步脏数据。如果数据量大的话,而且写操作比较多,必然会引起大量的磁盘io操作,可能会严重影响性能
 
如果aof或rdb文件语法有误,可以使用下面两条命令来修复。 1)aof修复命令:
  redis-check-aof --fix appendonlly.aof
2)rdb修复命令:
  redis-check-rdb --fix dump.rdb
 
aof是采用文件追加方式,将所有的写操作保存在aof文件中,当文件越来越大时,有可能存在相同的写操作,这些相同的操作可以将他浓缩为一条操作,这样可以减少aof文件的容量。
 
redis对aof新增了一种重写机制,当aof文件大小超过所设定的阈值时,redis会启动aof文件的内容压缩,只保留可以恢复数据的最小指令集,可以使用命令bgrewriteaof

RDB和AOF各自的优缺点:
1、RDB持久化优点
RDB 是一个非常紧凑(compact)的文件,它保存了Redis在某个时间点上的数据集。 这种文件非常适合用于进行备份的,比如说,可以在最近的24小时内,每小时备份一次RDB文件,并且在每个月的每一天,也备份一个 RDB 文件。这样的话,即使遇上问题,也可以随时将数据集还原到不同的版本。RDB 非常适用于灾难恢复(disaster recovery):它只有一个文件,并且内容都非常紧凑,可以(在加密后)将它传送到别的数据中心,或者亚马逊 S3 中。RDB可以最大化 Redis 的性能:父进程在保存RDB文件时唯一要做的就是fork出一个子进程,然后这个子进程就会处理接下来的所有保存工作,父进程无须执行任何磁盘 I/O 操作。RDB在恢复大数据集时的速度比AOF的恢复速度要快。

 2、RDB持久化缺点
如果需要尽量避免在服务器故障时丢失数据,那么RDB不适合这种情况。 虽然Redis允许设置不同的保存点(save point)来控制保存RDB文件的频率,但是因为RDB文件需要保存整个数据集的状态,所以它并不是一个轻松的操作。因此你可能会至少5分钟才保存一次RDB文件。在这种情况下, 一旦发生故障停机,就可能会丢失好几分钟的数据。每次保存RDB的时候,Redis都要 fork() 出一个子进程,并由子进程来进行实际的持久化工作。在数据集比较庞大时, fork() 可能会非常耗时,造成服务器在某某毫秒内停止处理客户端; 如果数据集非常巨大,并且 CPU 时间非常紧张的话,那么这种停止时间甚至可能会长达整整一秒。 虽然 AOF 重写也需要进行 fork() ,但无论 AOF 重写的执行间隔有多长,数据的耐久性都不会有任何损失。

3、AOF持久化优点
使用AOF持久化会让Redis变得非常耐久(much more durable):你可以设置不同的fsync 策略,比如无fsync ,每秒钟一次 fsync ,或者每次执行写入命令时fsync 。AOF的默认策略为每秒钟fsync 一次,在这种配置下,Redis 仍然可以保持良好的性能,并且就算发生故障停机,也最多只会丢失一秒钟的数据( fsync 会在后台线程执行,所以主线程可以继续努力地处理命令请求)。AOF 文件是一个只进行追加操作的日志文件(append only log), 因此对 AOF 文件的写入不需要进行 seek , 即使日志因为某些原因而包含了未写入完整的命令(比如写入时磁盘已满,写入中途停机,等等), redis-check-aof 工具也可以轻易地修复这种问题。
Redis可以在AOF文件体积变得过大时,自动地在后台对AOF进行重写:重写后的新AOF文件包含了恢复当前数据集所需的最小命令集合。整个重写操作是绝对安全的,因为Redis在创建新AOF文件的过程中,会继续将命令追加到现有的 AOF 文件里面,即使重写过程中发生停机,现有的 AOF 文件也不会丢失。 而一旦新 AOF 文件创建完毕,Redis 就会从旧 AOF 文件切换到新 AOF 文件,并开始对新 AOF 文件进行追加操作。AOF 文件有序地保存了对数据库执行的所有写入操作, 这些写入操作以Redis协议的格式保存, 因此AOF文件的内容非常容易被人读懂, 对文件进行分析(parse)也很轻松。 导出(export) AOF 文件也非常简单: 举个例子, 如果你不小心执行了 FLUSHALL 命令, 但只要 AOF 文件未被重写, 那么只要停止服务器,移除AOF文件末尾的FLUSHALL命令, 并重启Redis ,就可以将数据集恢复到 FLUSHALL 执行之前的状态。

 4、AOF持久化缺点
对于相同的数据集来说,AOF文件的体积通常要大于RDB文件的体积。根据所使用的fsync策略,AOF的速度可能会慢于RDB 。在一般情况下,每秒 fsync 的性能依然非常高,而关闭fsync可以让AOF的速度和 RDB 一样快, 即使在高负荷之下也是如此。 不过在处理巨大的写入载入时,RDB 可以提供更有保证的最大延迟时间(latency)。AOF 在过去曾经发生过这样的 bug : 因为个别命令的原因,导致 AOF 文件在重新载入时,无法将数据集恢复成保存时的原样。 (举个例子,阻塞命令BRPOPLPUSH就曾经引起过这样的 bug 。)测试套件里为这种情况添加了测试:它们会自动生成随机的、复杂的数据集,并通过重新载入这些数据来确保一切正常。 虽然这种 bug 在 AOF 文件中并不常见, 但是对比来说, RDB 几乎是不可能出现这种 bug 的。

RDB持久化和AOF持久化,应该用哪一个?
一般来说,如果想达到足以媲美PostgreSQL的数据安全性,应该同时使用两种持久化功能。
如果非常关心数据,但仍然可以承受数分钟以内的数据丢失, 那么可以只使用RDB持久化。
不推荐只使用AOF持久化:因为定时生成RDB快照(snapshot)非常便于进行数据库备份,并且RDB恢复数据集的速度也要比 AOF 恢复的速度要快,除此之外,使用RDB还可以避免之前提到的AOF程序的bug。

二、线上redis主从环境下的持久化策略
描述:
之前线上项目使用redis,部署了redis主从环境。redis的主从复制功能非常强大,一个master可以拥有多个slave,而一个slave又可以拥有多个slave,如此下去,形成了强大的多级服务器集群架构。由于主redis采用了AOF和save快照的持久化,长时间下去,aof文件不断增大,磁盘空间使用率逐渐暴增。
考虑到性能问题,需要对redis持久化做些调整,调整如下:
   1、主库不开启AOF持久化,并关闭save快照功能(即注释默认的三个save设置),只在每晚12点定时手动做一次bgsave快照,并将快照文件转移到异地。即主库上不产生appendonly.aof持久化文件,做的快照数据放在.rdb文件里(如dump.rdb,由于是压缩配置(rdbcompression yes表示快照文件要压缩),所以快照文件要比aof文件小),然后将这个快照文件dump.rdb转移到其他的服务器上,防止主服务器宕机造成的损失!
   2、从库开启AOF持久化并1秒落地,同样不做快照save。并在每晚12点做一次bgrewriteaof压缩appendonly.aof持久化文件,压缩前先对aof文件进行备份。
--------------------------------------------------------------------------------------------------------------------------------------------
按照这种方法进行redis持久化调整,由于线上redis的主库之前采用了AOF和save快照的持久化,之后将这两种都关闭,从库采用AOF持久化。出现了下面的现象:
就是主库关闭AOF和save快照后,主redis上的appendonly.aof持久化文件在一段时间内还在刷,在增大,这是正常的,由于之前开启的缘故,刷过一段时间,主redis的appendonly.aof持久化文件就不刷了,只有从redis的appendonly.aof持久化文件在刷了
--------------------------------------------------------------------------------------------------------------------------------------------

主从redis部署的主要目的:数据持久化,灾难恢复,冗余。主库不落地,减少消耗。
1、主库不做AOF,不做快照,允许从库访问即可。
2、从库开启AOF,不做save
配置:

1、主库配置:
关闭save开展,aof默认不开启:
#save 900 1
#save 300 10
#save 60 10000
允许从库访问:
#bind 192.168.71.229
主库设置了密码访问:
requirepass password
2、从库配置:
开启AOF持久化:
appendonly yes
appendfsync everysec
appendfilename appendonly.aof
设置主库密码:
slaveof <masterip> <masterport>

验证:

主节点:
./redis-benchmark -c 100 -n 100000 -r 10000 -q -a password
./redis-cli -a password dbsize
从节点:
./redis-cli  dbsize
数量一样就是同步成功

灾难恢复:

1、主库故障,快速恢复到最近状态描述:主库挂了(redis程序挂了/机器宕机了),从库正常,

恢复到主库挂掉的时间点:去从库手动做一次快照,拷贝快照到主库相应目录,启动,OK。

注意: 

1、若主库挂了,不能直接开启主库程序。若直接开启主库程序将会冲掉从库的AOF文件,这样将导致只能恢复到前一天晚上12的备份。

2、程序在跑时,不能重启网络(程序是通过网络接口的端口进行读写的)。网络中断将导致中断期间数据丢失。

3、确定配置文件全部正确才启动(尤其不能有数据文件名相同),否则会冲掉原来的文件,可能造成无法恢复的损失。