Redis持久化

Redis持久化

1. 简介

【概述】

​ 1、掌握redis如何保证数据的稳定性

​ 2、深入理解持久化方案的原理以及各自优缺点

​ 3、掌握redis容灾备份的方案,进一步确保数据安全

【理论知识】

​ 1、持久化含义

​ 2、RDB持久化优缺点以及工作原理

​ 3、AOF持久化优缺点以及工作原理,AOF祖塞

​ 4、fork子进程的开销和优化

【实际操作】

​ 1、RDB相关参数配置以及触发命令

​ 2、AOF相关参数配置以及异常修复命令

​ 3、开启RDB-AOF混合持久化配置

2. Redis的持久化方式

通常数据库存在三种用于持久操作以防止数据掲坏的常见策略:

1.是数据库不关心故障,而是在数据文件损坏后从数据备份或快照中恢复。RD就是这种情况

2.该数据库使用操作日志记录毎个操作的操作行为,以在失败后通过日志恢复一致性。

由于操作日志是按顺序追加写入的,因此不会出现无法恢复操作日志的情况。类似于Msq的重做和撤消日志。

3.数据库不修改旧数据,而仅通过追加进行写入,因此数据本身就是日志,因此永远不会出现数据无法恢复的情况 COUCHDB是一个很好的例子。AOF类似这种情况

严格上讲Reds为持久化提供了三种方式

  • RDB: 在指定的时间间隔能对数据进行快照存储,类似于MSQ的dump备份文件。
  • AOF: 记录毎次对服务器写的操作,当服务器重启的时候会重新执行这些命令来恢复原始的数据(MSQ的binlρg)
  • RDB与AOF混合使用,这是 Redis4.0开始的新特性。在混合使用中AOF读取RD数据重建原始数据集,集二者优势为一体。

3. RDB持久化

3 . 1 . 初始化环境

3 . 1 . 1 . 创建配置/数据/日志目录
#创建配置目录
mkdir -p /usr/local/redis/conf
#创建数据目录
mkdir -p /usr/local/redis/data
#创建日志目录
mkdir -p /usr/local/redis/log
3 . 1 . 2 . 配置文件
vim /usr/local/redis/conf/redis.conf
#放行访问IP限制
bind 0.0.0.0
#后台启动
daemonize yes
#日志存储目录及日志文件名
logfile /usr/local/redis/log/redis.log
#rdb数据文件名
dbfilename dump.rdb
#rdb数据文件和aof数据郭件的存储目录
dir /usr/local/redis/data
#设置密码
requirepass 123456
3 . 1 . 3 . 准备数据

/usr/1ocal/ redis/bin目录下创建 initdata.py内容如下

python initdata.py | redis-cli -a 123456 --pipe
#!/usr/bin/env python
# -*- coding:utf-8-*-

class Token(object):
    def __init__(self, value):
        if isinstance(value, Token):
            value= value.value
        self.value = value

    def __repr__(self):
        return self.value

    def __str__(self):
    	return self.value

def b(x):
    return x

SYM_STAR = b('*')
SYM_DOLLAR = b('$')
SYM_CRLF = b('\r\n')
SYM_EMPTY = b ('')

class RedisProto(object):
    def __init__(self, encoding='utf-8', encoding_errors='strict'):
        self.encoding = encoding
        self.encoding_errors = encoding_errors

    def encode(self, value):
        if isinstance(value, Token):
            return b(value.value)
        elif isinstance(value,bytes):
            return value
        elif isinstance(value, int):
            value = b(str(value))
        elif not isinstance(value, str):
            value = str(value)
        if isinstance(value, str):
            value = value.encode(self.encoding, self.encoding_errors)
        return value

    def pack_command(self,*args):

        output = []
        command = args[0]
        if ' ' in command:
            args = tuple([Token(s) for s in command.split(' ')]) + args [1:]
        else:
            args = (Token(command),) + args[1:]

        buff = SYM_EMPTY.join(
            (SYM_STAR, b(str(len(args))), SYM_CRLF))

        for arg in map(self.encode, args):
            if len(buff) > 6000 or len(arg) > 6000:
                buff= SYM_EMPTY.join((buff, SYM_DOLLAR, b(str(len(arg))),SYM_CRLF))
                output.append(buff)
                output.append(arg)
                buff = SYM_CRLF
            else:
                buff = SYM_EMPTY.join((buff, SYM_DOLLAR, b(str(len(arg))), SYM_CRLF, str(arg), SYM_CRLF))

        output.append(buff)
        return output

if __name__ == '__main__':
    for i in range(5000):
        commands_args = [('SET','key_' + str(i), 'value_' + str(i))]
        commands = ''.join([RedisProto().pack_command(*args)[0] for args in commands_args])
        print commands

3 . 1 . 4 . 开启RBD

​ 我们可以配置 Redis在n秒内如果超过m个key被修改就自动做快照,下面是默认的快照保存配置 ( 这3个选项都屏蔽,则RDB禁用)

#900秒内如果超过1个key改动,则发起快照保存
save 900 1
#300秒内如果超过10个key改动,则发起快照保存
save 300 10
#60秒内如果超过1w个key改动,则发起快照保存
save 60 10000

3 . 2 . 什么叫redis快照

​ 快照,顾名思义可以理解为拍照一样,把整个内存数据映射到硬盘中,保存一份到硬盘,因此恢复数据起来比较快,把数据映射回去即可,不像AOF,一条条的执行操作命令。

​ 快照是默认的持久化方式。这种方式是就是将内存中数据以快照的方式写入到二进制文件中,默认的文件名为dump.rdb。可以通过配置设置自动做快照持久化的方式。

产生快照的情况有以下几种:

  • 手动 bgrave执行
  • 手动save执行
  • 根据配置文件自动执行
  • 客户端发送 shutdown、系统会先执行save命令阻塞客户端、然后关闭服务器
  • 当有主从架构时,从服务器向主服务器发送sync命令来执行复制操作时,主服务器会执行 bgsave操作
  • 执行flushall命令,也会产生dump.rdb文件,但里面是空的,无意义

3 . 3 . RDB工作原理

​ Redis默认会将快照文件存储在Redi当前进程的工作目录中的 dump. rdb文件中,可以通过配置dir和 dbfilename两个参数分另指定快照文件的存储路径和文件名。流程过程如下(rdb.c中)。

在这里插入图片描述

3 . 3 . 1 . 持久化原理-fork

​ Redis会单独创建(fork)一个子进程来进行持久化,会先将数据写入到 一个临时文件中,待持久化过程都结束了,再用这个临时文件替换上次持久化好的文件。

​ 整个过程中,主进程是不进行任何IO操作的,这就确保了极高的性能,如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感。

​ 那RDB方式要比AOF方式更加的高效。RDB的缺点是最后一次持久化后的数据可能丢失。

​ Fork的作用是复制一个与当前进程一样的进程。新进程的所有数据(变量、环境变量、程序计数器等),数值都和原进程一致,但是是一个全新的进程,并作为原进程的子进程。

3 . 4 . RBD的优点

  • 适合大规模的数据恢复

  • 对数据完整性和一致性要求不高

  • 紧凑压缩的二进制文件

  • fork子进程性能最大化

  • 启动效率高

3 . 5 . RDB的缺点

  • 生成快照的时机问题
  • fork子进程的开销问题
  • RDB的缺点是最后一次持久化后的数据可能丢失。
  • 在一定间隔时间做一次备份,所以如果redis意外down掉的话,就会丢失最后一次快照后的所有修改。
  • Fork的时候,内存中的数据被克隆了一份,大致2倍的膨胀性能需要考虑

4 . AOF持久化

​ 它也是 Redis持久化的重要手段之一,AoF( Append Only File)只追加文件,也就是每次处理完请求命令后都会将此命令追加到aof文件的末尾。而RDB是压缩成二进制等时机开子进程去干这件事。

4 . 1 . 开启AOF

通过配置进行启动,默认都是关闭的

#默认 appendonly 为no
appendonly yes
appendfilename "appendonly.aof"
#RDB文件和AOF文件所在目录
dir /usr /local/redis/data

4 . 2 . 同步策略

Redist中提供了3种AOF同步策略:

  • 每秒同步(默认,每秒调用一次fsnc,这种模式性能并不是很糟糕)
  • 每修改同步(会极大消弱 Redis 的性能,因为这种模式下每次write后都会调用 fsync)
  • 不主动同步(由操作系统自动调度刷磁盘,性能是最好的)
#每秒钟同步一次,该策略为A0F的默认策略
appendfsync everysec
#每次有数据修改发生时都会写入AOF文件
appendfsync always
#从不同步。高效但是数据不会主动被持久化
appendsync no

4 . 3 . AOF工作原理

在这里插入图片描述

​ AOF的频率高的话肯定会对Red带来性能影响,因为每次都是刷盘操作。跟mysq样了。 Redis每次都是先将命令放到缓冲区,然后根据具体策略(每秒/每条指令/缓冲区满)进行刷盘操作。如果配置的 always,那么就是典型阻塞,如果是 everysec每秒的话,那么会开一个同步线程去每秒进行刷盘操作,对主线程影响稍小。

4 . 4 . 写入文件与恢复

​ AoF文件是一个只进行 append操作的日志文件,因此在写入过程中即使出现宕机现象,也不会破坏日志文件中已经存在的内容。假如一次操作只是写入了一半数据就出现了系统崩溃问题,不用担心,在 Redis下一次启动之前,我们可以通过 fredischeck-aof工具来帮助我们修复问题。

​ AoF文件有序地保存了对数据库执行的所有写入操作,这些写入操作以Red协议的格式保存,因此AOF文件的内容非常容易被人读懂,对文件进行分析( parse)也很轻松。

​ 导出( export)AOF文件也非常简单:举个例子,如果你不小心执行了 FLUSHALL命令,但只要AOF文件未被重写,那么只要停止服务器,移除AQF文件末尾的 FLUSHALL命令,并重启Reds,就可以将数据集恢复到F∪SHAL执行之前的状态。

4 . 5 . 重写

​ Redis可以在AoF文件体积变得过大时,自动地在后台对AOF进行 rewrite。即 Redis以 append模式不断的将修改数据写入到老的磁盘文件中,同时 Redis还会创建一个新的文件用于记录此期间有哪些修改命令被执行。

​ 因为Red在创建新AOF文件的过程中,会继续将命令追加到现有的AOF文件里面,即使重写过程中发生停机,现有的AOF文件也不会丢失。

而一旦新AoF文件创建完毕,Redis i就会从旧AF文件切换到新AOF文件,并开始对新AOF文件进行追加操作。

4 . 5 . 1 . 重写流程

​ 在进行AOF 重写期间,也会fork一个子进程去进行,而主进程继续接收命令。子进程根据当前的内存快照,对原AOF文件进行扫描,并把新的结果写入一个新的AOF文件(与RDB一样,保证任意时刻文件的完整性)。最后用新的AOF文件替换旧的AOF文件。
注意:这里fork子进程,以及替换AOF文件时,Redis是阻塞的。

4 . 5 . 2. 为什么要重写

​ 比如我有业务很简单,就来回 delete set同一个key。就这个业务运行了10年,那么aof文件将记录无数个 delete k1,setk1 。其实都是重复的,但是我aof侮每次都追加,文件变成了大小。这时候Reds宕机了,要恢复,你想想1TB大小的ao文件去恢复,累死了。最主要的是1TB大小只记录了两个命令,所以压缩其实就是来处理这件事的。

4 . 5 . 3 . rewrite触发条件
  • 客户端执行 bgrewriteaof命令
  • 配置文件 auto-aof-rewrite-min-size 64mb 当aof文件大于64mb的时候进行一次重写
  • auto-aof-rewrite-percentage 100 百分比重写,当前文件大小是上次重写大小的两倍,则进行一次重写

4 . 6 . 常用配置

# fsync持久化策略
appendfsync everysec

#AOF重写期间是否禁止 fsync:如果开启该选项,可以减轻文件重写时CPU和硬盘的负载(尤其是硬盘),但是可能会丢失AOF重写期间的数据:需要在负载和安全性之间进行平衡
no-appendfsync-on-rewtite no

#当前aof文件大于多少字节后才触发重写
auto-aof-rewrite-min-size 64mb

#当前写入日志文件的大小超过上一次 rewrite之后的文件大小的百分之100时,也就是2倍时触发 
auto-aof-rewrite-percentage 100

#如果AOF文件结尾损坏, Redis启动时是否仍载入AOF文件
aof-load-truncated yes

4 . 7 . AOF优点

  • 数据不易丢失
  • 自动重写机制
  • 易懂易恢复

4 . 8 . AOF缺点

  • AOF文件恢复数据慢
  • AOF持久化效率低

5 . 如何选择RDB和AOF

5 . 1 . 同时开启

​ Redis先加载AOF文件来恢复原始数据,因为AOF数据比rdb更完整,但是aof存在潜在的bug,如把错误的操作记录写入了aof,会导出数据恢复失败,所以可以把RDB作为后备数据。

​ 为了考虑性能,可以只在Slave上开启RDB,并且15min备份一次 ,如果为了避免AOF rewite的IO以及阻塞,可以在Redis集群中不开启AOF,靠集群的备份机制来保证可用性,在启动时选取较新的RDB文件, 如果集群全部崩溃,会丢失15min前的数据。

5 . 2 . 混合模式

Redis4.0开始支持该模式(5.0 版本 默认开启)。

解决的问题 : Redis在重启时通常是加载AOF文件,但加载速度慢。因为RDB数据不完整,所以加载AOF。

开启方式 : aof-use-rdb-preamble yes

开启后,AOF在重写时会直接读取RDB中的内容。

运行过程:通过 bgrwriteaof完成,不同的是当开启混合持久化后

  • 子进程会把内存中的数据以RDB的方式写入aof中
  • 把AOF重写缓冲区中的增量命令以AOF方式写入到文件
  • 将含有RDB格式和AOF格式的AOF数据覆盖旧的AOF文件新的AOF文件中,一部分数据来自RDB文件,一部分来自 Redis运行过程时的增量数据

5 . 3 . 数据恢复

当我们开启了混合持久化时,启动 Redis依然优先加载aof文件,aof文件加载可能有两种情况如下

  • ao文件开头是rdb的格式,先加载rdb内容再加载剩余的aof
  • aof文件开头不是rdb的格式,直接以aof格式加载整个文件

优点:既能快速备份又能避免大量数据丟失

缺点:RDB是压缩格式,AOF在读取它时可读性较差

6 . 二者动态切换

在Reds2.2或以上版本,可以在不重启的情况下,从RDB切换到AoF

  • 为最新的 dump.rdb文件创建一个备份
  • 将备份放到一个安全的地方
cp dump.rdb dump.rdb.bak
  • 执行以下两条命令
#开启aof
redis-cli config set appendonly yes
#关闭rdb
redis-cli config set save ""
  • 确保写命令会被正确地追加到AOF文件的末尾
  • 执行的第一条命令开启了A0F功能: Redis会阻塞直到初始A0F文件创建完成为止,之后 Redis会继续处理命令请求,并开始将写入命令追加到AOF文件末尾

7 . Redis容灾备份

1 . 开启RDB持久化

save 900 1
save 300 10
save 60 10000

2 . 开启AOF配置

#开启aof
appendonly yes
appendfilename "appendony.aof"

#rewrite
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

# appendfsync always
appendfsync everysec
# appendfsync no

3 . RDB日志备份,编写脚本定时备份

  • vim一个redis-rdb-copy-per-hour.sh
#!bin/bash
cur_date=$(date "+%Y%m%d%H%M%S")

#先删除文件,在创建一个文件
rm -rf /usr/local/redis/snapshotting/$cur_date
mkdir -p /usr/local/redis/snapshotting/$cur_date

#将当前的rdb文件拷贝
cp /usr/local/redis/data/dump.rdb /usr/local/redis/snapshotting/$cur_date

#删除48小时前的rdb文件
del_date=$(date -d -48hour "+%Y%m%d%H%M")
rm -rf /usr/local/redis/snapshotting/$del_date
  • 使用 crontab定时器执行备份脚本
#打开 crontab
crontab -e
  • 然后写入(以下为每10秒执行一次,生成环境可以调整一下每小时执行一次)
*/1 * * * * sh /usr/local/redis/bin/redis-rdb-copy-per-hour.sh
*/1 * * * * sleep 10sh /usr/local/redis/bin/redis-rdb-copy-per-hour.sh
*/1 * * * * sleep 20sh /usr/local/redis/bin/redis-rdb-copy-per-hour.sh
*/1 * * * * sleep 30sh /usr/local/redis/bin/redis-rdb-copy-per-hour.sh
*/1 * * * * sleep 40sh /usr/local/redis/bin/redis-rdb-copy-per-hour.sh
*/1 * * * * sleep 50sh /usr/local/redis/bin/redis-rdb-copy-per-hour.sh

8 . 优化方案

8.1.独立部署,硬盘优化

8.2.缓存禁用持久化

8.3.主从模式,从持久化

8.4.优化fork处理

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值