介绍

Redis是一个内存数据库,数据保存在内存中,但是我们都知道内存的数据变化是很快的,也容易发生丢失。Redis提供了持久化的机制,分别是RDB(Redis DataBase)和AOF(Append Only File)。

既然redis的数据可以保存在磁盘上,那么这个流程是什么样的呢? 主要有下面五个过程:

  • (1)客户端向服务端发送写操作(数据在客户端的内存中)。
  • (2)数据库服务端接收到写请求的数据(数据在服务端的内存中)。
  • (3)服务端调用write这个系统调用,将数据往磁盘上写(数据在系统内存的缓冲区中)。
  • (4)操作系统将缓冲区中的数据转移到磁盘控制器上(数据在磁盘缓存中)。
  • (5)磁盘控制器将数据写到磁盘的物理介质中(数据真正落到磁盘上)。

redis设置存储方式 redis如何存储_数据库

RDB方式

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

  • 在指定的时间间隔,执行数据集的时间点快照
  • 实现类似照片记录效果的方式,就是把某一时刻的数据和状态以文件的形式写到磁盘上,也就是快照。这样一来即使故障宕机,快照文件也不会丢失,数据的可靠性也就得到了保证。
  • 这个快照文件就称为RDB文件(dump.rdb),其中,RDB就是Redis DataBase的缩写。
  • 将内存数据全部保存到磁盘dump.rdb文加中

RDB在恢复时,将硬盘中的快照文件直接读取到内存中。

Redis的数据都在内存中,保存备份时执行的是全量快照,即将内存中的所有数据都记录到磁盘中。

自动触发

配置方法

redis默认的配置文件redis.conf,其中有一个自动触发RDB持久化的配置:

Redis7的。
################################ SNAPSHOTTING  ###########################        #####
    413 
    414 # Save the DB to disk.
    415 #
    416 # save <seconds> <changes> [<seconds> <changes> ...]
    417 #
    418 # Redis will save the DB if the given number of seconds elapsed and it
    419 # surpassed the given number of write operations against the DB.
    420 #
    421 # Snapshotting can be completely disabled with a single empty string argum        ent
    422 # as in following example:
    423 #
    424 # save ""
    425 #
    426 # Unless specified otherwise, by default Redis will save the DB:
    427 #   * After 3600 seconds (an hour) if at least 1 change was performed
    428 #   * After 300 seconds (5 minutes) if at least 100 changes were performed
    429 #   * After 60 seconds if at least 10000 changes were performed
    430 #
    431 # You can set these explicitly by uncommenting the following line.
    432 #
    433 # save 3600 1 300 100 60 10000

说明:

save 3600 1 300 100 60 10000表示一小时内有一次修改,5分钟内有至少100次修改,1分钟内至少有10000次修改,就会自动触发RDB持久化。

自动触发

  • 修改save配置为5秒钟2次修改
# save 3600 1 300 100 60 10000
save 5 2
  • 修改dump文件保存路径
# 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 ./
dir /opt/redis-7.0.10/myredis/dumpfiles
# 注意该目录一定要存在,不会自动创建
[root@192 myredis]# ll
total 108
drwxr-xr-x. 2 root root      6 Apr 23 06:23 dumpfiles
  • 修改dump文件名字
# The filename where to dump the DB
dbfilename dump6379.rdb
  • 查看修改后的值
[root@192 myredis]# redis-cli -a 1
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:6379> config get dir
1) "dir"
2) "/opt/redis-7.0.10/myredis/dumpfiles"
  • 5秒钟执行两次set命令,然后查看dumpfiles目录下是否生成文件
127.0.0.1:6379> set k1 v1
OK
127.0.0.1:6379> set k2 v2
OK

[root@192 dumpfiles]# ll
total 0
[root@192 dumpfiles]# ll
total 4
-rw-r--r--. 1 root root 108 Apr 23 06:30 dump6379.rdb

可知,dumpfiles目录下生成了rdb文件。

  • 执行一次set后,等待5秒钟后,查看rdb文件大小
127.0.0.1:6379> set k3 v3
OK

[root@192 dumpfiles]# ll
total 4
-rw-r--r--. 1 root root 108 Apr 23 06:30 dump6379.rdb

可见,rdb文件大小没有任何变化。

  • 5秒后,继续执行set命令,然后查看rdb文件大小
127.0.0.1:6379> set k4 v4
OK

[root@192 dumpfiles]# ll
total 4
-rw-r--r--. 1 root root 122 Apr 23 06:34 dump6379.rdb

可见,文件变大,存储成功。

备份恢复

1、将备份文件修改名字,如下:

ot@192 dumpfiles]# ll
total 4
-rw-r--r--. 1 root root 122 Apr 23 06:34 dump6379.rdb.bak

2、使用flushdb命令,清空redis,并查看dumpfiles目录。

127.0.0.1:6379> keys *
1) "k4"
2) "k3"
3) "k2"
4) "k1"
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> keys *
(empty array)

[root@192 dumpfiles]# ll
total 8
-rw-r--r--. 1 root root  89 Apr 23 06:37 dump6379.rdb
-rw-r--r--. 1 root root 122 Apr 23 06:34 dump6379.rdb.bak

可以看到,dumpfiles目录下又生成了rdb文件,说明当执行类似flushdb/flushall/shutdown这样的提交命令时,redis也会自动触发RDB持久化

3、shutdown退出后,重新进入redis。

127.0.0.1:6379> shutdown
not connected> quit
[root@192 myredis]# redis-server redis7.conf
[root@192 myredis]# redis-cli -a 1
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:6379> keys *
(empty array)

可见,没有恢复。

4、将之前的RDB文件恢复

[root@192 dumpfiles]# ll
total 8
-rw-r--r--. 1 root root  89 Apr 23 06:42 dump6379.rdb
-rw-r--r--. 1 root root 122 Apr 23 06:34 dump6379.rdb.bak
[root@192 dumpfiles]# rm -rf dump6379.rdb
[root@192 dumpfiles]# mv dump6379.rdb.bak dump6379.rdb
[root@192 dumpfiles]# ll
total 4
-rw-r--r--. 1 root root 122 Apr 23 06:34 dump6379.rdb

5、重新进入redis

[root@192 myredis]# redis-server redis7.conf
[root@192 myredis]# redis-cli -a 1
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:6379> keys *
1) "k2"
2) "k1"
3) "k3"
4) "k4"
127.0.0.1:6379>

可以看到已经恢复了。

注意:不可以将备份文件dump.rdb和生产redis服务器放在同一台机器,必须分开各自存储,以防生产机物理损坏之后备份文件丢失。

手动触发

save命令(不建议使用)

save命令是一个同步操作,执行该命令后,RDB持久化是在主进程中进行的,这样会阻塞当前redis服务,直到RDB持久化完成后,客户端才能正常连接redis服务。

redis设置存储方式 redis如何存储_数据_02

bgsave命令(默认)

bgsave命令是对save命令的一个优化,是一个异步操作。执行该命令后,redis主进程会通过fork操作创建一个子进程,RDB持久化是由子进程操作,完成后自动结束。这个过程中,主进程不阻塞,可以继续接收客户端的访问。因此,redis内部所有涉及RDB持久化的操作都是采用的bgsave方式,save命令基本已经废弃。

redis设置存储方式 redis如何存储_数据_03

127.0.0.1:6379> set k5 v5
OK
[root@192 dumpfiles]# ll
total 4
-rw-r--r--. 1 root root 122 Apr 23 06:34 dump6379.rdb

127.0.0.1:6379> bgsave
Background saving started
[root@192 dumpfiles]# ll
total 4
-rw-r--r--. 1 root root 129 Apr 23 06:54 dump6379.rdb

127.0.0.1:6379> lastsave
(integer) 1682258078
# LASTSAVE 命令用于查看 BGSAVE 命令是否执行成功。

redis设置存储方式 redis如何存储_redis_04

优点

RDB 数据持久化适合于大规模的数据恢复,并且还原速度快,如果对数据的完整性不是特别敏感(可能存在最后一次丢失的情况),那么 RDB 持久化方式非常合适。

缺点

在 RDB 持久化的过程中,子进程会把 Redis 的所有数据都保存到新建的 dump.rdb 文件中,这是一个既消耗资源又浪费时间的操作。因此 Redis 服务器不能过于频繁地创建 rdb 文件,否则会严重影响服务器的性能。

RDB 持久化的最大不足之处在于,最后一次持久化的数据可能会出现丢失的情况。可以这样理解,在持久化进行过程中,服务器突然宕机了,这时存储的数据可能并不完整,比如子进程已经生成了 rdb 文件,但是主进程还没来得及用它覆盖掉原来的旧 rdb 文件,这样就把最后一次持久化的数据丢失了。

如果数据集比较大的时候,fork可以能比较耗时,造成服务器在一段时间内停止处理客户端的请求。

数据丢失案例

1、正常录入k1k2,并查看RDB文件

127.0.0.1:6379> set k1 v1
OK
127.0.0.1:6379> set k2 v2
OK
[root@192 dumpfiles]# ll
total 4
-rw-r--r--. 1 root root 108 Apr 23 07:02 dump6379.rdb

2、录入k3,然后kill -9杀掉redis服务,并查看RDB文件

127.0.0.1:6379> set k3 v3
OK
127.0.0.1:6379> keys *
1) "k2"
2) "k1"
3) "k3"

[root@192 dumpfiles]# ps -ef | grep redis
root      35233      1  0 06:44 ?        00:00:00 redis-server *:6379
root      35238   2815  0 06:44 pts/0    00:00:00 redis-cli -a 1
root      35563  34926  0 07:02 pts/1    00:00:00 grep --color=auto redis
[root@192 dumpfiles]# kill -9 35233
[root@192 dumpfiles]# ll
total 4
-rw-r--r--. 1 root root 108 Apr 23 07:02 dump6379.rdb #大小没有变化

127.0.0.1:6379> keys * #执行该命令时,显示已经被杀掉了。
Error: Server closed the connection
not connected> quit

可以看到,执行完set k3 v3后,在内存中存在,但是没有保存到RDB文件中,此时杀掉redis服务后,RDB文件大小并没有变化。

3、重新进入redis,查看

[root@192 myredis]# redis-server redis7.conf
[root@192 myredis]# redis-cli -a 1
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:6379> get k1
"v1"
127.0.0.1:6379> get k2
"v2"
127.0.0.1:6379> get k3
(nil)

可以看到,k3并没有值,也就是最后一次操作丢失了

检查和修复RDB文件

当RDB文件遇到状况时,需要进行检查并且修复。

[root@192 ~]# cd /usr/local/bin
[root@192 bin]# ll
total 74708
-rwxr-xr-x. 1 root root 54453847 Apr 15 18:24 docker-compose
-rwxr-xr-x. 1 root root  5197776 Apr 16 00:39 redis-benchmark
lrwxrwxrwx. 1 root root       12 Apr 16 00:39 redis-check-aof -> redis-server
lrwxrwxrwx. 1 root root       12 Apr 16 00:39 `redis-check-rdb -> redis-server`
-rwxr-xr-x. 1 root root  5411112 Apr 16 00:39 redis-cli
lrwxrwxrwx. 1 root root       12 Apr 16 00:39 redis-sentinel -> redis-server
-rwxr-xr-x. 1 root root 11429256 Apr 16 00:39 redis-server

执行如下命令进行检查和修复:

redis-check-rdb /opt/redis-7.0.10/myredis/dumpfiles/dump6379.rdb

[root@192 bin]# redis-check-rdb /opt/redis-7.0.10/myredis/dumpfiles/dump6379.rdb 
[offset 0] Checking RDB file /opt/redis-7.0.10/myredis/dumpfiles/dump6379.rdb
[offset 27] AUX FIELD redis-ver = '7.0.10'
[offset 41] AUX FIELD redis-bits = '64'
[offset 53] AUX FIELD ctime = '1682258526'
[offset 68] AUX FIELD used-mem = '1054608'
[offset 80] AUX FIELD aof-base = '0'
[offset 82] Selecting DB ID 0
[offset 108] Checksum OK
[offset 108] \o/ RDB looks OK! \o/
[info] 2 keys read
[info] 0 expires
[info] 0 already expired

禁用快照

动态停止RDB保存规则

redis-cli config set save ""

快照禁用

在配置文件中,按照如下修改:

# Snapshotting can be completely disabled with a single empty string argument
# as in following example:
#
# save ""

其他配置项

配置项

作用

stop-writes-on-bgsave-error

默认yes,配置成no,表示不在乎数据不一致,在快照写入失败时,确保redis继续接受新的写请求

rdbcompression

默认yes,对于存储到磁盘中的快照,是否进行压缩存储。

rdbchecksum

默认yes,在存储快照后,使用CRC64算法进行数据校验,会增加约10%的性能消耗。

rdb-del-sync-files

默认no,在没有持久性的情况下删除复制中使用的RDB文件启用。

AOF方式

全量备份总是耗时的,Redis为我们提供了一种更加高效的持久化方式,即AOF(appendonlyfile)。此方式工作机制很简单,redis会将每一个收到的写命令都通过write函数追加到aof文件中。默认情况下Redis没有开启AOF方式的持久化。在redis服务器重启时,会读取并加载aof文件,达到恢复数据的目的。

开启AOF持久化后,每执行一条会更改Redis中的数据的命令,Redis就会将该命令写入硬盘中的AOF文件,这一过程显然会降低Redis的性能,但大部分情况下这个影响是能够接受的,另外使用较快的硬盘可以提高AOF的性能。

工作流程

redis设置存储方式 redis如何存储_数据库_05

1、Client是命令的来源,会有多个源头以及请求命令

2、在这些命令到达Redis Server之后,不是直接写入AOF文件,将这些命令存放到AOF缓存中进行保存,当这些命令达到一定量之后写入磁盘,避免频繁的磁盘IO操作。

3、AOF缓存会根据AOF缓存区同步文件的三种写回策略将命令写入磁盘上的AOF文件。

4、随着写入AOF内容的增加,为避免文件膨胀,会根据规则进行命令的合并(AOF重写),从而起到AOF文件压缩的目的。

5、当Redis Server服务器重启的时候,将从AOF文件载入数据。

写回策略

appendfsync always

客户端对redis服务器的每次写操作都写入AOF日志文件。这种方式是最安全的方式,但每次写操作都进行一次磁盘IO,非常影响redis的性能,所以一般不使用这种方式。

appendfsync everysec

每秒刷新一次缓冲区中的数据到AOF文件。这种方式是redis默认使用的策略,是考虑数据完整性和性能的这种方案,理论上,这种方式最多只会丢失1秒内的数据。

appendfsync no

redis服务器不负责将数据写入到AOF文件中,而是直接交给操作系统去判断什么时候写入。这种方式是最快的一种策略,但丢失数据的可能性非常大,因此也是不推荐使用的。

配置

配置文件:redis.conf

# 可以通过修改redis.conf配置文件中的appendonly参数开启
appendonly yes

# Redis6:AOF文件的保存位置和RDB文件的位置相同,都是通过dir参数设置的。
dir /opt/redis-7.0.10/myredis
# Redis7:在dir只下生成一个appendonlydir目录,存放aof文件
dir /opt/redis-7.0.10/myredis
appenddirname "appendonlydir"

# 默认的文件名是appendonly.aof,可以通过appendfilename参数修改
# - 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

# 写回策略
# appendfsync always
appendfsync everysec
# appendfsync no

正常恢复

1、启动redis

127.0.0.1:6379> SHUTDOWN
not connected> quit
[root@192 myredis]# redis-server redis7.conf
[root@192 myredis]# redis-cli -a 1
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:6379> 

[root@192 myredis]# ll
total 108
drwxr-xr-x. 2 root root    103 Apr 23 07:51 appendonlydir
drwxr-xr-x. 2 root root     26 Apr 23 07:51 dumpfiles
-rw-r--r--. 1 root root 106580 Apr 23 07:51 redis7.conf
[root@192 myredis]# cd appendonlydir/
[root@192 appendonlydir]# ll
total 8
-rw-r--r--. 1 root root 89 Apr 23 07:51 appendonly.aof.1.base.rdb
-rw-r--r--. 1 root root  0 Apr 23 07:51 appendonly.aof.1.incr.aof
-rw-r--r--. 1 root root 88 Apr 23 07:51 appendonly.aof.manifest

2、正常录入k1,k2,k3,查看aof文件并备份,并删除RDB文件排除rdb的影响。

127.0.0.1:6379> set k1 v1
OK
127.0.0.1:6379> set k2 v2
OK

[root@192 myredis]# ll
total 112
drwxr-xr-x. 2 root root    103 Apr 23 07:51 appendonlydir
-rw-r--r--. 1 root root    108 Apr 23 07:53 dump6379.rdb
drwxr-xr-x. 2 root root     26 Apr 23 07:51 dumpfiles
-rw-r--r--. 1 root root 106580 Apr 23 07:51 redis7.conf
[root@192 myredis]# rm -rf dump6379.rdb 
[root@192 myredis]# rm -rf dumpfiles/
[root@192 myredis]# ll
total 108
drwxr-xr-x. 2 root root    103 Apr 23 07:51 appendonlydir
-rw-r--r--. 1 root root 106580 Apr 23 07:51 redis7.conf
[root@192 myredis]# cp -a appendonlydir/ appendonlydir_bak
[root@192 myredis]# ll
total 108
drwxr-xr-x. 2 root root    103 Apr 23 07:51 appendonlydir
drwxr-xr-x. 2 root root    103 Apr 23 07:51 appendonlydir_bak
-rw-r--r--. 1 root root 106580 Apr 23 07:51 redis7.conf
[root@192 myredis]# cd appendonlydir/
[root@192 appendonlydir]# ll
total 12
-rw-r--r--. 1 root root 89 Apr 23 07:51 appendonly.aof.1.base.rdb
-rw-r--r--. 1 root root 81 Apr 23 07:53 appendonly.aof.1.incr.aof
-rw-r--r--. 1 root root 88 Apr 23 07:51 appendonly.aof.manifest

3、执行flushdb清空,然后删除rdb文件,并进行恢复。

# 执行flushdb
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> SHUTDOWN
not connected> quit
# 删除rdb文件,排除rdb的干扰
[root@192 myredis]# ll
total 112
drwxr-xr-x. 2 root root    103 Apr 23 07:51 appendonlydir
drwxr-xr-x. 2 root root    103 Apr 23 07:51 appendonlydir_bak
-rw-r--r--. 1 root root     89 Apr 23 08:02 dump6379.rdb
-rw-r--r--. 1 root root 106580 Apr 23 07:51 redis7.conf
[root@192 myredis]# rm -rf dump6379.rdb 
[root@192 myredis]# cd appendonlydir
[root@192 appendonlydir]# ll
total 12
-rw-r--r--. 1 root root 89 Apr 23 07:51 appendonly.aof.1.base.rdb
-rw-r--r--. 1 root root 98 Apr 23 08:02 appendonly.aof.1.incr.aof
-rw-r--r--. 1 root root 88 Apr 23 07:51 appendonly.aof.manifest
# 重启redis,恢复
[root@192 myredis]# redis-server redis7.conf
[root@192 myredis]# redis-cli -a 1
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:6379> keys *
(empty array)

可见,flushdb也是写操作命令,也会写入到aof文件中,导致恢复时会恢复到flushdb的时候。

4、将bak目录恢复,重新恢复

[root@192 myredis]# mv appendonlydir_bak/ appendonlydir
[root@192 myredis]# ll
total 108
drwxr-xr-x. 2 root root    103 Apr 23 07:51 appendonlydir
-rw-r--r--. 1 root root 106580 Apr 23 07:51 redis7.conf

[root@192 myredis]# redis-server redis7.conf
[root@192 myredis]# redis-cli -a 1
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:6379> keys *
1) "k1"
2) "k2"

成功。

异常恢复

当redis写命令写了一半,redis服务突然down了,这时,aof文件中就会出现一些问题。

1、手动写坏aof文件内容

$3
set
$2
k4
$2
v4
sadfasdfasdfdasfsadfsdafdsfdgfdhdfh

2、重新启动redis

[root@192 myredis]# redis-server redis7.conf
[root@192 myredis]# redis-cli -a 1
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
Could not connect to Redis at 127.0.0.1:6379: Connection refused
not connected>

3、修复aof文件

redis-check-aof --fix appendonly.aof.1.incr.aof

[root@192 appendonlydir]# redis-check-aof appendonly.aof.1.incr.aof 
Start checking Old-Style AOF
AOF appendonly.aof.1.incr.aof format error
AOF analyzed: filename=appendonly.aof.1.incr.aof, size=170, ok_up_to=133, ok_up_to_line=32, diff=37
AOF appendonly.aof.1.incr.aof is not valid. Use the --fix option to try fixing it.
[root@192 appendonlydir]# redis-check-aof --fix appendonly.aof.1.incr.aof 
Start checking Old-Style AOF
AOF appendonly.aof.1.incr.aof format error
AOF analyzed: filename=appendonly.aof.1.incr.aof, size=170, ok_up_to=133, ok_up_to_line=32, diff=37
This will shrink the AOF appendonly.aof.1.incr.aof from 170 bytes, with 37 bytes, to 133 bytes
Continue? [y/N]: y
Successfully truncated AOF appendonly.aof.1.incr.aof

4、重启redis

[root@192 myredis]# redis-server redis7.conf
[root@192 myredis]# redis-cli -a 1
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:6379> keys *
1) "k4"
2) "k1"
3) "k2"

成功。

优点

redis设置存储方式 redis如何存储_redis设置存储方式_06

缺点

redis设置存储方式 redis如何存储_redis设置存储方式_07

文件重写

既然AOF是通过日志追加的方式来存储redis的写指令,那么当我们对同一个key做多次写操作时,就会产生大量针对同一个key操作的日志指令,导致AOF文件会变得非常大,恢复数据的时候会变得非常慢。因此,redis提供了重写机制来解决这个问题。redis通过重写AOF文件,保存的只是恢复数据的最小指令集。

手动触发重写

bgrewriteaof

示例
127.0.0.1:6379> set k1 11111111111111111111111111111111111
OK
127.0.0.1:6379> set k1 v22
OK
127.0.0.1:6379> BGREWRITEAOF
Background append only file rewriting started

[root@192 appendonlydir]# ll
total 8
-rw-r--r--. 1 root root 53 Apr 23 08:40 appendonly.aof.3.base.aof
-rw-r--r--. 1 root root  0 Apr 23 08:40 appendonly.aof.3.incr.aof
-rw-r--r--. 1 root root 88 Apr 23 08:40 appendonly.aof.manifest

[root@192 appendonlydir]# vi appendonly.aof.3.base.aof 
*2
$6
SELECT
$1
0
*3
$3
SET
$2
k1
$3
v22

自动触发重写

配置文件:redis.conf

auto-aof-rewrite-percentage 100 #当文件的大小达到原先文件大小(上次重写后的文件大小,如果没有重写过,那就是redis服务启动时的文件大小)的两倍。
auto-aof-rewrite-min-size 64mb #文件重写的最小文件大小,即当AOF文件低于64mb时,不会触发重写。【同时满足】
示例

1、修改配置,并关闭混合

auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 1kb
aof-use-rdb-preamble no

2、去除干扰项

[root@192 myredis]# ll
total 112
drwxr-xr-x. 2 root root    103 Apr 23 08:13 appendonlydir
-rw-r--r--. 1 root root    115 Apr 23 08:27 dump6379.rdb
-rw-r--r--. 1 root root 106578 Apr 23 08:30 redis7.conf
[root@192 myredis]# rm -rf dump6379.rdb 
[root@192 myredis]# cd appendonlydir/
[root@192 appendonlydir]# ll
total 12
-rw-r--r--. 1 root root  89 Apr 23 07:51 appendonly.aof.1.base.rdb
-rw-r--r--. 1 root root 133 Apr 23 08:16 appendonly.aof.1.incr.aof
-rw-r--r--. 1 root root  88 Apr 23 07:51 appendonly.aof.manifest
[root@192 appendonlydir]# rm -rf *
[root@192 appendonlydir]# ll
total 0

3、重新启动redis,查看aof文件

[root@192 myredis]# redis-server redis7.conf
[root@192 myredis]# redis-cli -a 1
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:6379> 

[root@192 appendonlydir]# ll
total 4
-rw-r--r--. 1 root root  0 Apr 23 08:31 appendonly.aof.1.base.aof
-rw-r--r--. 1 root root  0 Apr 23 08:31 appendonly.aof.1.incr.aof
-rw-r--r--. 1 root root 88 Apr 23 08:31 appendonly.aof.manifest

4、执行set k1 1查看aof文件是否正常。

127.0.0.1:6379> set k1 1
OK
127.0.0.1:6379> get k1
"1"

[root@192 appendonlydir]# ll
total 8
-rw-r--r--. 1 root root  0 Apr 23 08:31 appendonly.aof.1.base.aof
-rw-r--r--. 1 root root 51 Apr 23 08:32 appendonly.aof.1.incr.aof
-rw-r--r--. 1 root root 88 Apr 23 08:31 appendonly.aof.manifest

5、重复执行set k1 111111111111111111操作,直到aof文件大小达到1024.

127.0.0.1:6379> set k1 11111111111111111111111111111111111
OK
127.0.0.1:6379> set k1 11111111111111111111111111111111111
OK
127.0.0.1:6379> set k1 11111111111111111111111111111111111
OK

[root@192 appendonlydir]# ll
total 8
-rw-r--r--. 1 root root   0 Apr 23 08:31 appendonly.aof.1.base.aof
-rw-r--r--. 1 root root 933 Apr 23 08:35 appendonly.aof.1.incr.aof
-rw-r--r--. 1 root root  88 Apr 23 08:31 appendonly.aof.manifest
[root@192 appendonlydir]# cat appendonly.aof.1.incr.aof
……
*3
$3
set
$2
k1
$35
11111111111111111111111111111111111
*3
$3
set
$2
k1
$35
11111111111111111111111111111111111

#继续执行set,查看aof文件
[root@192 appendonlydir]# ll
total 12
-rw-r--r--. 1 root root 86 Apr 23 08:36 appendonly.aof.2.base.aof
-rw-r--r--. 1 root root 86 Apr 23 08:36 appendonly.aof.2.incr.aof
-rw-r--r--. 1 root root 88 Apr 23 08:36 appendonly.aof.manifest
#可见,aof文件变成2了。

6、查看base.aof的内容

*2
$6
SELECT
$1
0
*3
$3
SET
$2
k1
$35
11111111111111111111111111111111111

只保留了最后一次的命令。

重写流程

(1)bgrewriteaof触发重写,判断是否存在bgsave或者bgrewriteaof正在执行,存在则等待其执行结束再执行;

(2)主进程fork子进程,防止主进程阻塞无法提供服务;

(3)子进程遍历Redis内存快照中数据写入临时AOF文件,同时会将新的写指令写入aof_buf和aof_rewrite_buf两个重写缓冲区,前者是为了写回旧的AOF文件,后者是为了后续刷新到临时AOF文件中,防止快照内存遍历时新的写入操作丢失;

(4)子进程结束临时AOF文件写入后,通知主进程;

(5)主进程会将上面的aof_rewirte_buf缓冲区中的数据写入到子进程生成的临时AOF文件中;

(6)主进程使用临时AOF文件替换旧AOF文件,完成整个重写过程。

redis设置存储方式 redis如何存储_数据_08

伪代码

def AOF_REWRITE(tmp_tile_name):
f = create()
# 遍历所有数据库
for db in redisServer.db:
# 如果数据库为空,那么跳过这个数据库
if db.is_empty(): continue
# 写入 SELECT 命令,用于切换数据库
f.write_command("SELECT " + db.number)
# 遍历所有键
for key in db:
# 如果键带有过期时间,并且已经过期,那么跳过这个键
if key.have_expire_time() and key.is_expired(): continue
if key.type == String:
# 用 SET key value 命令来保存字符串键
value = get_value_from_string(key)
f.("SET " + key + value)
elif key.type == List:
# 用 RPUSH key item1 item2 ... itemN 命令来保存列表键
item1, item2, ..., itemN = get_item_from_list(key)
f.("RPUSH " + key + item1 + item2 + ... + itemN)
elif key.type == Set:
# 用 SADD key member1 member2 ... memberN 命令来保存集合键
member1, member2, ..., memberN = get_member_from_set(key)
f.("SADD " + key + member1 + member2 + ... + memberN)
elif key.type == Hash:
# 用 HMSET key field1 value1 field2 value2 ... fieldN valueN 命令来保存哈希键
field1, value1, field2, value2, ..., fieldN, valueN =\
get_field_and_value_from_hash(key)
f.("HMSET " + key + field1 + value1 + field2 + value2 +\
... + fieldN + valueN)
elif key.type == SortedSet:
# 用 ZADD key score1 member1 score2 member2 ... scoreN memberN
# 命令来保存有序集键
score1, member1, score2, member2, ..., scoreN, memberN = \
get_score_and_member_from_sorted_set(key)
f.write_command("ZADD " + key + score1 + member1 + score2 + member2 +\
... + scoreN + memberN)
else:
raise_type_error()
# 如果键带有过期时间,那么用 EXPIREAT key time 命令来保存键的过期时间
if key.have_expire_time():
f.write_command("EXPIREAT " + key + key.expire_time_in_unix_timestamp())
# 关闭文件
f.close()

实际为了避免执行命令时造成客户端输入缓冲区溢出,重写程序在处理list hash set zset时,会检查键所包含的元素的个数。

如果元素的数量超过了redis.h/REDIS_AOF_REWRITE_ITEMS_PER_CMD常量的值,那么重写程序会使用多条命令来记录键的值,而不是单使用一条命令。该常量默认值是64,即每条命令设置的元素的个数是最多64个,重写程序使用多条命令实现集合键中元素数量超过64个的键。

RDB和AOF混合持久化

在同时开启RDB和AOF持久化时,重启只会加载aof文件,不会加载rdb文件。

redis设置存储方式 redis如何存储_数据库_09

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

问题:RDB的数据不实时,同时使用两者时服务器重启也只会找AOF文件。那要不要只使用AOF呢?
建议不要,因为RDB更适合用于备份数据库(AOF在不断变化不好备份),留着rdb作为一个万一的手段。

配置

开启混合方式配置

aof-use-rdb-preamble yes

yes表示开启,设置为no表示禁用。

RDB镜像做全量持久化,AOF做增量持久化。

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

同时关闭RDB和AOF

save ""

禁用rdb持久化,可以使用命令save和bgsave生成rdb文件。

appendonly no

禁用aof持久化模式,可以使用bgrewriteaof生成aof文件。