redis持久化策略梳理及主从环境下的策略调整记录

 

redis是一个支持持久化的内存数据库,也就是说redis需要经常将内存中的数据同步到磁盘来保证持久化。可以不定期的通过异步方式保存到磁盘上(即“半持久化模式”);也可以把每一次数据变化都写入到一个Append Only File(AOF)里面(即“完全持久化模式”)。redis支持两种持久化方式,一种是默认方式的RDB(Snapshotting快照)持久化,另一种是AOF(Append-only file)持久化方式。这两种持久化方式都可以将内存中的数据库状态保存到磁盘上,redis对应的也有两种落地文件:数据文件(默认文件名dump.rdb,也即快照文件)、AOF持久化文件。接下来详细说明它们之间的用法:

1.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文件中的命令全部以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推荐同时使用bgrewriteaofAOF 重写和 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,数据写入到dump文件中。如果要启用AOF持久化,就在redis.conf文件中配置如下:
    appendonly yes       #启用AOF持久化方式
    appendfilename "appendonly.aof"      #AOF文件的名称,默认为appendonly.aof
    # appendfsync always       #每次收到写命令就立即强制写入磁盘,是最有保证的完全的持久化,但速度也是最慢的,一般不推荐使用。
   appendfsync everysec       #每秒钟强制写入磁盘一次,在性能和持久化方面做了很好的折中,这种fsync策略可以兼顾速度和安全性,是受推荐的方式。
   # appendfsync no       #完全依赖OS的写入,一般为30秒左右一次,性能最好但是持久化最没有保证,不被推荐。

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

2)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 执行之前的状态。
   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将数据库快照保存在名字为dump.rdb的二进制文件中。可以对Redis 进行设置, 让它在“ N 秒内数据集至少有M个改动”这一条件被满足时,自动保存一次数据集。也可以通过调用 SAVE 或者 BGSAVE , 手动让 Redis 进行数据集保存操作。比如说, 以下设置会让 Redis 在满足“ 60 秒内有至少有1000个键被改动”这一条件时,自动保存一次数据集:
save 60 1000
这种持久化方式被称为快照(snapshot)。

快照的运作方式:
当 Redis 需要保存 dump.rdb 文件时, 服务器执行以下操作:
Redis 调用 fork() ,同时拥有父进程和子进程。
子进程将数据集写入到一个临时 RDB 文件中。
当子进程完成对新 RDB 文件的写入时,Redis 用新 RDB 文件替换原来的 RDB 文件,并删除旧的 RDB 文件。
这种工作方式使得 Redis 可以从写时复制(copy-on-write)机制中获益。
只进行追加操作的文件(append-only file,AOF)
快照功能并不是非常耐久(durable): 如果 Redis 因为某些原因而造成故障停机, 那么服务器将丢失最近写入、且仍未保存到快照中的那些数据。尽管对于某些程序来说, 数据的耐久性并不是最重要的考虑因素, 但是对于那些追求完全耐久能力(full durability)的程序来说, 快照功能就不太适用了。
从 1.1 版本开始, Redis 增加了一种完全耐久的持久化方式: AOF 持久化。
你可以通过修改配置文件来打开 AOF 功能:
appendonly yes
从现在开始, 每当 Redis 执行一个改变数据集的命令时(比如 SET), 这个命令就会被追加到 AOF 文件的末尾。
这样的话, 当 Redis 重新启时, 程序就可以通过重新执行 AOF 文件中的命令来达到重建数据集的目的。

下面是redis默认的快照设置(要想关闭save快照功能,即注释掉这三个默认的save设置即可):
save 900 1      #当有一条Keys数据被改变时,900秒刷新到Disk一次
save 300 10    #当有10条Keys数据被改变时,300秒刷新到Disk一次
save 60 10000    #当有10000条Keys数据被改变时,60秒刷新到Disk一次
Redis的RDB文件不会坏掉,因为其写操作是在一个新进程中进行的。
当生成一个新的RDB文件时,Redis生成的子进程会先将数据写到一个临时文件中,然后通过原子性rename系统调用将临时文件重命名为RDB文件。
这样在任何时候出现故障,Redis的RDB文件都总是可用的。
同时,Redis的RDB文件也是Redis主从同步内部实现中的一环。
第一次Slave向Master同步的实现是:
Slave向Master发出同步请求,Master先dump出rdb文件,然后将rdb文件全量传输给slave,然后Master把缓存的命令转发给Slave,初次同步完成。
第二次以及以后的同步实现是:
Master将变量的快照直接实时依次发送给各个Slave。
但不管什么原因导致Slave和Master断开重连都会重复以上两个步骤的过程。
Redis的主从复制是建立在内存快照的持久化基础上的,只要有Slave就一定会有内存快照发生。
可以很明显的看到,RDB有它的不足,就是一旦数据库出现问题,那么我们的RDB文件中保存的数据并不是全新的。
从上次RDB文件生成到Redis停机这段时间的数据全部丢掉了。

AOF重写:
因为 AOF 的运作方式是不断地将命令追加到文件的末尾, 所以随着写入命令的不断增加, AOF 文件的体积也会变得越来越大。举个例子, 如果你对一个计数器调用了 100 次 INCR , 那么仅仅是为了保存这个计数器的当前值, AOF 文件就需要使用 100 条记录(entry)。然而在实际上, 只使用一条 SET 命令已经足以保存计数器的当前值了, 其余 99 条记录实际上都是多余的。为了处理这种情况, Redis 支持一种有趣的特性: 可以在不打断服务客户端的情况下, 对AOF文件进行重建(rebuild)。执行 BGREWRITEAOF 命令, Redis将生成一个新的AOF文件,这个文件包含重建当前数据集所需的最少命令。

RDB和AOF之间的相互作用:
在版本号大于等于 2.4 的 Redis 中, BGSAVE 执行的过程中, 不可以执行 BGREWRITEAOF 。 反过来说, 在 BGREWRITEAOF 执行的过程中, 也不可以执行 BGSAVE 。
这可以防止两个 Redis 后台进程同时对磁盘进行大量的 I/O 操作。
如果 BGSAVE 正在执行, 并且用户显示地调用 BGREWRITEAOF 命令, 那么服务器将向用户回复一个 OK 状态, 并告知用户, BGREWRITEAOF 已经被预定执行: 一旦 BGSAVE 执行完毕, BGREWRITEAOF 就会正式开始。当 Redis 启动时, 如果 RDB 持久化和 AOF 持久化都被打开了, 那么程序会优先使用 AOF 文件来恢复数据集, 因为 AOF 文件所保存的数据通常是最完整的。

备份Redis 数据:
Redis对于数据备份是非常友好的,因为你可以在服务器运行的时候对 RDB 文件进行复制: RDB 文件一旦被创建, 就不会进行任何修改。 当服务器要创建一个新的 RDB 文件时, 它先将文件的内容保存在一个临时文件里面, 当临时文件写入完毕时, 程序才使用 原子地用临时文件替换原来的 RDB 文件。这也就是说, 无论何时, 复制 RDB 文件都是绝对安全的。

----------------------------------------------------------------------------------------------------------------------------------------------
公司线上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
3)备份策略:
主库每晚12点整给每个实例手动做一次bgsave快照,并将快照文件备份到远程节点上。
从库每晚12点整对AOF文件打包备份(tar),打包备份后做一次AOF文件压缩(bgrewriteaof)。每天的数据起始点是前一天晚上rewriteaof后的数据。

主库服务器脚本:
即主库快照之后,将快照文件转移到异地即从库机器192.168.1.121/135上面。

[root@192-168-1-132 redis]# cat redis_bgsave.sh
#!/bin/bash
CURHOUR=`date +%Y%m%d_%H`
/usr/local/bin/redis-cli -h 127.0.0.1 -p 6379 bgsave
sleep 10
rsync -av /data/redis/dump.rdb root@192.168.1.121:/data/backup/192.168.1.132-save/$CURHOUR/
rsync -av /data/redis/dump.rdb root@192.168.1.135:/data/backup/192.168.1.132-save/$CURHOUR/
sleep 10
date >> /data/logs/bgsave.log

从库服务器脚本:

[root@cdn redis]# cat redis_backup.sh
#!/bin/bash

CURDATE=`date +%Y%m%d`
CURHOUR=`date +%Y%m%d_%H`
CURTIME=`date +%Y%m%d_%H%M%S`
LOGFILE=/data/logs/redisbak/redis_allbak_${CURDATE}.log
REDISNAME=appendonly.7000
DDIR=/data/backup/redis/$CURHOUR
mkdir -p ${DDIR}
RDIR=/data/redis
cd ${RDIR}
tar -zcf $DDIR/${REDISNAME}_${CURTIME}.tar.gz appendonly.7000.aof
if [ $? != 0 ]; then
  echo "tar error $REDISNAME.aof" >> $LOGFILE
fi
sleep 5
/usr/local/bin/redis-cli -h 127.0.0.1 -p 6379 bgrewriteaof
sleep 5

###  delete old backup data dir  ###
#/bin/rm -rf `date -d -30day + "%Y%m%d"`
find /data/backup/redis/ -mtime +30 | xargs rm -rf
echo "Backup $REDISNAME ok at $CURTIME !" >> $LOGFILE

[root@cdn redis]# crontab -e
59 23 * * * /bin/bash /data/redis/redis_backup.sh >/dev/null 2>&1

[root@cdn redis]# cd /data/backup/redis/20161207_13
[root@cdn 20161207_13]# ls
appendonly.7000_20161207_133131.tar.gz

-------------再看一例----------------------------------------------------------------------------------------------------------------------
公司线上一个项目数据存储采用MySQL,共分为10个库,分布在4台机器上,每个库数据量约为10G,各机器均采用RAID5加速磁盘访问;
当同时在线人数达高峰期(10w),DB磁盘IO压力巨大,导致访问巨慢,,在线人数就很难上不去了。

针对上面描述情况,使用redis后可有效解决这一瓶颈,因为Redis数据读写都是直接操作内。

解决方案:
将部分数据压缩导入到redis后,总数据量约30G(转换成redis数据类型数据量),一主一从模型,共两组。
一台机器内存32G,开10个实例,共20个实例,多实例方便做持久化。

同样适用于上面的redis持久化策略调整方案(思路和上面一致)

主从库配置:
主库:关闭save开展,aof默认不打开,允许从库访问。主库设置了密码访问requirepass My#redis
从库:需增加配置:开启AOF持久化,关闭save快照,设置密码;
从库10个实例的配置文件分别为:slave6001.conf ~ slave6010.conf
slave6001.conf配置内容如下(其他实例拷贝这个,修改端口等其他信息即可)

daemonize yes
pidfile /var/run/slave6001.pid
port 6001
timeout 300
loglevel debug
logfile /usr/local/redis/var/debug6001.log
syslog-enabled yes
databases 16
rdbcompression yes
dbfilename slave6001.rdb
dir /data/redis-data/slave6001
slaveof 192.168.0.139 6001
masterauth My#redis
slave-serve-stale-data yes
requirepass My#redis
appendonly yes
appendfilename slave6001.aof
appendfsync everysec
no-appendfsync-on-rewrite no
vm-enabled no
vm-swap-file /tmp/redis.swap
vm-max-memory 0
vm-page-size 32
vm-pages 134217728
vm-max-threads 4
hash-max-zipmap-entries 512
hash-max-zipmap-value 64
list-max-ziplist-entries 512
list-max-ziplist-value 64
set-max-intset-entries 512
activerehashing yes

主库每晚12点给每个实例手动做一次bgsave快照。主库备份脚本(redis_bgsave.sh)

#!/bin/bash
#date=`date +%y%m%d_%H%M%S`
REDISPASSWORD=My#redis
for PORT in `seq 6001 6010`
do
/usr/local/redis/bin/redis-cli -h 127.0.0.1 -p $PORT -a $REDISPASSWORD bgsave
sleep 10
done
date >> /usr/local/redis/var/bgsave.log

从库每晚12点拷贝每个实例的AOF到其他目录并对其打包,压缩包要有异地备份,之后再压缩AOF(bgrewriteaof)。
从库备份AOF并bgrewriteaof脚本(redis_backup.sh :对单个实例)

#!/bin/sh
## FD:File Dir
## RD:Runing Dir
## 第一个参数为redis实例名
if [ $# -ne 1 ]; then
echo “Usage:$0  redis_name”
exit
fi
CURDATE=`date +%Y%m%d`
CURHOUR=`date +%Y%m%d_%H`
CURTIME=`date +%Y%m%d_%H%M%S`
REDISPASSWORD=My#redis
REDISNAME=$1
PORT=`echo $REDISNAME | cut -c6-9`
LOGFILE=/data/logs/redisbak/redis_allbak_${CURDATE}.log
if [ "${REDISNAME}" = "" ]; then
echo “redis name Error!”
exit 1
else
if [ ! -d "/data/redis-data/${REDISNAME}" ]; then
echo “redis name Error!”
exit 1
fi
fi
DDIR=/data/backup/redis/$CURHOUR
mkdir -p ${DDIR}
RDIR=/data/redis-data/$REDISNAME
cd ${RDIR}
tar -zcf $DDIR/${REDISNAME}_${CURTIME}.tar.gz $REDISNAME.aof
if [ $? != 0 ]; then
echo “tar error $REDISNAME.aof” >> $LOGFILE
#exit 1
fi
sleep 5
/usr/local/redis/bin/redis-cli -h 127.0.0.1 -p $PORT -a $REDISPASSWORD bgrewriteaof
sleep 5
###  delete old backup data dir  ###
#/bin/rm -rf `date -d -7day +”%Y%m%d”`
find /data/backup/redis/ -mtime +7 | xargs rm -rf
echo “Backup $REDISNAME ok at $CURTIME !” >> $LOGFILE

从库对所有实例备份(/data/sh/redis_allbak.sh)

#!/bin/sh
CURDATE=`date +%Y%m%d`
LOGFILE=/data/logs/redisbak/redis_allbak_${CURDATE}.log
for PORT in `seq 6001 6010`
do
/data/sh/redis_backup.sh slave${PORT} && echo “slave${PORT} ok `date +%Y%m%d_%H%M%S`” >> $LOGFILE 2>&1 || echo “slave${PORT} backup error” >> $LOGFILE 2>&1
done

操作注意事项
1)若主库挂了,不能直接开启主库程序。若直接开启主库程序将会冲掉从库的AOF文件,这样将导致只能恢复到前一天晚上12的备份。
2)程序在跑时,不能重启网络(程序是通过网络接口的端口进行读写的)。网络中断将导致中断期间数据丢失。
3)确定配置文件全部正确才启动(尤其不能有数据文件名相同),否则会冲掉原来的文件,可能造成无法恢复的损失。

灾难恢复
1)主库故障,快速恢复到最近状态描述:主库挂了(redis程序挂了/机器宕机了),从库正常,恢复到主库挂掉的时间点:去从库手动做一次快照,拷贝快照到主库相应目录,启动,OK。
在从库做一次快照,转移快照文件到其他目录,将快照文件目录拷贝到主库相应目录,启动主库,OK!
( /data/sh/redis_bgsave_cp.sh )

#!/bin/bash
REDISPASSWORD=My#redis
for PORT in `seq 6001 6010`
do
/usr/local/redis/bin/redis-cli -h 127.0.0.1 -p $PORT -a $REDISPASSWORD bgsave
sleep 5
done
sleep 15
for PORT in `seq 6001 6010`
do
SDIR=/data/redis-data/slave${PORT}/
DDIR=/data/redis_recovery/redis-data/
mkdir -p $DDIR/redis${PORT}/
cd $SDIR
cp -rf slave${PORT}.rdb $DDIR/redis${PORT}/redis${PORT}.rdb
#sleep 1
done

在主库将原来数据目录重命名。
从从库拷贝快照文件到主库。
启动主库。

2)恢复到当天12点状态注意备份数据(当前状态AOF+正常退出快照)!
停止redis。
解压AOF(/data/sh/redis_untar.sh)

#!/bin/bash
DAY=20111102
SDIR=/data/backup/redis/20161102_00/
cd $SDIR
for PORT in `seq 6001 6010`
do
tar -zxf slave${PORT}_$DAY_*.tar.gz
sleep 2
done
切割AOF(/data/sh/redis_sed.sh)
#!/bin/bash
DDIR=/data/redis_recovery/
TAG=”TAG111101_1200″
for PORT in `seq 6001 6010`
do
SDIR=/data/backup/redis/20161102_00/
SAOF=${SDIR}/slave${PORT}.aof
line=`sed -n “/$TAG/=” $SAOF`
num=$[$line + 3]
mkdir -p ${DDIR}/slave${PORT}/
sed “${num},\$d” $SAOF > ${DDIR}/slave${PORT}/slave${PORT}.aof
done

将原来数据目录重命名。
将切割出来的AOF目录重命名为配置文件的数据目录。(注释主从同步配置项)。
启动从库。
做快照,拷贝到主库,启动主库(同上面第1)步)。

3)恢复到两天或几天前12点状态从库每晚备份要备份AOF未bgrewriteaof之前的数据,可根据当天晚上12点备份,没有bfrewriteaof之前的AOF文件来进行恢复,方法同上面的第2)步。

posted @ 2017-01-09 19:13  散尽浮华  阅读(4813)  评论(0编辑  收藏  举报