系列七、Redis的持久化

一、概述

        前面的系列文章介绍了Redis的基本情况和常见操作,我们知道Redis是基于内存的数据库,也即数据时存储在内存中的,而内存中的数据有一个显著特点:断电即消失,对于一些业务来说,这显然是无法接受的,这就不得不说下Redis的持久化了,所谓持久化,用大白话讲就是 将内存中的数据写入到硬盘的过程 。针对持久化,Redis官方提供了两种形式的持久化机制,即:RDBAOF。

二、RDB(Redis Database)

2.1、概述

       在指定的时间间隔,执行数据集的时间点快照。实现类似照片记录效果的方式,就是把某一时刻的数据和状态以文件的形式写到磁盘上,也就是快照。这样一来即使机器因故障宕机,快照文件也不会丢失,数据的可靠性就得到了保证。这个快照文件就被称为RDB文件(dump.rdb)。

2.2、作用

        在指定的时间间隔内将内存中的数据集快照写入磁盘,也就是行话讲的Snapshot(内存快照),恢复时再将硬盘中的数据直接读回到内存中。

        说明:Redis中的数据都存储在内存中,保存备份时它执行的是全量快照,也就是说执行快照时会把内存中的所有数据都写到磁盘中,即一锅端。

        注意事项:RDB保存的是dump.rdb文件

2.3、触发方式

客户端方式:

        ① bgsave

        ② save(注意事项:save命令不常用,因为使用save命令时会导致redis处于阻塞状态,直至快照创建完毕,在这期间redis无法对外提供服务。)

服务端方式:

        ① 满足配置自动触发

        ② 接收客户端shutdown指令

        ③ 接收客户端flush指令(生成的rdb文件无意义,无法恢复数据)

主从复制时,主节点自动触发

2.4、触发原理

2.4.1、bgsave

        当服务端收到客户端的bgsave指令时,redis会fork一个子进程,这个子进程和主进程一模一样,相当于是主进程的一个副本,这个副本和主进程共享相同的内存,它唯一要做的工作就是将当前内存中的数据写到磁盘中,而父进程则继续对外提供服务,处理指令。原理如下:

2.4.2、save(线上禁止使用

        客户端还可以使用save命令来触发快照,当服务端收到save指令后,redis将执行持久化操作,在这期间redis将无法对外提供服务,直至直至快照创建完毕。原理如下:

2.4.3、满足配置自动触发

        如果用户在redis.conf中设置了save配置项,那么redis服务将在满足条件时自动触发一次bgsave指令,如果配置了多个save选项,那么当任意一个save选项满足条件时,都将会触发bgsave指令,说明:默认情况下RDB是开启的,其在redis.conf中的配置如下(redis版本为4.0.10):

# 默认配置说明

save 900 1: 15分钟内至少有一个key变化(after 900 sec (15 min) if at least 1 key changed) 

save 300 10:五分钟内至少有10个key变化(after 300 sec (5 min) if at least 10 keys changed)

save 60 10000:一分钟内至少有10000个key变化(after 60 sec if at least 10000 keys changed)

2.4.4、接收客户端shutdown指令

        当redis服务端收到客户端发送的shutdown指令时,会执行一次save指令,这期间服务端将会阻塞所有的客户端,不再执行客户端发送的任何指令,并在save指令执行完毕后关闭服务器,线上禁止使用!!!

2.5、触发rdb案例(满足配置自动触发)

2.5.1、修改redis.conf  SNAPSHOTTING/save 配置 

        在redis.conf配置文件中的 SNAPSHOTTING 下配置save参数,来触发redis的RDB持久化条件,格式:save m n,表示m秒内数据集存在n次修改,自动触发bgsave

save 5 2 

save 300 10

save 60 10000

2.5.2、修改rdb文件的保存位置

注意事项:redisPersistenceFiles 需要提前创建好,mkdir redisPersistenceFiles

2.5.3、配置rdb文件的名称

2.5.4、重启redis服务

        先关闭redis服务,再重新启动。

2.5.5、触发

(1)5s内触发两次set操作,观察 /dumpFiles/rdb 中的文件情况

(2)5s内只执行一次set操作,再次观察

(3)结论:基于 满足配置自动触发rdb,需要需要满足redis.conf中的配置才会触发rdb

2.6、触发rdb案例(接收客户端shutdown指令) 

2.6.1、客户端shutdown

2.7、数据恢复

2.7.1、说明

        模拟生产环境redis服务宕机(注意事项:一般情况下,生产环境会采用 主从配置+读写分离+集群 的模式对外提供服务,以达到服务的高可用,即:备份的rdb文件在从机上也会保留一份,这样当主服务宕机时,可以使用从机生成的rdb快照进行数据的恢复,达到容灾备份的目的,生产环境禁止把备份文件dump.rdb文件和生成redis服务器放在同一台机器上,必须分开各自存储!以防生产机物理损坏后,备份文件也挂了,那就无法恢复了!!!

2.7.2、备份dump文件 & 删除原始文件

        备份dump文件,模拟备份文件在从机。cp dump6379_standAlone.rdb dump6379_standAlone_bak.rdb

2.7.3、关闭redis服务(模拟宕机)

        使用 SHUTDOWN nosave 指令,模拟redis服务宕机时的场景,宕机时来不及生成rdb文件

2.7.4、拷贝备份文件(模拟从备机拷贝备份rdb)

2.7.5、重启redis服务(主机)

        重启redis服务后,数据恢复了!

2.7.6、rdb原理 

        当满足触发rdb的条件时,主进程会fork一个子进程,主进程和子进程共享内存中的数据,主进程对外提供服务,子进程用来将当前时刻内存中的数据以二进制的形式保存到磁盘中(注意:保存的是数据,不是操作),当redis服务因宕机等原因重启时,会将磁盘中的文件加载至内存重新读取进行恢复。 

2.8、rdb的优点  & 缺点

优点:

        (1)适合大规模的数据恢复;

        (2)按照业务定时备份;

        (3)对数据完整性和一致性要求不高;

        (4)rdb文件在内存中的加载速度要比aof快得多;

        

缺点:

        (1)在一定间隔时间做一次备份,所以如果redis意外宕机的话,就会丢失从当前至最近一次快照期间的数据;

        (2)由于同步是全量同步,如果数据量太大的话,会导致大量IO,严重影响服务器的性能;

        (3)rdb依赖于主进程的fork进程,即子进程,在更大的数据集中,这可能会导致服务请求的瞬间延迟;

        (4)fork的时候,内存中的数据被克隆了一份,将会出现大致2倍的膨胀性,需要考虑;

2.9、 查看最近一次快照保存时间

lastsave:得到一串时间戳

date -d @时间戳:格式化时间戳,年月日 星期 十分秒

2.10、查看rdb文件保存位置

config get dir

2.11、检修损坏的rdb文件 

        上面介绍了rdb的触发时机,实际生产环境中难免不会遇到触发rdb,子进程往磁盘中写数据时,数据还没写完整,此时恰巧服务器宕机了,那这就意味着写入dump.rdb中的数据是有问题的,当重启redis服务重新读取dump.rdb就会不成功,那么这种情况我们该怎么处理呢?前面的文章介绍了redis的安装,安装完后,在 /usr/local/bin 目录会有redis相关的指令,我们不防来回顾一下:

可以看到在 /usr/local/bin 目录有两个特殊的文件,其中redis-check-rdb是用来修复破损的rdb文件的,redis-check-aof是用来修复aof文件的

./redis-check-rdb /redisPersistenceFiles/dump6379_standAlone.rdb

2.12、禁用快照的方式 

2.12.1、动态停止所有的rdb保存规则

redis-cli config set save ""

2.12.2、禁用快照 

        修改redis.cof SNAPSHOTTING的save配置,即将save配置为空

2.13、rdb配置项详解

2.13.1、save

        作用:修改服务端触发rdb的条件;

        语法:save <seconds> <changes>

        案例:

2.13.2、dbfilename

        作用:修改默认生成的rdb文件的名称;

        语法:dbfilename xxx.rdb

        案例:

2.13.3、dir

        作用:配置rdb文件的保存位置;

        语法:dir xxx

        案例:

2.13.4、 stop-writes-on-bgsave-error

        默认yes(推荐),如果配置成no,表示你不在乎数据不一致或者有其他的手段发现和控制这种不一致,那么在快照写入失败时,也能确保redis继续接受新的写请求。

2.13.5、rdbcompression

        默认yes(推荐),对于存储到磁盘中的快照,可以设置是否进行压缩存储,如果是的话,redis会采用LZF算法进行压缩,如果你不想消耗CPU的性能来进行压缩的话,可以设置为no,关闭此功能。

2.13.6、rdbchecksum

        默认yes(推荐),在存储快照后,还可以让redis使用CRC64算法来进行数据校验,但是这样做会增加大约10%的性能消耗,如果希望获取到最大性能的提升,可以关闭此功能。

2.14、rdb总结 

        rdb是一个非常紧凑的文件(采用二进制进行保存),当满足触发rdb的条件时,父进程会fork出一个子进程,这个子进程和父进程享有共同的内存区域,是父进程的一个完全拷贝,它唯一要做得事情就是将内存中的数据持久化至磁盘中,与aof相比,在恢复大数据时会更快一些。但是它也面临着数据丢失的问题,另外在业务比较繁忙的系统中,rdb需要经常fork子进程进行持久化,当数据集比较大时,fork的过程会比较耗时,将会导致产生毫秒级别延迟,另外还要考虑一瞬间内存中的数据翻倍的问题。

三、AOF(Append Only File)

3.1、概述

        以日志的形式来记录每个写操作,将redis执行过程中的所有写指令记录下来(读操作不记录),只许追加文件但不可以改写文件,redis启动之初会读取该文件重新构建数据,换言之,redis重启的话就根据日志文件的内容将写指令从前到后执行一次,以完成数据的恢复工作。默认情况下,redis是没有开启AOF的,开启AOF功能需要在redis.conf中将配置开启:appendonly yes

3.2、原理 

        第一步:Client作为命令的来源,会有多个源头以及源源不断的请求命令;

        第二步:在这些命令到达Redis Server后并不是直接写入AOF文件,而是将这些命令先放入AOF缓存中进行保存。这里AOF缓冲区实际上是内存中的一片区域,存在的目的是当这些命令达到一定量后再写入磁盘,避免频繁的IO操作;

        第三步:AOF缓冲会根据缓冲区同步文件的三种回写策略将命令写入磁盘上的AOF文件;

        第四步:随着写入AOF内容的增加,为避免文件膨胀,会根据规则进行命令的合并(又称AOF重写),从而起到AOF文件压缩的目的;

3.3、回写策略

3.3.1、always

        同步写回,每个写命令执行完后,立刻同步地将日志写回磁盘。

3.3.2、everysec(默认)

        每秒写回,每个写命令执行完,只是先将日志写到AOF文件的内存缓冲区,每隔1s把缓冲区的内容写入磁盘;

3.3.3、no

        操作系统控制写回,每个写命令执行完,只是先把日志写到AOF文件的内存缓冲区,由操作系统决定何时将缓冲区内容写回磁盘;

3.4、AOF案例

3.4.1、拷贝redis.conf

cp redis6379_standAlone.conf redis6379_standAlone_aof.conf

3.4.2、修改配置(redis6379_standAlone_aof.conf)

修改内容:appendonly no ==> appendonly yes

3.4.5、重启redis服务(使用redis6379_standAlone_aof.conf)

./redis-server /myconf/redis/redis6379_standAlone_aof.conf

3.4.6、/aofFiles/aof 目录文件情况

3.4.7、客户端执行若干指令

3.4.8、模拟宕机

        flushdb,关闭redis服务,模拟机器宕机,删除 /redisPersistenceFiles/dump6379_standAlone.rdb 文件(防止干扰),然后再重新启动redis服务,观察数据是否恢复

3.4.9、结果

        数据没有恢复 !!!o(╥﹏╥)o 

        原因:执行flushdb指令时,该操作也会被记录在appenonly.aof文件中,所以当重新启动redis服务时,虽然将写命令重新执行了一遍,但是最后又执行了一次flushdb,所以重启之后数据还是空的

3.4.10、解决

        删除appendonly.aof中的flushdb指令,然后再重新启动redis服务即可恢复数据。 

3.4.11、appendonly.aof和dump.rdb文件的优先级

        思考:当前redis.conf文件中既配置了rdb方式的持久化,又配置了aof方式的持久化,那么当redis服务出现宕机需要进行数据恢复时,优先加载哪个配置文件?

        思路:编辑当前appendonly.aof文件,在末尾随便填写一些"乱七八糟"的数据,破坏该文件,然后重新启动redis服务,接着使用redis-cli客户端工具进行连接,观察能否连接上,如果能够连接的上,说明redis服务启动时,优先加载的是rdb文件,否则说明优先加载的是appendonly.aof文件。

步骤:

        (1)先执行shutdown指令,目的是为了生成dump.rdb文件;

        (2)接着"破坏"aof文件;

        (3)重启redis服务

        结果:连接被拒绝

        结论:redis服务宕机,进行数据恢复时,优先加载的文件是appendonly.aof文件

3.4.12、修复损坏的aof文件

        场景:当开启aof的持久化方式后,默认情况下,会每隔1s种记录一次写操作,极端情况下,在这1s钟会出现数据没有写完,即只写了一部分数据的情况,这种情况下,如何修复appendonly.aof文件?可以使用redis给我们提供的redis-check-aof指令进行修复。

 ./redis-check-aof --fix /redisPersistenceFiles/appendonly.aof

3.5、rewrite

3.5.1、概述

        AOF采用文件追加的方式,文件会越来越大,为了避免出现此种情况,新增加了重写机制,当AOF文件的大小超过了所设定的阈值时,redis就会对AOF文件的内容压缩,只保留可以恢复数据的最小指令集,指令为 bgrewriteaof。

3.5.2、原理

        当AOF文件持续增长而过大时,主进程会fork出一条子进程来将文件重写(也是先写临时文件,最后再rename),遍历新进程的内存中的数据,每条记录有一条set语句,重写aof文件的操作,并没有读取旧的aof文件,而是将整个内存中的数据库内容用命令的方式重写了一份新的aof文件,这点儿和快照有点类似。

3.5.3、触发机制   

        redis会记录上次重写时的aof文件大小,默认配置是当aof文件的大小是上次rewrite后大小的一倍,且文件大于64MB时触发。

3.6、aof的优点 & 缺点

优点:

        (1)每秒同步(appendfsync always):同步持久化,每次发生数据变更会被立即记录到磁盘,性能较差但是数据完整性比较好;

        (2)每修改同步(appendfsync everysec):默认。异步操作,每秒记录,如果1s内宕机,会丢失这1s中的数据;

        (3)不同步(appendfsync no):从不同步。操作系统控制写回,每个写命令执行完,只是先把日志写到AOF文件的内存缓冲区,由操作系统决定何时将缓冲区内容写回磁盘;

缺点:

        (1)对于相同数据集的数据而言,aof文件要远大于rdb文件,恢复速度慢于rdb;

        (2)aof运行效率要慢于rdb,每秒同步策略效率较好,不同步效率和rdb相同

3.7、aof总结 

四、如何选择 

4.1、分析

        RDB持久化方式:能够在指定的时间间隔内对你的数据进行快照存储;

        AOF持久化方式:记录每次对服务器的写操作,当服务器重启的时候会重新执行这些命令来恢复原始的数据,aof命令以redis协议追加每次的写操作至文件末尾,redis还能对AOF文件进行后台重写,使得AOF文件的大小不至于过大;

4.2、只做缓存

        如果你只希望你的数据在服务器运行的时候存在,你也可以不使用任何持久化方式;

4.3、同时开启rdb & aof

        在这种情况下,当redis服务重启的时候会优先加载aof文件来恢复原始数据,因为在通常情况下aof文件保存的数据集要比rdb文件保存的数据集更完整。rdb的数据不实时,同时使用两者时服务器也只会找aof文件。那要不要只使用aof文件呢?作者建议不要,因为rdb文件更适合于备份数据库(aof文件不断变化,不好备份),建议留着作为一个万一的手段。

4.4、性能建议

        因为rdb文件只用作后备用途,建议只在slave上持久化rdb文件,而且只要15分钟备份一次就够了,只保留save 900 1这条规则即可;

        如果开启了aof的持久化,好处是在恶劣情况下也只会丢失不会超过2s的数据,启动脚本比较简单,只加载自己的aof文件就可以了。代价是带来了持续的IO,二是aof rewrite过程中产生的新数据写到新文件造成的阻塞几乎是不可避免的,只要硬盘许可,应该尽量减少aof rewrite的频率,aof重写的基础大小默认为64MB太小了,可以设置到5GB以上。默认超过原大小100%时重写;

        如果没有开启aof的持久化,仅靠Master-Slave Replication实现高可用性也可以。能省掉一大笔IO,也减少了rewrite时带来的系统波动。代价是如果Master、Slave同时宕机,将会丢失十几分钟的数据,启动脚本也要比较Master/Slave中的rdb文件,加载最新的那个。新浪微博采用的就是这种架构;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值