Redis持久化
1 持久化的作用
1.1 什么是持久化
Redis 是一款基于内存的非关系型数据库,它会将数据全部存储在内存中。但是如果 Redis 服务器出现某些意外情况,比如宕机或者断电等,那么内存中的数据就会全部丢失。因此必须有一种机制能够保证 Redis 储存的数据不会因故障而丢失,这就是 Redis 的数据持久化机制。
数据的持久化存储是 Redis 的重要特性之一,它能够将内存中的数据保存到本地磁盘中,实现对数据的持久存储。这样即使在服务器发生故障之后,也能通过本地磁盘对数据进行恢复。
1.2 持久化的实现方式
Redis 提供了两种持久化机制:第一种是 RDB,又称快照(snapshot)模式,第二种是 AOF 日志,也就追加模式。
快照:某时某刻数据的一个完整备份,要触发某个条件才完成备份,可能会丢数据,适合做缓存
-mysql的Dump
-redis的RDB
写日志:任何操作记录日志,要恢复数据,只要把日志重新走一遍即可,数据完整性更高,适合重要数据的保存
-mysql的 Binlog
-Redis的 AOF
2 Redis RDB持久化
2.1 什么是RDB
2.2 RDB快照模式原理
RDB 即快照模式,它是 Redis 默认的数据持久化方式,它会将数据库的快照保存在 dump.rdb 这个二进制文件中。所谓“快照”就是将内存数据以二进制文件的形式保存起来。
我们知道 Redis 是单线程的,也就说一个线程要同时负责多个客户端套接字的并发读写,以及内存数据结构的逻辑读写。
Redis 服务器不仅需要服务线上请求,同时还要备份内存快照。在备份过程中 Redis 必须进行文件 IO 读写,而 IO 操作会影响服务器的性能。那么如何实现既不影响客户端的请求,又实现快照备份操作呢,这时就用到了多进程。
Redis 使用操作系统的多进程 COW(Copy On Write) 机制来实现快照持久化操作。
RDB 实际上是 Redis 内部的一个定时器事件,它每隔一段固定时间就去检查当前数据发生改变的次数和改变的时间频率,看它们是否满足配置文件中规定的持久化触发条件。当满足条件时,Redis 就会通过操作系统调用 fork() 来创建一个子进程,该子进程与父进程享有相同的地址空间。
Redis 通过子进程遍历整个内存空间来获取存储的数据,从而完成数据持久化操作。注意,此时的主进程则仍然可以对外提供服务,父子进程之间通过操作系统的 COW 机制实现了数据段分离,从而保证了父子进程之间互不影响。
2.3 RDB持久化触发策略
RDB 持久化提供了两种触发策略:一种是手动触发,另一种是自动触发。
1) 手动触发策略
手动触发是通过SAVE
命令或者BGSAVE
命令将内存数据保存到磁盘文件中。如下所示:
127.0.0.1:6379> SAVE
OK
127.0.0.1:6379> BGSAVE
Background saving started
127.0.0.1:6379> LASTSAVE # 查看 BGSAVE 命令是否执行成功
(integer) 1611298430
'''
save(同步)
1 客户端执行save命令----> redis服务端----> 同步创建RDB二进制文件
2 会造成redis的阻塞(数据量非常大的时候)
3 文件策略:如果老的RDB存在,会替换老的
4 复杂度 o(n)
'''
'''
bgsave(异步,Backgroud saving started)
1 客户端执行save命令----> redis服务端----> 异步创建RDB二进制文件
2 此时访问redis,会正常响应客户端
3 文件策略:跟save相同,如果老的RDB存在,会替换老的
4 复杂度 o(n)
'''
上述命令BGSAVE
从后台执行数据保存操作,其可用性要优于执行 SAVE 命令。
SAVE 命令会阻塞 Redis 服务器进程,直到 dump.rdb 文件创建完毕为止,在这个过程中,服务器不能处理任何的命令请求。
BGSAVE
命令是非阻塞式的,所谓非阻塞式,指的是在该命令执行的过程中,并不影响 Redis 服务器处理客户端的其他请求。这是因为 Redis 服务器会 fork() 一个子进程来进行持久化操作(比如创建新的 dunp.rdb 文件),而父进程则继续处理客户端请求。当子进程处理完后会向父进程发送一个信号,通知它已经处理完毕。此时,父进程会用新的 dump.rdb 文件覆盖掉原来的旧文件。
因为SAVE
命令无需创建子进程,所以执行速度要略快于BGSAVE
命令,但是SAVE
命令是阻塞式的,因此其可用性欠佳,如果在数据量较少的情况下,基本上体会不到两个命令的差别,不过仍然建议您使用 BGSAVE
命令。
2) 自动触发策略
自动触发策略,是指 Redis 在指定的时间内,数据发生了多少次变化时,会自动执行BGSAVE
命令。自动触发的条件包含在 Redis 配置文件中,如下所示:
'''
配置 seconds changes
save 900 1 在 900 秒内,至少更新了 1 条数据,Redis 自动触发 BGSAVE 命令,将数据保存到硬盘。
save 300 10 在 900 秒内,至少更新了 1 条数据,Redis 自动触发 BGSAVE 命令,将数据保存到硬盘。
save 60 10000 在 60 秒内,至少更新了 10000 条数据,Redis 自动触发 BGSAVE 命令,将数据保存到硬盘。
以上三条符合任意一条,就自动生成rdb,内部使用bgsave
'''
#最佳配置
save 900 1
save 300 10
save 60 10000
dbfilename dump-${port}.rdb #rdb文件的名字,默认为dump.rdb;改为以端口号作为文件名,可能一台机器上很多reids,不会乱
dir /opt/zl/redis/data #rdb文件保存目录,保存路径放到一个大硬盘位置目录
stop-writes-on-bgsave-error yes #如果bgsave出现错误,是否停止写入,默认为yes
rdbcompression yes #采用压缩格式
rdbchecksum yes #是否对rdb文件进行校验和检验,默认yes
2.4 触发机制-不容忽略的方式
1 全量复制 #每次都是全量复制而不是只复制增量,如果数据量非常大,比如10个G的数据,每次快照都会把10个G的数据备份一遍
2 debug reload #debug级别的重启,不会将内存中的数据清空
3 shutdown save #关闭会触发rdb的生成
2.5 RDB持久化优劣势
在 RDB 持久化的过程中,子进程会把 Redis 的所有数据都保存到新建的 dump.rdb 文件中,这是一个既消耗资源又浪费时间的操作。因此 Redis 服务器不能过于频繁地创建 rdb 文件,否则会严重影响服务器的性能。
RDB 持久化的最大不足之处在于,最后一次持久化的数据可能会出现丢失的情况。
RDB 数据持久化适合于大规模的数据恢复,并且还原速度快,如果对数据的完整性不是特别敏感,那么 RDB 持久化方式非常合适。
3 Redis AOF持久化
3.1 AOF介绍
AOF 被称为追加模式,或日志模式,是 Redis 提供的另一种持久化策略,它能够存储 Redis 服务器已经执行过的的命令,并且只记录对内存有过修改的命令,这种数据记录方法,被叫做“增量复制”,其默认存储文件为appendonly.aof
。
客户端每写入一条命令,都记录一条日志,放到日志文件中,如果出现宕机,可以将数据完全恢复。
3.2 AOF的三种策略
日志不是直接写到硬盘上,而是先放在内存缓存区(buffer)中,缓冲区根据一些策略,写到硬盘上
always:redis –-->服务器每写入一个命令,就调用一次 fsync 函数,将缓冲区里面的命令写入到硬盘 ---> AOF文件
everysec(默认值):redis ---> 服务器每一秒调用一次 fsync 函数,将缓冲区里面的命令写入到硬盘 ---> AOF文件
no :redis ---> 服务器不主动调用 fsync 函数,由操作系统决定何时将缓冲区里面的命令写入到硬盘 ---> AOF文件
命令 | always | everysec | no |
---|---|---|---|
优点 | 不丢失数据 | 每秒一次fsync | 不用管,操作系统决定 |
缺点 | IO开销大,一般的sata盘(机械硬盘)只有几百TPS | 最多只丢失一秒钟内的执行的命令数据 | 不可控 |
在生产环境的服务器中,Redis 通常是每隔 1s 左右执行一次 fsync 操作( Everysec),这样既保持了高性能,也让数据尽可能的少丢失。
3.4 AOF 重写机制
Redis 在长期运行的过程中,aof 文件会越变越长。如果机器宕机重启,“重演”整个 aof 文件会非常耗时,导致长时间 Redis 无法对外提供服务。因此就需要对 aof 文件做一下“瘦身”运动。本质就是把过期的,无用的,重复的,可以优化的命令,进行优化,下表对原有 aof 文件和新生成的 aof 文件做了对比:
原有aof文件 | 重写后的aof文件 |
---|---|
set hello world set hello java set hello hehe incr counter incr counter rpush mylist a rpush mylist b rpush mylist c 过期数据 |
set hello hehe set counter 2 rpush mylist a b c |
1)手动重写AOF
手动执行BGREWRITEAOF
命令,开始重写 aof 文件,客户端向服务端发送BGREWRITEAOF
命令,服务端会起一个fork进程,完成AOF重写,如下所示:
127.0.0.1:6379> BGREWRITEAOF
Background append only file rewriting started
通过上述操作后,服务器会生成一个新的 aof 文件,该文件具有以下特点:
- 新的 aof 文件记录的数据库数据和原 aof 文件记录的数据库数据完全一致;
- 新的 aof 文件会使用尽可能少的命令来记录数据库数据,因此新的 aof 文件的体积会小很多;
- AOF 重写期间,服务器不会被阻塞,它可以正常处理客户端发送的命令。
2) 自动触发AOF重写
Redis 为自动触发 AOF 重写功能,提供了相应的配置策略。如下所示:修改 Redis 配置文件,让服务器自动执行 BGREWRITEAOF 命令。
配置名 | 含义 |
---|---|
auto-aof-rewrite-min-size | AOF文件重写需要尺寸 |
auto-aof-rewrite-percentage | AOF文件增长率 |
统计名 | 含义 |
---|---|
aof_current_size | AOF当前尺寸(单位:字节) |
aof_base_size | AOF上次启动和重写的尺寸(单位:字节) |
自动触发时机(两个条件同时满足):
aof_current_size > auto-aof-rewrite-min-size:当前尺寸大于重写需要尺寸
(aof_current_size-aof_base_size)/aof_base_size > auto-aof-rewrite-percentage:(增长率)当前尺寸减去上次重写的尺寸,除以上次重写的尺寸如果大于配置中的增长率
演示示例:
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb # 表示触发AOF重写的最小文件体积,大于或等于64MB自动触发。
该配置项表示:触发重写所需要的 aof 文件体积百分比,只有当 aof 文件的增量大于 100% 时才进行重写,也就是大一倍。比如,第一次重写时文件大小为 64M,那么第二次触发重写的体积为 128M,第三次重写为 256M,以此类推。如果将百分比值设置为 0 就表示关闭 AOF 自动重写功能。
3) 重写流程
3.5 AOF持久化配置
最优配置方案,配置好自动开启AOF持久化和AOF重写
appendonly yes #将该选项设置为yes,打开
appendfilename "appendonly-${port}.aof" #文件保存的名字,以端口号作为文件名,可能一台机器上很多reids,不会乱
appendfsync everysec #采用第二种策略
dir /opt/zl/redis/data #文件存放的路径
no-appendfsync-on-rewrite yes #在aof重写的时候,是否要做aof的append操作,因为aof重写消耗性能,磁盘消耗,正常aof写磁盘有一定的冲突,这段期间的数据,允许丢失
4 RDB和AOF的选择
4.1 rdb和aof的比较
RDB持久化 | AOF持久化 |
---|---|
全量备份,一次保存整个数据库。 | 增量备份,一次只保存一个修改数据库的命令。 |
每次执行持久化操作的间隔时间较长。 | 保存的间隔默认为一秒钟(Everysec) |
数据保存为二进制格式,其还原速度快。 | 使用文本格式还原数据,所以数据还原速度一般。 |
执行 SAVE 命令时会阻塞服务器,但手动或者自动触发的 BGSAVE 不会阻塞服务器 | AOF持久化无论何时都不会阻塞服务器。 |
如果进行数据恢复时,既有 dump.rdb文件,又有 appendonly.aof 文件,您应该先通过 appendonly.aof 恢复数据,这能最大程度地保证数据的安全性。
4.2 rdb最佳策略
rdb关掉,主从操作时
集中管理:按天,按小时备份数据
主从配置,从节点打开
4.3 aof最佳策略
开:缓存和存储,大部分情况都打开
aof重写集中管理
everysec:通过每秒刷新的策略
4.4 redis持久化最佳策略
小分片:每个redis的最大内存为4g
缓存或存储:根据特性,使用不同策略
时时监控硬盘,内存,负载网络等
有足够内存