1 Redis持久化
1.1 Redis持久化分类
Redis 中的数据都是保存在内存中的,当Redis服务重启后,内存中的数据都会丢失,所以需要将内存中的数据保存到磁盘上,方便系统故障时,从磁盘上的备份数据恢复到内存中。
Redis 中的持久化方式有两种,RDB全量持久化和AOF增量持久化。在4.0及以后版本中,提供了一种混合持久化的功能,就是RDB和AOF结合的持久化模式。
分类如下:
- RDB
RDB持久化方式是通过快照完成的。RDB程序将当前内存中的数据快照保存到磁盘中,在Redis重启时,RDB程序可以通过载入RDB文件来还原数据库的状态。
- AOF
AOF(append only file),是以独立日志的方式记录每次的写命令,重启时在执行文件中的命令来达到恢复数据的目的。
- 混合模式
混合模式就是同时结合了RDB持久化和AOF持久化混合写入AOF文件。这样就可以结合2者的优点了,快速的加载持久化文件,同时避免数据丢失过多。
1.2 RDB 持久化
1.2.1 RDB概念介绍
RDB(Redis DataBase)是将某一个时刻的内存快照(Snapshot),以二进制的方式写入磁盘的过程。
触发方式
触发rdb持久化的方式有2种,分别是手动触发和自动触发。
(1)手动触发
手动触发分别对应save和bgsave命令:
- save命令:阻塞当前Redis服务器,直到RDB过程完成为止,对于内存比较大的实例会造成长时间阻塞,线上环境不建议使用;
- bgsave命令:Redis进程执行fork操作创建子进程,RDB持久化过程由子 进程负责,完成后自动结束。阻塞只发生在fork阶段,一般时间很短(推荐);
bgsave流程图如下所示:
具体流程如下:
- redis客户端执行 bgsave 命令或者自动触发 bgsave 命令;
- 主进程判断当前是否已经存在正在执行的子进程,如果存在,那么主进程直接返回;
- 如果不存在正在执行的子进程,那么就fork一个新的子进程进行持久化数据,fork过程是阻塞的,fork操作完成后主进程即可执行其他操作;
- 子进程先将数据写入到临时的rdb文件中,待快照数据写入完成后再原子替换旧的rdb文件;
- 同时发送信号给主进程,通知主进程rdb持久化完成,主进程更新相关的统计信息(info Persitence下的rdb_*相关选项)。
(2)自动触发
在以下4种情况时会自动触发:
- redis.conf中配置save m n,即在m秒内有n次修改时,自动触发bgsave生成rdb文件;
- 主从复制时,从节点要从主节点进行全量复制时也会触发bgsave操作,生成当时的快照发送到从节点;
- 执行debug reload命令重新加载redis时也会触发bgsave操作;
- 默认情况下执行shutdown命令时,如果没有开启aof持久化,那么也会触发bgsave操作
1.2.2 配置说明
快照周期:内存快照虽然可以通过技术人员手动执行SAVE或BGSAVE命令来进行,但生产环境下多数情况都会设置其周期性执行条件。
代码语言:javascript复制#周期性执行条件的设置格式为
save <seconds> <changes>
#默认的设置为:
save 900 1 # 如果900秒内有1条Key信息发生变化,则进行快照;
save 300 10 # 如果300秒内有10条Key信息发生变化,则进行快照;
save 60 10000 # 如果60秒内有10000条Key信息发生变化,则进行快照。读者可以按照这个规则,根据自己的实际请求压力进行设置调整。
#以下设置方式为关闭RDB快照功能
save ""
其它相关配置
代码语言:javascript复制# RDB持久化数据库文件名,默认dump.rdb
dbfilename dump.rdb
# 数据文件存放目录,rdb快照文件和aof文件都会存放至该目录,请确保有写权限
dir /home/work/app/redis/data/
# yes:代表当使用bgsave命令持久化出错时候停止写RDB快照文件,no:表明忽略错误继续写文件。
stop-writes-on-bgsave-error yes
# 是否开启RDB文件压缩,yes默认开启压缩,no不开启
rdbcompression yes
# 在写入文件和读取文件时是否开启rdb文件检查,检查是否有无损坏,如果在启动是检查发现损坏,则停止启动
rdbchecksum yes
配置查询
代码语言:javascript复制127.0.0.1:6379> config get dbfilename # 想要获取 RDB 文件的存储名称设置
127.0.0.1:6379> config get dir # 查询 RDB 的文件目录
1.2.3 RDB优缺点
优点
- RDB 的内容为二进制的数据,占用内存更小,更紧凑,更适合做为备份文件;
- RDB 对灾难恢复非常有用,它是一个紧凑的文件,可以更快的传输到远程服务器进行 Redis 服务恢复;
- RDB 可以更大程度的提高 Redis 的运行速度,因为每次持久化时 Redis 主进程都会 fork() 一个子进程,进行数据持久化到磁盘,Redis 主进程并不会执行磁盘 I/O 等操作;
- 与 AOF 格式的文件相比,RDB 文件可以更快的重启。
缺点
- 因为 RDB 只能保存某个时间间隔的数据,如果中途 Redis 服务被意外终止了,则会丢失一段时间内的 Redis 数据;
- RDB 需要经常 fork() 才能使用子进程将其持久化在磁盘上。如果数据集很大,fork() 可能很耗时,并且如果数据集很大且 CPU 性能不佳,则可能导致 Redis 停止为客户端服务几毫秒甚至一秒钟。
1.3 AOF 持久化
1.3.1 介绍
AOF(Append-Only File)记录Redis中每次的写命令,类似mysql中的binlog,服务重启时会重新执行AOF中的命令将数据恢复到内存中,RDB(按策略持久化)持久化方式记录的粒度不如AOF(记录每条写命令),因此很多生产环境都是开启AOF持久化。
AOF日志记录Redis的每个写命令,步骤分为:命令追加(append)、文件写入(write)和文件同步(sync)。
- 命令追加,当AOF持久化功能打开了,服务器在执行完一个写命令之后,会以协议格式将被执行的写命令追加到服务器的 aof_buf 缓冲区。
- 文件写入和同步,关于何时将 aof_buf 缓冲区的内容写入AOF文件中,Redis提供了三种写回策略:always、everysec、no
触发持久化
AOF 的触发条件分为两种:自动触发和手动触发。
(1)手动触发
在客户端执行 bgrewriteaof 命令就可以手动触发 AOF 持久化,如下图所示:
可以看出执行完 bgrewriteaof 命令之后,AOF 持久化就会被触发。
(2)自动触发
有两种情况可以自动触发 AOF 持久化,分为是:满足 AOF 设置的策略触发 和 满足 AOF 重写触发。其中,AOF 重写触发会在本文的后半部分详细介绍,这里重点来说 AOF 持久化策略,配置 Redis 多久才将数据 fsync(同步)到磁盘一次。
AOF 持久化策略,分为以下三种:
- always:每条 Redis 操作命令都会写入磁盘,最多丢失一条数据;
- everysec:每秒钟写入一次磁盘,最多丢失一秒的数据;
- no:不设置写入磁盘的规则,根据当前操作系统来决定何时写入磁盘,Linux 默认 30s 写入一次数据至磁盘。
推荐(并且也是默认)的措施为每秒 fsync 一次, 这种 fsync 策略可以兼顾速度和安全性。
注:因为每次写入磁盘都会对 Redis 的性能造成一定的影响,所以要根据用户的实际情况设置相应的策略,一般设置每秒写入一次磁盘的频率就可以满足大部分的使用场景了。
1.3.2 配置
代码语言:javascript复制# appendonly参数开启AOF持久化
appendonly yes
# AOF文件名
appendfilename "appendonly.aof"
# AOF文件的保存位置和RDB文件的位置相同,都是通过dir参数设置的
dir ./
# AOF同步策略,一般都是选择第一种[always:每个命令都记录],[everysec:每秒记录一次],[no:看机器的心情高兴了就记录]
appendfsync always
#appendfsync everysec
# appendfsync no
# 配置重写触发机制
# aof文件大小比起上次重写时的大小,增长100%(配置可以大于100%)时,触发重写。[假如上次重写后大小为10MB,当AOF文件达到20MB时也会再次触发重写,以此类推]
auto-aof-rewrite-percentage 100
# aof文件大小超过64MB时,触发重写
auto-aof-rewrite-min-size 64mb
1.3.3 深入理解AOF重写
AOF持久化机制记录每个写命令,当服务重启的时候会复现AOF文件中的所有命令,会消耗太多的资源且重启很慢。因此为了避免AOF文件中的写命令太多文件太大,Redis引入了AOF的重写机制来压缩AOF文件体积。AOF文件重写是把Redis进程内的数据转化为写命令同步到新AOF文件的过程。
把过期的,没有用的,重复的,可优化的命令简化为很小的aof文件。实际上是redis内存中的数据回溯成aof文件。
重写流程:
- bgrewriteaof 触发重写,判断是否当前有 bgsave 或 bgrewriteaof 在运行,如果有,则等待该命令结束后再继续执行。
- 主进程fork出子进程执行重写操作,保证主进程不会阻塞。
- 子进程遍历redis内存中数据到临时文件,客户端的写请求同时写入 aof_buf 缓冲区和 aof_rewrite_buf 重写缓冲区 保证原AOF文件完整以及新AOF文件生成期间的新的数据修改动作不会丢失。
- 子进程写完新的AOF文件后,向主进程发信号,父进程更新统计信息。主进程把aof_rewrite_buf中的数据写入到新的AOF文件。
- 使用新的AOF文件覆盖旧的AOF文件,完成AOF重写。
1.4 RDB和AOF混合方式(4.0版本)
Redis 4.0 中提出了一个混合使用 AOF 日志和内存快照的方法。简单来说,内存快照以一定的频率执行,在两次快照之间,使用 AOF 日志记录这期间的所有命令操作。
原理:混合持久化同样也是通过 bgrewriteaof 重写命令完成的,不同的是当开启混合持久化时,fork出的子进程先将共享的内存副本全量的以RDB方式写入aof文件,然后在将重写缓冲区的增量命令以AOF方式写入到文件,写入完成后通知主进程更新统计信息,并将新的含有RDB格式和AOF格式的AOF文件替换旧的的AOF文件。
简单的说:新的AOF文件前半段是RDB格式的全量数据后半段是AOF格式的增量数据。如图所示:
配置
代码语言:javascript复制#我们可以在appendonly yes命令 下面加上以下的配置,然后重启Reids
aof-use-rdb-preamble yes
2 数据恢复实战操作
本次实验redis版本由3.2.12升级到4.0.0,并开启混合持久化,迁移RDB数据,验证数据是否正常。
2.1 AOF和RDB的恢复顺序
当Redis服务重启时数据恢复的顺序如下:
- 判断是否开启AOF持久化,若开启了AOF,则使用AOF持久化文件恢复数据,否则使用RDB持久化文件恢复数据;
- 若AOF文件不存在则从RDB文件恢复【其实并没有】;若AOF文件存在则使用AOF文件恢复;
- 若AOF文件和RDB文件都不存在则直接启动Redis;
- 若AOF或RDB文件出现错误,则启动失败返回错误信息;
2.2 恢复流程
流程较为复杂,需要严格按照以下步骤:
- 修改配置文件方式关闭aof备份功能,但要开启rdb备份功能;
- 一定要开启热修改配置功能,这步很重要,所以单独列一条来写;
- 把备份的rdb文件拷贝过去,同时重启redis;
- 通过命令config set appendonly yes开启aof备份功能,执行命令后就会自动产生appendonly.aof这个文件,此时rdb和aof文件数据同步了;
- 然后关闭redis,修改配置文件开启aof备份功能;
- 然后开启redis,此时才叫数据恢复成功。
2.3 安装3.2.12并备份数据
代码语言:javascript复制# wget http://download.redis.io/releases/redis-3.2.12.tar.gz
# wget http://download.redis.io/releases/redis-4.0.0.tar.gz
tar -zxvf redis-3.2.12.tar.gz -C /data/
mv /data/redis-3.2.12 /data/redis
mkdir /data/redis/data
yum install -y gcc gcc-c make tcl-devel
cd /data/redis && make && # make负责编译,make install负责将二进制文件安装到/usr/local/bin
cd /data/redis/src && make install && make test # 测试确保编译无误
cp /data/redis/redis.conf /data/redis/redis.conf.bak
代码语言:javascript复制# redis-3.2.12.conf
supervised systemd
dir /data/redis/data
daemonize yes
pidfile /data/redis/redis.pid
port 6379
bind 0.0.0.0
requirepass w4RedisService
loglevel warning
maxclients 65535
tcp-backlog 10240
appendonly no
save 900 1
save 300 10
save 60 10000
maxmemory 50499420160
代码语言:javascript复制# /etc/systemd/system/redis.service
[Unit]
Description=Redis Single Service
After=network.target
[Service]
Type=notify
User=root
Group=root
TimeoutStartSec=120s
ExecStart=/data/redis/src/redis-server /data/redis/redis.conf
ExecStop=/data/redis/src/redis-cli shutdown -a w4RedisService
Restart=on-failure
RestartSec=30s
LimitNOFILE=100000
LimitNPROC=65535
[Install]
WantedBy=multi-user.target
插入数据
代码语言:javascript复制[root@localhost redis]# redis-cli -a w4RedisService
127.0.0.1:6379>set company1 huanle1
127.0.0.1:6379>set company2 huanle2
127.0.0.1:6379>set company3 huanle3
127.0.0.1:6379>bgsave
127.0.0.1:6379>exit
#重启服务
[root@localhost redis]#systemctl restart redis
2.4 升级4.0.0并恢复数据
代码语言:javascript复制tar -zxvf redis-4.0.0.tar.gz
cd redis-4.0.0
make
cd src && make install
make test
代码语言:javascript复制# # redis-4.0.0.conf
# 先不要开启aof相关配置,否则数据无法同步
supervised systemd
daemonize no
dir /data/redis/data
#pidfile /data/redis/redis.pid
port 6379
bind 0.0.0.0
requirepass w4RedisService
loglevel warning
maxclients 65535
tcp-backlog 10240
save 900 1
save 300 10
save 60 10000
maxmemory 50499420160
appendonly yes
aof-use-rdb-preamble yes
代码语言:javascript复制#重命名旧的目录和新版本目录
mv redis redis.bak
mv redis-4.0.0 redis
cd /data/redis/data
cp dump.rdb-bak dump.rdb
systemctl start redis
代码语言:javascript复制# 查看RDB数据是否已经恢复,命令行设置开启aof备份功能,执行命令后就会自动产生appendonly.aof这个文件,完成rdb和aof数据同步
[root@localhost redis]# redis-cli -a w4RedisService
127.0.0.1:6379> keys *
1) "company1"
2) "company2"
3) "company3"
127.0.0.1:6379> config set appendonly yes
127.0.0.1:6379> exit
# 接着关闭redis,配置文件中设置永久开启AOF持久化
[root@localhost redis]# systemctl stop redis
[root@localhost redis]# cat redis.conf
appendonly yes
[root@localhost redis]# systemctl start redis
代码语言:javascript复制# 配置混合持久化功能
[root@localhost redis]# redis-cli -a w4RedisService
127.0.0.1:6379> config set aof-use-rdb-preamble yes # 开启RDB AOF混合持久化功能
OK
127.0.0.1:6379> bgrewriteaof # 手动触发AOF重写
Background append only file rewriting started
127.0.0.1:6379> set name hanjianjuan
OK
127.0.0.1:6379> quit
# 接着关闭reids,配置文件中设置永久开启混合持久化
[root@localhost redis]# systemctl stop redis
[root@localhost redis]# cat redis.conf
aof-use-rdb-preamble yes
[root@localhost redis]# systemctl start redis
结论:aof文件再经过bgrewriteaof之后,再次执行的命令会按照aof的方式进行存储,等下次再bgrewriteaof之后,再进行二进制存储。redis后台再进行bgrewriteaof的时候,这时候如果有客户端命令进来,会再后面进行追加。
参考链接
redis详解之数据备份与恢复_redis备份和恢复_programmer_山风的博客-CSDN博客
Redis数据库备份、迁移、恢复实践_数据库_半隐退状态-华为云开发者联盟
Redis 数据备份和恢复_redis如何恢复数据_咸蛋黄派的博客-CSDN博客
Redis基本概念 - 简书
Redis-基本概念_redis定义_SeaDhdhdhdhdh的博客-CSDN博客
一文搞懂 Redis 架构演化之路
Redis设计与实现
redis架构_剑八-的博客-CSDN博客
Redis高可用方案—主从(masterslave)架构
Redis高可用架构—哨兵(sentinel)机制详细介绍
Redis高可用架构—Redis集群(Redis Cluster)详细介绍
Redis基本概念知识_redis 基本概念_Gatsby_codeLife的博客-CSDN博客
03 Redis 网络IO模型简介_redis的io模型_天秤座的架构师的博客-CSDN博客
Redis 详解_王叮咚的博客-CSDN博客