Redis从入门到入坑11——Redis持久化

2023年 8月 16日 56.7k 0

Redis从入门到入坑——redis持久化

redis 持久化(官网原文)

官网地址:redis.io/docs/manage…

Persistence refers to the writing of data to durable storage, such as a solid-state disk (SSD). Redis provides a range of persistence options. These include:

RDB (Redis Database): RDB persistence performs point-in-time snapshots of your dataset at specified intervals.
AOF (Append Only File): AOF persistence logs every write operation received by the server. These operations can then be replayed again at server startup, reconstructing the original dataset. Commands are logged using the same format as the Redis protocol itself.
No persistence: You can disable persistence completely. This is sometimes used when caching.
RDB + AOF: You can also combine both AOF and RDB in the same instance.
If you'd rather not think about the tradeoffs between these different persistence strategies, you may want to consider Redis Enterprise's persistence options, which can be pre-configured using a UI.

持久化(persistence)是指将数据写入持久存储,例如固态磁盘(SSD)。Redis提供了一系列的持久化选项。这些包括:

RDB (Redis Database):RDB持久化以指定的时间间隔执行数据集的时间点快照。

AOF(Append Only File):AOF持久性记录服务器接收到的每个写操作。然后,这些操作可以在服务器启动时再次重新加载,重建原始数据集。命令使用与Redis协议本身相同的格式进行记录。

禁用持久化:您可以完全禁用持久化。这有时在缓存时使用。

RDB + AOF:您也可以在同一个实例中组合使用AOF和RDB。

RDB和AOF使用情形所示:

image.png

RDB(Redis Database)

image.png

RDB (Redis Database):RDB持久化以指定的时间间隔执行数据集的时间点快照

简介:实现类似照片记录效果的方式,就是把某一时刻的数据和状态以文件的形式写到磁盘上,也就是
快照。这样一来即使故障宕机,快照文件也不会丢失,数据的可靠性也就得到了保证。
这个快照文件就称为RDB文件(dump.rdb),其中,RDB就是Redis DataBase的缩写

作用:在指定的时间间隔内将内存中的数据集快照写入磁盘,也就是行话讲的Snapshot内存快照,它恢复时再将硬盘快照文件直接读回到内存里。由于redis的数据都是在内存中,保存备份时执行的是全量快照,也就是把内存中的数据全部都写到磁盘中,保存生成的文件是 dump.rdb

RDB 配置概述

配置对比

Redis6.0.16及以下:

image.png

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

配置 描述
save 900 1 每隔900s(15min),如果有超过1个key发生了变化,就写一份新的RDB文件
save 300 10 每隔300s(5min),如果有超过10 个key 发生了变化,就写一份新的RDB文件
save 60 10000 每隔60s(1min),如果有超过10000 个key发生了变化,就写一份新的RDB文件

redis6.2至redis7配置:配置的 save 参数可以是多个

image.png

RDB 触发

SNAPSHOTTING 各个配置参数 :

参数 描述
save seconds changes [ ...] RDB触发条件:固定的时间范围内满足多少次的变化就触发
stop-writes-on-bgsave-error yes 配置了,如果进行 RDB 备份文件生成过程中,遭遇错误,是否停止 redis 提供写服务,以警示用户 RDB 备份异常,默认是开启状态
rdbcompression yes 配置的是 rdb 文件中压缩启用配置 ,默认是 yes
rdbchecksum yes 配置 redis 是否使用 CRC64 校验算法校验 RDB 文件是否发生损坏,默认开启状态,如果你需要提升性能,可以选择性关闭
dbfilename dump.rdb 配置生成的rdb文件名称
rdb-del-sync-files no Redis主从全量同步时,通过RDB文件传输实现。如果没有开启持久化,同步完成后,是否要移除主从同步的RDB文件,默认为no
dir ./ 生成的rdb文件路径

自动触发:

1.配置触发条件: 本处案例 5秒2次 修改

image.png

2.配置生成的rdb文件名称和路径:

image.png

3.触发备份

--- 第一种情况,5秒内保存两次
    
-- 生成的rdb文件路径下是没有任何文件的
[root@gone myredis]# cd  dumpfiles/
[root@gone dumpfiles]# ll
total 0
    
-- 5秒内执行命令
127.0.0.1:6379> set k1 v1
OK
127.0.0.1:6379> set k2 v2
OK
    
-- 查看rdb文件路径下的内容,此时已经生成了rdb文件
[root@gone dumpfiles]# ll
total 4
-rw-r--r--. 1 root root 107 Aug  3 21:19 dump6379.rdb
    
--- 第二种情况,两次保存间隔超过5秒
--- 执行前先查看下当前的rdb文件大小
[root@gone dumpfiles]# ll
total 4
-rw-r--r--. 1 root root 107 Aug  3 21:19 dump6379.rdb
--- 执行set命令
127.0.0.1:6379> set k3 v3
OK
--- 查看 rdb 文件大小,没有变化,执行set k3 v3的数据没有写入
[root@gone dumpfiles]# ll
total 4
-rw-r--r--. 1 root root 107 Aug  3 21:19 dump6379.rdb
.....间隔5秒后执行
127.0.0.1:6379> set k4 v4
OK
--- 再次查看 rdb 文件大小,可以看到由107变成121了,说明这两次数据写入已经持久化到rdb文件中了
[root@gone dumpfiles]# ll
total 4
-rw-r--r--. 1 root root 121 Aug  3 21:21 dump6379.rdb    
    

4.从rdb文件中恢复数据验证触发备份时数据正确写入到rdb文件中

--- 验证:
把rdb文件先移到别的目录下    
[root@gone dumpfiles]# mv dump6379.rdb /root/myredis
清空数据    
127.0.0.1:6379> flushall
OK
127.0.0.1:6379> keys *
(empty array)
127.0.0.1:6379> SHUTDOWN
not connected> quit
-- 删除掉因为执行 shutdown 生成的rdb文件
[root@gone dumpfiles]# rm dump6379.rdb 
rm: remove regular file ‘dump6379.rdb’? y
[root@gone dumpfiles]# ll
total 0
--- 把之前的rdb文件重新放到对应路径下,然后启动redis,查看之前写入的数据都能获取到,说明之前的数据写入到rdb文件成功
[root@gone myredis]# mv dump6379.rdb /root/myredis/dumpfiles/
[root@gone myredis]# redis-server redis.conf 
[root@gone myredis]# redis-cli -a 111111
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:6379> get k3 
"v3"
127.0.0.1:6379> get k4 
"v4" 

手动触发

RDB提供了 save 和 bgsave 两个命令来生成 rdb文件

save: 在主程序中执行会阻塞当前redis服务器,知道持久化工作完成,在执行save命令期间,redis不能处理其他命令;save执行流程如下图所示。线上禁止使用

image.png

save案例演示

--- 清空rdb文件生成目录dumpfiles内容
[root@gone dumpfiles]# rm dump6379.rdb 
rm: remove regular file ‘dump6379.rdb’? y
[root@gone dumpfiles]# 
[root@gone dumpfiles]# ll
total 0
    
--- 执行 set 命令
127.0.0.1:6379> set k1 v1 
OK
    
--- rdb 文件此时并未生成
[root@gone dumpfiles]# ll
total 0
    
--- 执行save命令
127.0.0.1:6379> save
OK
    
--- rdb 文件生成
[root@gone dumpfiles]# ll
total 4
-rw-r--r--. 1 root root 104 Aug  4 10:37 dump6379.rdb

bgsave(默认):Redis会在后台进行异步快照操作(不阻塞),快照同时还能响应客户端请求,该触发方式会fork一个子进程,由子进程复制持久化过程。bgsave执行流程图下图所示

image.png

bgsave案例演示

[root@gone dumpfiles]# rm dump6379.rdb 
rm: remove regular file ‘dump6379.rdb’? y
[root@gone dumpfiles]# 
[root@gone dumpfiles]# ll
total 0
    
--- 执行 set 命令
127.0.0.1:6379> set k1 v1 
OK
    
--- rdb 文件此时并未生成
[root@gone dumpfiles]# ll
total 0
    
--- 执行bgsave命令
127.0.0.1:6379> bgsave
Background saving started

--- rdb 文件生成
[root@gone dumpfiles]# ll
total 4
-rw-r--r--. 1 root root 104 Aug  4 10:37 dump6379.rdb

lastsave:返回最后一次成功执行快照的 unix 时间

127.0.0.1:6379> lastsave
(integer) 1691116884 

-- 查看对应的时间
[root@gone dumpfiles]# date -d @1691116884
Fri Aug  4 10:41:24 CST 2023

触发RDB快照情形

  • 手动执行 save/bgsave 命令
  • 执行flushall/flushdb 命令
  • 执行shutdown 且没有开启AOF
  • 主从复制时,主节点自动触发

RDB的优势和劣势

优势(官网原文)

RDB advantages

RDB is a very compact single-file point-in-time representation of your Redis data. RDB files are perfect for backups. For instance you may want to archive your RDB files every hour for the latest 24 hours, and to save an RDB snapshot every day for 30 days. This allows you to easily restore different versions of the data set in case of disasters.
RDB is very good for disaster recovery, being a single compact file that can be transferred to far data centers, or onto Amazon S3 (possibly encrypted).
RDB maximizes Redis performances since the only work the Redis parent process needs to do in order to persist is forking a child that will do all the rest. The parent process will never perform disk I/O or alike.
RDB allows faster restarts with big datasets compared to AOF.
On replicas, RDB supports partial resynchronizations after restarts and failovers.

RDB的优势

RDB是Redis数据的一个非常紧凑的单文件时间点表示。RDB文件是完美的备份。例如,您可能希望在最近24小时内每小时归档RDB文件,并在30天内每天保存RDB快照。这允许您在发生灾难时轻松恢复数据集的不同版本。
RDB非常适合灾难恢复,它是一个单一的压缩文件,可以传输到远端的数据中心,也可以传输到Amazon S3(可能是加密的)。
RDB最大限度地提高了Redis的性能,因为Redis父进程为了持久化所需要做的唯一工作就是分支一个子进程来完成其余的工作。父进程永远不会执行磁盘I/O或类似的操作。
与AOF相比,RDB允许更快地重启大数据集。
在副本上,RDB支持重启和故障转移后的部分重新同步

劣势(官网原文)

RDB disadvantages

RDB is NOT good if you need to minimize the chance of data loss in case Redis stops working (for example after a power outage). You can configure different save points where an RDB is produced (for instance after at least five minutes and 100 writes against the data set, you can have multiple save points). However you'll usually create an RDB snapshot every five minutes or more, so in case of Redis stopping working without a correct shutdown for any reason you should be prepared to lose the latest minutes of data.
RDB needs to fork() often in order to persist on disk using a child process. fork() can be time consuming if the dataset is big, and may result in Redis stopping serving clients for some milliseconds or even for one second if the dataset is very big and the CPU performance is not great. AOF also needs to fork() but less frequently and you can tune how often you want to rewrite your logs without any trade-off on durability.

如果你需要在Redis停止工作(例如停电后)时最小化数据丢失的机会,RDB不是很好。您可以在生成RDB的地方配置不同的保存点(例如,在对数据集进行至少5分钟和100次写操作之后,您可以有多个保存点)。然而,你通常会每五分钟或更长时间创建一个RDB快照,所以如果Redis在没有正确关机的情况下停止工作,你应该准备好丢失最近几分钟的数据。
为了使用子进程在磁盘上持久化,RDB需要经常fork()。如果数据集很大,fork()可能会很耗时,如果数据集很大,CPU性能不是很好,可能会导致Redis停止为客户端服务几毫秒甚至一秒钟。AOF也需要fork(),但频率较低,您可以调整重写日志的频率,而不会影响持久性。

优劣势总结

优势:

  • 适合大规模的数据备份
  • 按照业务定时备份
  • 对数据完整性和一致性要求不高
  • RDB文件在内存中加载速度比AOF文件快的多

劣势:

  • 在一定间隔时间内做一次备份,如果redis意外宕机,则会丢失从当前到最近一次快照期间的数据,快照之间的数据会丢失
  • 内存数据的全量同步,如果数据量太大会导致I/O严重影响服务器性能
  • RDB依赖主进程的fork,在更大的数据集中,可能导致服务请求的瞬间延迟;fork的时候,内存中的数据被克隆了一份,大致2倍的膨胀需要考虑

模拟数据丢失案例

-- 先查看数据库中所有的key
127.0.0.1:6379> keys *
1) "k1"
127.0.0.1:6379> get k1
"v1"

-- 查看当前的rdb文件大小    
[root@gone dumpfiles]# ll
total 4
-rw-r--r--. 1 root root 104 Aug  4 10:41 dump6379.rdb

-- 插入一条数据
127.0.0.1:6379> set k2 v2
OK    
-- 再次查看当前的rdb文件大小和执行 set k2 v2 命令之前无变化,说明此时数据并没有持久化  
[root@gone dumpfiles]# ll
total 4
-rw-r--r--. 1 root root 104 Aug  4 10:41 dump6379.rdb 

-- 使用kill -9 模拟宕机
[root@gone dumpfiles]# ps -ef|grep redis
root      78675      1  0 10:32 ?        00:00:01 redis-server *:6379
root      78684  77430  0 10:32 pts/2    00:00:00 redis-cli
root      80031  78704  0 10:44 pts/3    00:00:00 grep --color=auto redis
[root@gone dumpfiles]# kill -9 78675

-- 重新启动redis    
[root@gone dumpfiles]# redis-server /root/myredis/redis.conf

-- 查看 k2 是否有对应的数据
127.0.0.1:6379> get k2  
(nil)  --------- 说明数据丢失

如何检查修复RDB文件

image.png

[root@gone ~]# redis-check-rdb /root/myredis/dumpfiles/dump6379.rdb 
[offset 0] Checking RDB file /root/myredis/dumpfiles/dump6379.rdb
[offset 26] AUX FIELD redis-ver = '6.2.1'
[offset 40] AUX FIELD redis-bits = '64'
[offset 52] AUX FIELD ctime = '1691116884'
[offset 67] AUX FIELD used-mem = '872152'
[offset 83] AUX FIELD aof-preamble = '0'
[offset 85] Selecting DB ID 0
[offset 104] Checksum OK
[offset 104] o/ RDB looks OK! o/
[info] 1 keys read
[info] 0 expires
[info] 0 already expired

如何禁用快照

1.动态停止RDB保存规则的方法:redis-cli config set save ""

-- 清空数据
127.0.0.1:6379> flushdb 
OK
-- 删除rdb 文件
[root@gone dumpfiles]# rm dump6379.rdb 
rm: remove regular file ‘dump6379.rdb’? y
    
-- 动态停止RDB保存
[root@gone myredis]# redis-cli  config set save "" 
OK
[root@gone myredis]# redis-cli -a 111111
-- 5秒内执行下面3个命令
127.0.0.1:6379> set k1 v1
OK
127.0.0.1:6379> set k2 v2 
OK
127.0.0.1:6379> set k3 v3
OK
    
-- 查看rdb文件生成目录,并没有生成rdb文件
[root@gone dumpfiles]# ll
total 0

--- 此时执行手动触发RDB生成命令,则会生成RDB文件
127.0.0.1:6379> save
OK
[root@gone dumpfiles]# ll
total 4
-rw-r--r--. 1 root root 118 Aug  4 11:01 dump6379.rdb

2.配置文件中配置快照禁用:配置文件中开启 save "" ,且需要注释调之前配置的触发规则,否则不生效

image.png

AOF(Append Only File)

AOF (Append Only File):AOF持久化记录服务器接收到的每个写操作

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

作用:每次Redis接收到改变数据集的命令(例如SET),它都会将其附加到AOF。当你重启Redis时,它会重新加载AOF来恢复之前的数据

AOF持久化工作流程

image.png

执行流程步骤 流程执行内容
1 在这些命令到达Redis Server 以后并不是直接写入AOF文件,会将其这些命令先放入AOF缓存中进行保存。这里的AOF缓冲区实际上是内存中的一片区域,存在的目的是当这些命令达到一定量以后再写入磁盘,避免频繁的磁盘IO操作。
2 在这些命令到达Redis Server 以后并不是直接写入AOF文件,会将其这些命令先放入AOF缓存中进行保存。这里的AOF缓冲区实际上是内存中的一片区域,存在的目的是当这些命令达到一定量以后再写入磁盘,避免频繁的磁盘IO操作。
3 AOF缓冲会根据AOF缓冲区同步文件的三种写回策略将命令写入磁盘上的AOF文件。
4 随着写入AOF内容的增加为避免文件膨胀,会根据规则进行命令的合并(又称**AOF重写) **,从而起到AOF文件压缩的目的。
5 当Redis Server 服务器重启的时候会从AOF文件载入数据

AOF缓冲区三种回写策略

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

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

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

配置项 写回时机 优点 缺点
always 同步写回 可靠性高,数据基本不丢失 每个写命令都要罗盘,性能影响较大
everysec 每秒写回 性能适中 宕机时丢失1秒内的数据
no 操作系统控制的写回 性能好 宕机时丢失的数据比较多

AOF 配置概述

开启AOF

redis.conf 文件中把 把 appendonly no 修改为 appendonly yes

   # Please check https://redis.io/topics/persistence for more information.
 
   #appendonly no
    appendonly yes
   # The base name of the append only file

配置写回策略:使用默认———— appendfsync everysec ,

# If unsure, use "everysec".
# appendfsync always   --- 同步写回
appendfsync everysec   --- 每秒写回 (默认的写回策略)
# appendfsync no       --- 系统控制

AOF 文件保存路径

Redis6: AOF保存文件的位置和RDB保存文件的位置一样,都是通过redis.conf配置文件的dir配置

# The working directory.
#
# The DB will be written inside this directory, with the filename specified
# above using the 'dbfilename' configuration directive.
#
# The Append Only File will also be created inside this directory.
#
# Note that you must specify a directory here, not a file name.
dir /root/myredis

Redis7:已经和RDB做了区分,单独设置 aof 文件名称和 文件路径

# For convenience, Redis stores all persistent append-only files in a dedicated
# directory. The name of the directory is determined by the appenddirname
# configuration parameter.

appenddirname "appendonlydir"

Redis6 和 Redis7 的区别如下图所示

32.AOF配置文件路径(Redis7).jpg

区分对比
33.Redis新老版本区别.jpg

AOF文件保存名称

Redis6:有且仅有一个

# AOF and RDB persistence can be enabled at the same time without problems.
# If the AOF is enabled on startup Redis will load the AOF, that is the file
# with the better durability guarantees.
#
# Please check http://redis.io/topics/persistence for more information.

appendonly no

# The name of the append only file (default: "appendonly.aof")

appendfilename "appendonly.aof"

Redis7: multi part AOF 设计;分为 base基本文件、incr增量文件、manifest清单文件

# Append-only file names are created by Redis following a specific pattern.
# The file name's prefix is based on the 'appendfilename' configuration
# parameter, followed by additional information about the sequence and type.
#
# For example, if appendfilename is set to appendonly.aof, the following file
# names could be derived:
# 
# - appendonly.aof.1.base.rdb as a base file.
# - appendonly.aof.1.incr.aof, appendonly.aof.2.incr.aof as incremental files.
# - appendonly.aof.manifest as a manifest file.

appendfilename "appendonly.aof"

redis7 中redis.conf 文件里对应的AOF文件配置项信息

配置项 说明
appendfilename "appendonly.aof" 几种类型文件的前缀,后接有关序列和类型的附加信息
appenddirname "appendonlydir" 新版本增加的目录配置项目
appendonly.aof.1.base.rdb 基本文件
appendonly.aof.1.incr.aof 增量文件
appendonly.aof.2.incr.aof 增量文件
appendonly.aof.manifest 清单文件

模拟数据丢失恢复案例

正常恢复:

  • 修改默认的appendonly no,改为 yes ,并在配置文件中开启 save "" 执行禁用 rdb 快照
  • # AOF and RDB persistence can be enabled at the same time without problems.
    # If the AOF is enabled on startup Redis will load the AOF, that is the file
    # with the better durability guarantees.
    #
    # Please check https://redis.io/topics/persistence for more information.
    
    # appendonly no
      appendonly yes
    
  • 重新启动redis:可以看到在 /root/myredis/appendonlydir 路径下已经生成了 appendonly.aof 文件
  • [root@gone appendonlydir]# ll
    total 12
    -rw-------. 1 polkitd input 88 Aug 15 16:33 appendonly.aof.1.base.rdb
    -rw-------. 1 polkitd input 81 Aug 15 16:34 appendonly.aof.1.incr.aof
    -rw-------. 1 polkitd input 88 Aug 15 16:33 appendonly.aof.manifest
    [root@gone appendonlydir]# pwd
    /root/myredis/appendonlydir
    
  • 往redis中插入一些数据
  • 127.0.0.1:6379> keys *
    (empty array)
    127.0.0.1:6379> set k1 v1
    OK
    127.0.0.1:6379> set k2 v2
    OK
    127.0.0.1:6379> set k3 v3
    OK
    127.0.0.1:6379> keys *
    1) "k3"
    2) "k1"
    3) "k2"
    
  • 备份 appendonlydir 为appendonlydir_bak,然后删除掉 appendonlydir,并清空掉redis中的数据
  • [root@gone data]# cp -r appendonlydir appendonlydir_bak
    [root@gone data]# cd  appendonlydir
    [root@gone appendonlydir]# ll
    total 12
    -rw-------. 1 polkitd input  88 Aug 15 16:33 appendonly.aof.1.base.rdb
    -rw-------. 1 polkitd input 110 Aug 15 16:39 appendonly.aof.1.incr.aof
    -rw-------. 1 polkitd input  88 Aug 15 16:33 appendonly.aof.manifest
    [root@gone appendonlydir]# rm -f appendonly.aof.*
    [root@gone appendonlydir]# ll
    total 0
    [root@gone appendonlydir]# ll
    total 0
    --- 清空数据并停止redis服务
    127.0.0.1:6379> flushdb
    OK
    127.0.0.1:6379> keys *
    (empty array)
    127.0.0.1:6379> shutdown
    
    
  • 把备份的 aof 文件复制回 appendonlydir 路径下
  • [root@gone appendonlydir_bak]# cp appendonly.aof.* /root/myredis/appendonlydir
    [root@gone appendonlydir_bak]# cd /root/myredis/appendonlydir
    [root@gone appendonlydir]# ll
    total 12
    -rw-------. 1 root root  88 Aug 15 16:53 appendonly.aof.1.base.rdb
    -rw-------. 1 root root 110 Aug 15 16:53 appendonly.aof.1.incr.aof
    -rw-------. 1 root root  88 Aug 15 16:53 appendonly.aof.manifest 
    
  • 重新启动 redis ,查看是否有之前的数据————结果OK,将之前的数据重新写回了redis
  • [root@gone appendonlydir]# redis-server /root/myredis/redis.conf
    [root@gone appendonlydir]# redis-cli
    127.0.0.1:6379> keys *
    1) "k3"
    2) "k2"
    3) "k1"
    

    异常恢复

    1.故意胡乱改动正常的AOF文件,模拟网络闪断文件写入不完整等其他异常情况

    [root@gone appendonlydir]# vim appendonly.aof.1.incr.aof 
    
    *2
    $6
    SELECT
    $1
    0
    *3
    $3
    set
    $2
    k1
    $2
    v1
    *3
    $3
    set
    $2
    k2
    $2
    v2
    *3
    $3
    set
    $2
    k3
    $2
    v3
    
    aaaaaaa1111dsadsa
    
  • 重启redis:发现redis服务启动不了
  • 1:M 15 Aug 2023 09:07:33.895 # Bad file format reading the append only file appendonly.aof.1.incr.aof: make a backup of your AOF file, then use ./redis-check-aof --fix 
    

    3.使用 redis-check-aof 命令进行修复

    [root@gone appendonlydir]# redis-check-aof --fix appendonly.aof.1.incr.aof 
    'x              6e: Expected prefix '*', got: '
    AOF analyzed: size=132, ok_up_to=110, diff=22
    This will shrink the AOF from 132 bytes, with 22 bytes, to 110 bytes
    Continue? [y/N]: y
    Successfully truncated AOF
    
  • 再次启动,并重新连接————启动正常,连接成功后查看数据也OK
  • [root@gone appendonlydir]# redis-server /root/myredis/redis.conf
    [root@gone appendonlydir]# redis-cli
    127.0.0.1:6379> keys *
    1) "k3"
    2) "k2"
    3) "k1"
    

    AOF的优势和劣势

    优势(官网原文)

    • Using AOF Redis is much more durable: you can have different fsync policies: no fsync at all, fsync every second, fsync at every query. With the default policy of fsync every second, write performance is still great. fsync is performed using a background thread and the main thread will try hard to perform writes when no fsync is in progress, so you can only lose one second worth of writes.
    • The AOF log is an append-only log, so there are no seeks, nor corruption problems if there is a power outage. Even if the log ends with a half-written command for some reason (disk full or other reasons) the redis-check-aof tool is able to fix it easily.
    • Redis is able to automatically rewrite the AOF in background when it gets too big. The rewrite is completely safe as while Redis continues appending to the old file, a completely new one is produced with the minimal set of operations needed to create the current data set, and once this second file is ready Redis switches the two and starts appending to the new one.
    • AOF contains a log of all the operations one after the other in an easy to understand and parse format. You can even easily export an AOF file. For instance even if you've accidentally flushed everything using the FLUSHALL command, as long as no rewrite of the log was performed in the meantime, you can still save your data set just by stopping the server, removing the latest command, and restarting Redis again
    • 使用AOF Redis更持久:你可以有不同的fsync策略:根本不同步,每秒同步,每次查询同步。在默认的每秒fsync策略下,写性能仍然很好。Fsync是使用后台线程执行的,主线程在没有Fsync的情况下会努力执行写操作,所以你只会损失一秒钟的写时间。
    • AOF日志是一个只能追加的日志,因此在停电时不会出现查找和损坏问题。即使日志由于某种原因(磁盘已满或其他原因)以未写完的命令结束,redischeck -aof工具也能够轻松修复它。
      Redis能够在后台自动重写AOF,当它变得太大。重写是完全安全的,因为当Redis继续附加到旧文件时,一个全新的文件将产生,并且使用创建当前数据集所需的最小操作集,一旦第二个文件准备好,Redis切换两个文件并开始附加到新文件。
    • AOF以易于理解和解析的格式包含所有操作的一个接一个的日志。您甚至可以轻松地导出AOF文件。例如,即使您使用FLUSHALL命令意外刷新了所有内容,只要在此期间没有执行日志重写,您仍然可以通过停止服务器,删除最新命令并重新启动Redis来保存数据集

    劣势(官网原文)

    • AOF files are usually bigger than the equivalent RDB files for the same dataset.
    • AOF can be slower than RDB depending on the exact fsync policy. In general with fsync set to every second performance is still very high, and with fsync disabled it should be exactly as fast as RDB even under high load. Still RDB is able to provide more guarantees about the maximum latency even in the case of a huge write load.
    • 对于相同的数据集,AOF文件通常比同等的RDB文件大。
    • AOF可能比RDB慢,这取决于确切的fsync策略。一般来说,将fsync设置为每秒的性能仍然非常高,并且在禁用fsync的情况下,即使在高负载下,它也应该与RDB一样快。尽管如此,即使在写负载很大的情况下,RDB也能够提供更多关于最大延迟的保证。

    优劣势总结

    优势:

    • 更好的保护数据不丢失、性能高、可做紧急恢复

    劣势:

    • 相同数据集的数据而言aof文件要远大于rdb文件,恢复速度慢于rdbaof运行效率要慢于rdb,每秒同步策略效率较好,不同步效率和rdb相同
    • aof运行效率要慢于rdb,每秒同步策略效率较好,不同步效率和rdb相同

    AOF 重写机制(Log rewriting)

    由于AOF持久化是Redis不断将写命令记录到 AOF 文件中,随着Redis不断的进行,AOF 的文件会越来越大,文件越大,占用服务器内存越大以及 AOF 恢复要求时间越长。

    为了解决这个问题,Redis新增了重写机制,当AOF文件的大小超过所设定的峰值时,Redis就会自动启动AOF文件的内容压缩,只保留可以恢复数据的最小指令集,或者可以手动使用命令 bgrewriteaof 来重新。

    重写机制(官网原文)

    Log rewriting

    The AOF gets bigger and bigger as write operations are performed. For example, if you are incrementing a counter 100 times, you'll end up with a single key in your dataset containing the final value, but 100 entries in your AOF. 99 of those entries are not needed to rebuild the current state.

    The rewrite is completely safe. While Redis continues appending to the old file, a completely new one is produced with the minimal set of operations needed to create the current data set, and once this second file is ready Redis switches the two and starts appending to the new one.

    So Redis supports an interesting feature: it is able to rebuild the AOF in the background without interrupting service to clients. Whenever you issue a BGREWRITEAOF, Redis will write the shortest sequence of commands needed to rebuild the current dataset in memory. If you're using the AOF with Redis 2.2 you'll need to run BGREWRITEAOF from time to time. Since Redis 2.4 is able to trigger log rewriting automatically (see the example configuration file for more information).

    Since Redis 7.0.0, when an AOF rewrite is scheduled, the Redis parent process opens a new incremental AOF file to continue writing. The child process executes the rewrite logic and generates a new base AOF. Redis will use a temporary manifest file to track the newly generated base file and incremental file. When they are ready, Redis will perform an atomic replacement operation to make this temporary manifest file take effect. In order to avoid the problem of creating many incremental files in case of repeated failures and retries of an AOF rewrite, Redis introduces an AOF rewrite limiting mechanism to ensure that failed AOF rewrites are retried at a slower and slower rate

    日志重写

    随着写操作的执行,AOF变得越来越大。例如,如果您将计数器增加100次,那么数据集中只有一个键包含最终值,但是AOF中有100个条目。其中99项不需要重建当前状态。

    重写是完全安全的。当Redis继续添加旧文件时,一个全新的文件就会产生,而创建当前数据集所需的操作最少,一旦第二个文件准备好,Redis就会切换两个文件并开始添加新文件。

    所以Redis支持一个有趣的特性:它能够在后台重建AOF,而不会中断对客户端的服务。当你发出BGREWRITEAOF命令时,Redis会在内存中写入重建当前数据集所需的最短命令序列。如果你在Redis 2.2中使用AOF,你需要不时地运行BGREWRITEAOF。由于Redis 2.4能够自动触发日志重写(更多信息请参见示例配置文件)。

    从Redis 7.0.0开始,当计划重写AOF时,Redis父进程打开一个新的增量AOF文件来继续写入。子进程执行重写逻辑并生成一个新的基本AOF。Redis将使用一个临时清单文件来跟踪新生成的基本文件和增量文件。当他们准备好了,Redis将执行一个原子替换操作,使这个临时清单文件生效。为了避免在AOF重写的重复失败和重试的情况下创建许多增量文件的问题,Redis引入了AOF重写限制机制,以确保失败的AOF重写以越来越慢的速度重试

    触发机制(注意 :同时满足,且的关系才会触发)

    官网默认配置:

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

    1 根据上次重写后的aof大小,判断当前aof大小是不是增长了1倍

    2 重写时满足的文件大小

     # Automatic rewrite of the append only file.
    # Redis is able to automatically rewrite the log file implicitly calling
    # BGREWRITEAOF when the AOF log size grows by the specified percentage.
    #
    # This is how it works: Redis remembers the size of the AOF file after the
    # latest rewrite (if no rewrite has happened since the restart, the size of
    # the AOF at startup is used).
    #
    # This base size is compared to the current size. If the current size is
    # bigger than the specified percentage, the rewrite is triggered. Also
    # you need to specify a minimal size for the AOF file to be rewritten, this
    # is useful to avoid rewriting the AOF file even if the percentage increase
    # is reached but it is still pretty small.
    #
    # Specify a percentage of zero in order to disable the automatic AOF
    # rewrite feature.
    
    auto-aof-rewrite-percentage 100
    auto-aof-rewrite-min-size 64mb
    
    
    触发方式 描述
    自动触发 满足配置文件中的选项后,Redis会记录上次重写时的AOF大小,默认配置是当AOF文件大小是上次rewrite后大小的一倍且文件大于64M时
    手动触发 客户端向服务器发送bgrewriteaof命令

    案例演示

    • 自动触发
  • 开启AOF :修改默认的appendonly no,改为 yes
  •  # appendonly no  
       appendonly yes
    
  • 重写峰值修改为1kb
  • # auto-aof-rewrite-percentage 100
    # auto-aof-rewrite-min-size 1kb
      
      auto-aof-rewrite-min-size 1kb
    
  • 关闭混合: aof-use-rdb-preamble yes 修改为 aof-use-rdb-preamble no
  • # aof-use-rdb-preamble yes 
      aof-use-rdb-preamble no
    
  • 删除之前的全部aof和rdb,清除干扰项
  •  [root@gone myredis]# pwd
    /root/myredis
    [root@gone myredis]# ls
    redis.conf
    
  • 重启redis , 连接并执行 set 命令使得aof 文件增长
  • [root@gone myredis]# redis-server redis.conf
    [root@gone myredis]# redis-cli -a 111111
    Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
    127.0.0.1:6379> set k1 v1
    OK
    127.0.0.1:6379> set k1 v11
    OK
    127.0.0.1:6379> set k1 v111
    OK
    127.0.0.1:6379> set k1 v11111111111
    OK
    127.0.0.1:6379> set k1 v11111111111111111111111111111111111111111111111111111
    OK
    127.0.0.1:6379> set k1 v1111111111111111111111111111111111111111111111111111111
    OK
    127.0.0.1:6379> set k1 v111111111111111111111111111111111111111111111111111111122
    OK
    127.0.0.1:6379> set k1 v111111111111111111111111111111111111111111111111111111122333
    OK
    127.0.0.1:6379> set k1 v11111111111111111111111111111111111111111111111111111112233333333
    OK
    127.0.0.1:6379> set k1 v1111111111111111111111111111111111111111111111111111111223333333344444444444444
    OK
    127.0.0.1:6379> set k1 v111111111111111111111111111111111111111111111111111111122333333334444444444444455555555555555555555555555555555555555555555555555555555555555
    OK
    127.0.0.1:6379> set k1 v1111112222223333334444455555
    OK
    127.0.0.1:6379> set k1 v11111122222233333344444555556666
    OK
    127.0.0.1:6379> set k1 v111111222222333333444445555566667777
    OK
    
      
    --- 查看 aof 文件: 每一次的查看对应上面每一次set命令的执行
    [root@gone appendonlydir]# ll
    total 4
    -rw-r--r--. 1 root root  0 Aug 15 22:54 appendonly.aof.1.base.aof
    -rw-r--r--. 1 root root  0 Aug 15 22:54 appendonly.aof.1.incr.aof
    -rw-r--r--. 1 root root 88 Aug 15 22:54 appendonly.aof.manifest
    [root@gone appendonlydir]# ll
    total 8
    -rw-r--r--. 1 root root  0 Aug 15 22:54 appendonly.aof.1.base.aof
    -rw-r--r--. 1 root root 82 Aug 15 22:55 appendonly.aof.1.incr.aof
    -rw-r--r--. 1 root root 88 Aug 15 22:54 appendonly.aof.manifest
    [root@gone appendonlydir]# ll
    total 8
    -rw-r--r--. 1 root root   0 Aug 15 22:54 appendonly.aof.1.base.aof
    -rw-r--r--. 1 root root 113 Aug 15 22:55 appendonly.aof.1.incr.aof
    -rw-r--r--. 1 root root  88 Aug 15 22:54 appendonly.aof.manifest
    [root@gone appendonlydir]# ll
    total 8
    -rw-r--r--. 1 root root   0 Aug 15 22:54 appendonly.aof.1.base.aof
    -rw-r--r--. 1 root root 153 Aug 15 22:56 appendonly.aof.1.incr.aof
    -rw-r--r--. 1 root root  88 Aug 15 22:54 appendonly.aof.manifest
    [root@gone appendonlydir]# ll
    total 8
    -rw-r--r--. 1 root root   0 Aug 15 22:54 appendonly.aof.1.base.aof
    -rw-r--r--. 1 root root 235 Aug 15 22:56 appendonly.aof.1.incr.aof
    -rw-r--r--. 1 root root  88 Aug 15 22:54 appendonly.aof.manifest
    [root@gone appendonlydir]# ll
    total 8
    -rw-r--r--. 1 root root   0 Aug 15 22:54 appendonly.aof.1.base.aof
    -rw-r--r--. 1 root root 319 Aug 15 22:56 appendonly.aof.1.incr.aof
    -rw-r--r--. 1 root root  88 Aug 15 22:54 appendonly.aof.manifest
    [root@gone appendonlydir]# ll
    total 8
    -rw-r--r--. 1 root root   0 Aug 15 22:54 appendonly.aof.1.base.aof
    -rw-r--r--. 1 root root 405 Aug 15 22:56 appendonly.aof.1.incr.aof
    -rw-r--r--. 1 root root  88 Aug 15 22:54 appendonly.aof.manifest
    [root@gone appendonlydir]# ll
    total 8
    -rw-r--r--. 1 root root   0 Aug 15 22:54 appendonly.aof.1.base.aof
    -rw-r--r--. 1 root root 494 Aug 15 22:56 appendonly.aof.1.incr.aof
    -rw-r--r--. 1 root root  88 Aug 15 22:54 appendonly.aof.manifest
    [root@gone appendonlydir]# ll
    total 8
    -rw-r--r--. 1 root root   0 Aug 15 22:54 appendonly.aof.1.base.aof
    -rw-r--r--. 1 root root 588 Aug 15 22:56 appendonly.aof.1.incr.aof
    -rw-r--r--. 1 root root  88 Aug 15 22:54 appendonly.aof.manifest
    [root@gone appendonlydir]# ll
    total 8
    -rw-r--r--. 1 root root   0 Aug 15 22:54 appendonly.aof.1.base.aof
    -rw-r--r--. 1 root root 696 Aug 15 22:57 appendonly.aof.1.incr.aof
    -rw-r--r--. 1 root root  88 Aug 15 22:54 appendonly.aof.manifest
    [root@gone appendonlydir]# ll
    total 8
    -rw-r--r--. 1 root root   0 Aug 15 22:54 appendonly.aof.1.base.aof
    -rw-r--r--. 1 root root 867 Aug 15 22:57 appendonly.aof.1.incr.aof
    -rw-r--r--. 1 root root  88 Aug 15 22:54 appendonly.aof.manifest
    [root@gone appendonlydir]# ll
    total 8
    -rw-r--r--. 1 root root   0 Aug 15 22:54 appendonly.aof.1.base.aof
    -rw-r--r--. 1 root root 924 Aug 15 22:57 appendonly.aof.1.incr.aof
    -rw-r--r--. 1 root root  88 Aug 15 22:54 appendonly.aof.manifest
    [root@gone appendonlydir]# ll
    total 8
    -rw-r--r--. 1 root root   0 Aug 15 22:54 appendonly.aof.1.base.aof
    -rw-r--r--. 1 root root 985 Aug 15 22:57 appendonly.aof.1.incr.aof
    -rw-r--r--. 1 root root  88 Aug 15 22:54 appendonly.aof.manifest
    [root@gone appendonlydir]# ll
    total 8
    -rw-r--r--. 1 root root 88 Aug 15 22:57 appendonly.aof.2.base.aof
    -rw-r--r--. 1 root root  0 Aug 15 22:57 appendonly.aof.2.incr.aof
    -rw-r--r--. 1 root root 88 Aug 15 22:57 appendonly.aof.manifest
    

    可以看到 appendonly.aof.1.incr.aof 文件随着 set 命令执行增长,达到 1kb(1024 byte)后就触发了重写机制。当AOF重写瘦身完成后,会将 appendonly.aof.1.incr.aof 删除(因为是历史数据了) ,并生成瘦身后的文件 appendonly.aof.2.base.aof ,base 文件保留了最小数据集指令,incr 文件开始重新记录并增长

    查看 appendonly.aof.2.base.aof

    [root@gone appendonlydir]# cat appendonly.aof.2.base.aof 
    *2
    $6
    SELECT
    $1
    0
    *3
    $3
    SET
    $2
    k1
    $37
    v111111222222333333444445555566667777
    
    
    • 手动触发
  • 停掉 redis 服务并清空所有的 aof 文件

  • 127.0.0.1:6379> shutdown
    not connected> exit
    [root@gone myredis]# ll
    total 108
    drwxr-xr-x. 2 root root    103 Aug 15 22:57 appendonlydir
    -rw-r--r--. 1 root root 106774 Aug 15 22:47 redis.conf
    [root@gone myredis]# rm -rf appendonlydir/
    [root@gone myredis]# ll
    total 108
    -rw-r--r--. 1 root root 106774 Aug 15 22:47 redis.conf
    
  • 连接redis 后执行 下面三条 set 指令
  • 127.0.0.1:6379> keys *
    (empty array)
    127.0.0.1:6379> set k1 v1
    OK
    127.0.0.1:6379> set k1 v22
    OK
    127.0.0.1:6379> set k3 v33
    OK
    
  • 查看 appendonly.aof.1.incr.aof (此时文件大小是112字节)
  • [root@gone appendonlydir]# ll
    total 8
    -rw-r--r--. 1 root root   0 Aug 15 23:14 appendonly.aof.1.base.aof
    -rw-r--r--. 1 root root 112 Aug 15 23:15 appendonly.aof.1.incr.aof
    -rw-r--r--. 1 root root  88 Aug 15 23:14 appendonly.aof.manifest
    [root@gone appendonlydir]# cat appendonly.aof.1.incr.aof
    *2
    $6
    SELECT
    $1
    0
    *3
    $3
    set
    $2
    k1
    $2
    v1
    *3
    $3
    set
    $2
    k1
    $3
    v22
    *3
    $3
    set
    $2
    k3
    $3
    v33
    
  • 执行 bgrewriteaof命令
  • 127.0.0.1:6379> bgrewriteaof
    Background append only file rewriting started
    
  • 再次查看 appendonly.aof 文件,可以看到是已经生成了新的aof 文件:appendonly.aof.2.base.aof 和 appendonly.aof.2.incr.aof ,并且大小已经减到88字节了 ,cat 瘦身后的文件 appendonly.aof.2.base.aof
  • [root@gone appendonlydir]# ll
    total 8
    -rw-r--r--. 1 root root 83 Aug 15 23:19 appendonly.aof.2.base.aof
    -rw-r--r--. 1 root root  0 Aug 15 23:19 appendonly.aof.2.incr.aof
    -rw-r--r--. 1 root root 88 Aug 15 23:19 appendonly.aof.manifest
    [root@gone appendonlydir]# cat appendonly.aof.2.base.aof
    *2
    $6
    SELECT
    $1
    0
    *3
    $3
    SET
    $2
    k3
    $3
    v33
    *3
    $3
    SET
    $2
    k1
    $3
    v22
    
    • 结论:也就是说AOF文件重写并不是对原文件进行重新整理,而是直接读取服务器现有的键值对,然后用一条命令去代替之前记录这个键值对的多条命令,生成一个新的文件后去替换原来的AOF文件。 AOF文件重写触发机制:通过 redis.conf配置文件中的 auto-aof-rewrite-percentage:默认值为100,以及auto-aof-rewrite-min-size: 64mb配置,也就是说默认Redis会记录上次重写时的AOF大小,默认配置是当AOF文件大小是上次rewrite后大小的一倍且文件大于64M时触发

    重写原理

  • 在重写开始前,redis会创建一个“重写子进程”,这个子进程会读取现有的AOF文件,并将其包含的指令进行分析压缩并写入到一个临时文件中。
  • 与此同时,主进程会将新接收到的写指令一边累积到内存缓冲区中,一边继续写入到原有的AOF文件中,这样做是保证原有的AOF文件的可用性,避免在重写过程中出现意外。
  • 当“重写子进程”完成重写工作后,它会给父进程发一个信号,父进程收到信号后就会将内存中缓存的写指令追加到新AOF文件中
  • 当追加结束后,redis就会用新AOF文件来代替旧AOF文件,之后再有新的写指令,就都会追加到新的AOF文件中
  • 重写aof文件的操作,并没有读取旧的aof文件,而是将整个内存中的数据库内容用命令的方式重写了一个新的aof文件,这点和快照有点类似
  • AOF优化配置项

    28.AOF三种写回策略.jpg

    AOF总结

    52.AOF小总结.jpg

    RDB-AOF混合持久化

    官网建议

    同时开启 RDB 和 AOF 这两种持久化
    image.png

    AOF+RDB 混合持久化

    同时开启时数据恢复加载流程

    如下图所示:aof 文件和 rdb 文件同时存在时,只会加载 aof 文件,不会加载 rdb

    这样设计的原因:在这种情况下,当redis重启的时候会优先载入AOF文件来恢复原始的数据,因为在通常情况下AOF文件保存的数据集要比RDB文件保存的数据集要完整。

    image.png

    RDB的数据不实时,同时使用两者时服务器重启也只会找AOF文件。那要不要只使用AOF呢?

    作者建议不要,因为RDB更适合用于备份数据库(AOF在不断变化不好备份),留着rdb作为一个万一的手段。同时开启结合了RDB和AOF的优点,既能快速加载又能避免丢失过多的数据。

    混合持久化开启配置

    1 开启混合方式设置

    设置aof-use-rdb-preamble的值为 yes   yes表示开启,设置为no表示禁用

    aof-use-rdb-preamble yes
    

    2 RDB+AOF的混合方式---------> 结论:RDB镜像做全量持久化,AOF做增量持久化

    先使用RDB进行快照存储,然后使用AOF持久化记录所有的写操作,当重写策略满足或手动触发重写的时候,将最新的数据存储为新的RDB记录。这样的话,重启服务的时候会从RDB和AOF两部分恢复数据,既保证了数据完整性,又提高了恢复数据的性能。简单来说:混合持久化方式产生的文件一部分是RDB格式,一部分是AOF格式。----AOF包括了RDB头部+AOF混写。前提是必须要开启AOF

    纯缓存模式

    同时关闭 RDB 和 AOF

    禁用 RDB

    redis.conf文件中 放开 save "" 配置。

    save ""    
    

    在关闭rdb持久i话的情况下,仍然可以使用save 和bgsave 命令生成rdb 文件

    禁用AOF

    redis.conf 文件中配置 appendonly no

    appendonly no
    

    禁用AOF持久化模式下,我们仍然可以使用命令bgrewriteaof生成AOF文件

    相关文章

    JavaScript2024新功能:Object.groupBy、正则表达式v标志
    PHP trim 函数对多字节字符的使用和限制
    新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
    使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
    为React 19做准备:WordPress 6.6用户指南
    如何删除WordPress中的所有评论

    发布评论