你的位置:首页 > 信息动态 > 新闻中心
信息动态
联系我们

Redis持久化及备份

2021-11-21 16:31:31

Redis持久化概述

Redis是内存数据库,数据都是存储在内存中,为了避免进程退出导致数据的永久丢失,需要定期将Redis中的数据以某种形式(数据或命令)从内存保存到硬盘。 当下次Redis重启时,利用持久化文件实现数据恢复。除此之外,为了进行灾难备份,可以将持久化文件拷贝到一个远程位置。Redis持久化分为RDB持久化和AOF持久化,前者将当前数据保存到硬盘,后者则是将每次执行的写命令保存到硬盘。

RDB

RDB是一种快照存储持久化方式,具体就是将Redis某一时刻的内存数据保存到硬盘的文件当中,默认保存的文件名为dump.rdb,而在Redis服务器启动时,会重新加载dump.rdb文件的数据到内存当中恢复数据。 ,触发 RDB 持久化过程分为手动触发和自动触发。

手动触发

save 命令:阻塞当前 Redis 服务器,直到 RDB 过程完成为止,对于内存比较大的实例会造成长时间阻塞,线上环境不建议使用。
bgsave 命令:Redis 进程执行 fork 操作创建子进程,RDB 持久化过程由子进程负责,完成后自动结束。阻塞只发生在 fork 阶段,一般时间很短。

save

127.0.0.1:6379> keys *
(empty array)
127.0.0.1:6379> set k1 1  
OK
127.0.0.1:6379> set k2 2
OK
127.0.0.1:6379> save   #启动redis持久化 rdb
OK
127.0.0.1:6379> keys *
1) "k2"
2) "k1"
127.0.0.1:6379> flushdb  #情况key
OK
127.0.0.1:6379> keys *
(empty array)

在另一个窗口pkill redis,然后重新启动redis

[root@iZwz96awf0ghl7tyldox1wZ ~]# redis-cli
127.0.0.1:6379> auth root
OK
127.0.0.1:6379> keys *
1) "k1"
2) "k2"
127.0.0.1:6379> 

bgsave

127.0.0.1:6379> set k1 1
OK
127.0.0.1:6379> set k2 2
OK
127.0.0.1:6379> keys *
1) "k2"
2) "k1"
127.0.0.1:6379> bgsave
Background saving started
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> keys *
(empty array)

在另一个窗口pkill redis,然后重新启动redis

[root@iZwz96awf0ghl7tyldox1wZ ~]# redis-cli
127.0.0.1:6379> auth root
OK
127.0.0.1:6379> keys *
1) "k1"
2) "k2"
127.0.0.1:6379> 

bgsave流程

加粗样式1)执行 bgsave 命令,Redis 父进程判断当前是否存在正在执行的子进程,如 RDB/AOF 子进程,如果存在 bgsave 命令直接返回。主要是基于性能方面的考虑:两个并发的子进程同时执行大量的磁盘写操作,可能引起严重的性能问题。

2)父进程执行 fork 操作创建子进程,fork 操作过程中父进程会阻塞,通过 info stats 命令查看 latest_fork_usec 选项,可以获取最近一个
fork 操作的耗时,单位为微秒

3)父进程 fork 完成后,bgsave 命令返回“Background saving started”信息并不再阻塞父进程,可以继续响应其他命令

4)子进程创建 RDB 文件,根据父进程内存生成临时快照文件,完成后对原有文件进行原子替换。执行 lastsave 命令可以获取最后一次生成 RDB 的时间,对应 info 统计的 rdb_last_save_time 选项。

5)进程发送信号给父进程表示完成,父进程更新统计信息,

自动触发

在Redis配置文件中的save指定到达触发RDB持久化的条件,比如【多少秒内至少达到多少写操作】就开启RDB。

# 900s内至少达到一条写命令
save 900 1
# 300s内至少达至10条写命令
save 300 10
# 60s内至少达到10000条写命令
save 60 10000

通过服务器配置文件触发RDB的方式,与bgsave命令类似,达到触发条件时,会forks一个子进程进行数据同步

RDB文件处理

保存

RDB 文件保存在 dir 配置指定的目录下,文件名通过 dbfilename 配置指定。可以通过执行 config set dir{newDir}和 config set
dbfilename{newFileName}运行期动态执行,当下次运行时 RDB 文件会保存到新目录。

当遇到坏盘或磁盘写满等情况时,可以通过 config set dir{newDir}在线修改文件路径到可用的磁盘路径,之后执行 bgsave 进行磁盘切换。

压缩

Redis 默认采用 LZF 算法对生成的 RDB 文件做压缩处理,压缩后的文件远远小于内存大小,默认开启,可以通过参数 config set
rdbcompression{yes|no}动态修改。

虽然压缩 RDB 会消耗 CPU,但可大幅降低文件的体积,方便保存到硬盘或通过网络发送给从节点,因此线上建议开启。

RDB优缺点

优点

1.RDB 是一个非常紧凑的文件,它保存了 Redis 在某个时间点上的数据集。 这种文件非常适合用于进行备份: 比如说,你可以在最近的 24 小
时内,每小时备份一次 RDB 文件,并且在每个月的每一天,也备份一个 RDB 文件。 这样的话,即使遇上问题,也可以随时将数据集还原到不同的版本。
2.RDB 可以最大化 Redis 的性能:父进程在保存 RDB 文件时唯一要做的就是 fork 出一个子进程,然后这个子进程就会处理接下来的所有保存工
作,父进程无须执行任何磁盘 I/O 操作。
3.RDB 在恢复大数据集时的速度比 AOF 的恢复速度要快。

缺点

1.RDB 方式数据没办法做到实时持久化/秒级持久化

如果服务器宕机的话,采用RDB的方式会造成某个时段内数据的丢失,比如我们设置10分钟同步一次或5分钟达到1000次写入就同步一次,那么如果还没达到触发条件服务器就死机了,那么这个时间段的数据会丢失。

2.使用bgsave命令在forks子进程时,如果数据量太大,forks的过程也会发生阻塞,另外,forks子进程会耗费内存。
针对 RDB 不适合实时持久化的问题,Redis 提供了 AOF 持久化方式来解决。

AOF

AOF(append only file)持久化:与RDB存储某个时刻的快照不同,AOF持久化方式会记录客户端对服务器的每一次写操作命令到日志当中,并将这些写操作以Redis协议追加保存到以后缀为aof文件末尾。

配置
appendonly yes #启用aof持久化方式
appendfsync always #每次收到写命令就立即强制写入磁盘,最慢的大概只有几百的TPS,但是保证完全的持久化,不推荐使用
appendfsync everysec #每秒钟强制写入磁盘一次,在性能和持久化方面做了很好的折中,推荐
appendfsync no #完全依赖os,性能最好,持久化没保证,Redis不会主动调用fsync去将AOF日志内容同步到磁盘,所以这一切就完全依赖于操作系统的
调试了。对大多数Linux操作系统,是每30秒进行一次fsync,将缓冲区中的数据写到磁盘上
aof-load-truncated yes:如果AOF文件结尾损坏,Redis启动时是否仍载入AOF文件

AOF 文件名通过 appendfilename 配置设置,默认文件名是 appendonly.aof。保存路径同RDB 持久化方式一致,通过 dir 配置指定

工作流程

在这里插入图片描述
1)所有的写入命令会追加到 aof_buf(缓冲区)中。
2)AOF 缓冲区根据对应的策略向硬盘做同步操作。
3)随着 AOF 文件越来越大,需要定期对 AOF 文件进行重写,达到压缩的目的。
4)当 Redis 服务器重启时,可以加载 AOF 文件进行数据恢复。

重写机制

AOF将客户端的每一个写操作都追加到aof文件末尾,随着命令不断写入 AOF,文件会越来越大,为了解决这个问题,Redis 引入 AOF 重写机制压缩文件体积。
AOF 文件重写是把 Redis 进程内的数据转化为写命令同步到新 AOF 文件的过程。AOF 重写降低了文件占用空间,除此之外,另一个目的是:更小的 AOF 文件可以更快地被 Redis 加载。

触发方式

手动触发

 bgrewriteaof

自动触发

auto-aof-rewrite-min-size:表示运行 AOF 重写时文件最小体积,默认为 64MB。
auto-aof-rewrite-percentage:代表当前 AOF 文件空间(aof_current_size)和上一次重写后 AOF 文件空间(aof_base_size)的比值。

例如:

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

默认配置是当AOF文件大小是上次rewrite后大小的一倍且文件大于64M时触发

重写流程

在这里插入图片描述
1)执行 AOF 重写请求。 如果当前进程正在执行 AOF 重写,请求不执行并返回如下响应: ERR Background append only file rewriting already in progress

2)父进程执行 fork 创建子进程,开销等同于 bgsave 过程。

3.1)主进程 fork 操作完成后,继续响应其他命令。所有修改命令依然写入 AOF 缓冲区并根据 appendfsync 策略同步到硬盘,保证原有 AOF 机制正确性。

3.2)由于 fork 操作运用写时复制技术,子进程只能共享 fork 操作时的内存数据。由于父进程依然响应命令,Redis 使用“AOF 重写缓冲区”保存这部分新数据,防止新 AOF 文件生成期间丢失这部分数据。

4)子进程根据内存快照,按照命令合并规则写入到新的 AOF 文件。每次批量写入硬盘数据量由配置 aof-rewrite-incremental-fsync 控制,默认为 32MB,防止单次刷盘数据过多造成硬盘阻塞。

4.1)新 AOF 文件写入完成后,子进程发送信号给父进程,父进程更新统计信息,具体见 info persistence 下的 aof_*相关统计。

4.2)父进程把 AOF 重写缓冲区的数据写入到新的 AOF 文件。

4.3)使用新 AOF 文件替换老文件,完成 AOF 重写。

AOF文件损坏

在写入aof日志文件时,如果Redis服务器宕机,则aof日志文件文件会出格式错误,在重启Redis服务器时,Redis服务器会拒绝载入这个aof文件,可以通过命令修复aof并恢复数据

redis-check-aof -fix file.aof
AOF优缺点

优点

1.AOF可以设置 完全不同步、每秒同步、每次操作同,默认是每秒同步。因为AOF是操作指令的追加,所以可以频繁的大量的同步。

2.AOF文件是一个值追加日志的文件,即使服务宕机为写入完整的命令,也可以通过redis-check-aof工具修复这些问题。

3.如果AOF文件过大,Redis会在后台自动地重写AOF文件。重写后会使AOF文件压缩到最小所需的指令集。

4.AOF文件是有序保存数据库的所有写入操作,易读,易分析。即使如果不小心误操作数据库,也很容易找出错误指令,恢复到某个数据节点。例如不小心FLUSHALL,可以非常容易恢复到执行命令之前。

缺点

1、相同数据量下,AOF的文件通常体积会比RDB大。因为AOF是存指令的,而RDB是所有指令的结果快照。但AOF在日志重写后会压缩一些空间。

2、在大量写入和载入的时候,AOF的效率会比RDB低。因为大量写入,AOF会执行更多的保存命令,载入的时候也需要大量的重执行命令来得到最后的结果。RDB对此更有优势。

持久化

持久化配置方案

1、企业级的持久化的配置策略
save 60 10000:如果你希望尽可能确保说,RDB最多丢1分钟的数据,那么尽量就是每隔1分钟都生成一个快照,低峰期,数据量很少,也没必要10000->生成RDB,1000->RDB,这个根据你自己的应用和业务的数据量,你自己去决定
AOF一定要打开,fsync,everysec
auto-aof-rewrite-percentage 100: 就是当前AOF大小膨胀到超过上次100%,上次的两倍
auto-aof-rewrite-min-size 64mb: 根据你的数据量来定,16mb,32mb
2、数据备份方案
RDB非常适合做冷备,每次生成之后,就不会再有修改了
数据备份方案
(1)写crontab定时调度脚本去做数据备份
(2)每小时都copy一份rdb的备份,到一个目录中去,仅仅保留最近48小时的备份
(3)每天都保留一份当日的rdb的备份,到一个目录中去,仅仅保留最近1个月的备份
(4)每次copy备份的时候,都把太旧的备份给删了
(5)每天晚上将当前服务器上所有的数据备份,发送一份到远程的云服务上去【crontab】

备份

info persistence

# Persistence
loading:0
# 离最近一次成功生成rdb文件,写入命令的个数,即有多少个写入命令没有持久化
rdb_changes_since_last_save:0
# 服务器是否正在创建rdb文件
rdb_bgsave_in_progress:0
# 离最近一次成功创建rdb文件的时间戳。当前时间戳 - rdb_last_save_time=多少秒未成功生成rdb文件
rdb_last_save_time:1635707415
# 最近一次rdb持久化是否成功
rdb_last_bgsave_status:ok
rdb_last_bgsave_time_sec:-1
rdb_current_bgsave_time_sec:-1
rdb_last_cow_size:0
# 是否开启了aof
aof_enabled:1
# 标识aof的rewrite操作是否在进行中
aof_rewrite_in_progress:0
# rewrite任务计划,当客户端发送bgrewriteaof指令,如果当前rewrite子进程正在执行,那么将客户端请求的bgrewriteaof变为计划任务,待aof子进程结束后
执行rewrite
aof_rewrite_scheduled:0
aof_last_rewrite_time_sec:-1
aof_current_rewrite_time_sec:-1
# 上次aof写入状态
aof_last_bgrewrite_status:ok
# 上次bgrewriteaof操作的状态
aof_last_write_status:ok
aof_last_cow_size:0
module_fork_in_progress:0
module_fork_last_cow_size:0
aof_current_size:0
aof_base_size:0
aof_pending_rewrite:0
aof_buffer_length:0
aof_rewrite_buffer_length:0
aof_pending_bio_fsync:0
aof_delayed_fsync:0
类型地址
主机192.168.34.170
备份机192.168.34.165

0.准备工作

awk
在这里插入图片描述
ssh&&scp

ssh 登录其他服务器
在这里插入图片描述
scp 推送文件到指定服务器
在这里插入图片描述
可以看出这个每次都要输入密码有些麻烦,所以我们可以做个免密登录。
1.生成公钥 ssh-keygen -t rsa 带 :的地方直接回车即可。
在这里插入图片描述

在这里插入图片描述
authorized_keys:存放远程免密登录的公钥,主要通过这个文件记录多台机器的公钥
id_rsa : 生成的私钥文件
id_rsa.pub : 生成的公钥文件

2.将本机的公钥复制到远程机器的authorized_keys文件中

 ssh-copy-id

在这里插入图片描述
通过scp将内容写到对方的文件中
在这里插入图片描述
测试
在这里插入图片描述
准备工作已经介绍完了,现在开始实现。

1.开始备份

#!/bin/bash
msg=`redis-cli bgsave`
result=`redis-cli info Persistence |grep rdb_bgsave_in_progress |awk 'BEGIN{FS=":"}{print $2}'`
while [ $result == 1 ]
do
	sleep 1
	result=`redis-cli info Persistence |grep rdb_bgsave_in_progress |awk 'BEGIN{FS=":"}{print $2}'`
done
dateDir=`date +%Y%m%d%H`
dateFile=`date +%M`
scpData=/data/redis/data/rdb/$dateDir
ssh root@192.168.34.165 "mkdir -p ${scpData}"
scp -p /home/redis-6.0.6/dump.rdb root@192.168.34.165:$scpData

在这里插入图片描述
在这里插入图片描述
aof文件跟rdb文件备份差不多。

如果想每天备份或每小时备份一次,可以用linux的定时任务crontab;