4. Redis的配置文件以及持久化

Posted 来自东方地灵殿的小提琴手

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了4. Redis的配置文件以及持久化相关的知识,希望对你有一定的参考价值。

配置文件

Redis最大的一个特点就是它的配置文件行数非常多,加上注释大概一千三四百行,里面有大量的配置可以供我们进行设置。其实关于Redis的配置我们之前也提到过,比如:开启多线程、设置线程数、数据结构内部存储元素的数量限制等等,那么下面我们就来介绍一下Redis配置文件中一些其它的常见配置项。

不过提到了配置文件,这里再提一个命令,叫做config,是专门获取当前Redis配置项的。

127.0.0.1:6379> config get requirepass
1) "requirepass"
2) ""
127.0.0.1:6379> config get dir
1) "dir"
2) "/data"
127.0.0.1:6379> 

config get requirepass查看密码,这里是没有密码的。config get dir查看启动路径,docker是在/data下面启动的redis-server。既然有get,那就有set。

127.0.0.1:6379> config set requirepass 123456
OK  # 设置密码,一旦设置立即生效
127.0.0.1:6379> auth 12345  # 验证
(error) WRONGPASS invalid username-password pair
127.0.0.1:6379> auth 123456
OK
127.0.0.1:6379> 

下面我们来介绍配置文件,首先根据功能的不同,我们可以将Redis的配置文件分为以下几个部分,我们分别来介绍,当然Redis内部就是这么分的。

units

# 1k => 1000 bytes
# 1kb => 1024 bytes
# 1m => 1000000 bytes
# 1mb => 1024*1024 bytes
# 1g => 1000000000 bytes
# 1gb => 1024*1024*1024 bytes

里面定义了一些基本单位,而且大小写不敏感。

includes

# include /path/to/local.conf
# include /path/to/other.conf

可以将配置写在其他地方,然后include进来,就跟编程语言里面的模块一样,如果都写在一个文件里面,会比较多,因此可以通过导入的方式

network

# 默认本地连接,如果想支持其他机器连接的话,那么把127.0.0.1改成0.0.0.0
bind 127.0.0.1

# 保护模式,为了让其他机器连接,我们会改成no
protected-mode yes

监听端口
port 6379

#设置tcp的backlog,backlog其实是一个连接队列,backlog队列总和=未完成三次握手队列+已完成三次握手队列
# 在高并发环境下你需要一个高backlog值来避免慢客户端连接问题,注意linux内核会将这个值减小到
# /proc/sys/net/core/somaxconn的值,所以需要增大somaxconn和tcp_max_syn_backlog两个值来达到想要的结果
tcp-backlog 511

# 当客户端N秒没有活动,那么关闭连接,0表示禁用该功能,一直保持连接
timeout 0

# 如果是redis集群,那么每隔300秒发送一个信息,告诉主节点自己还活着。
tcp-keepalive 300

因此可以看到network是和网络连接相关的。

general

# 是否是以守护进程方式启动,默认是no,但是一般我们会改成yes,也就是让redis后台启动
daemonize no

# redis的pid管道文件
pidfile /var/run/redis_6379.pid

# 日志级别:debug、verbose、notice、warning,级别越高,打印的信息越少。
# 刚开发会选择debug,会打印详细日志,上线之后选择notice或者warning
loglevel notice

# 日志名字
logfile ""

# 是否把日志输出到系统日志里面,默认是不输出
# syslog-enabled no

# 指定日志文件标识,这里是redis,所以就是redis.log
# syslog-ident redis

# 指定syslog设备,值可以是user或者local0到local7
# syslog-facility local0

# redis数据库的数量,默认是16个,0-15
databases 16

# 总是显示logo
always-show-logo yes

这部分对应的是一些通用的配置。

SECURITY

# 设置密码,一旦设置,再使用redis-cli连接的时候就需要指定密码了
# 否则进去之后无法执行命令,可以使用redis-cli -a password,但是这样密码就暴露在终端中
# 尽管能连接,但是redis提示你不安全。当然我们还可以进去之后通过auth password来设置
# requirepass foobared

CLIENT

# 设置客户端的最大连接数量,默认是10000
# maxclients 10000

MEMORY MANAGEMENT

# 最大内存
# maxmemory <bytes>

# 当你的内存达到极限的时候,肯定要清除缓存,那么你要选择哪种策略
# volatile-lru:使用LRU(最近最少使用)策略移除keys,只针对过期的keys
# allkeys-lru:使用LRU(最近最少使用)策略移除keys
# volatile-lfu:使用LFU(最近最不常使用)策略移除keys,只针对过期的keys
# allkeys-lru:使用LFU(最近最不常使用)策略移除keys
# volatile-random:随机移除一个过期的key
# allkeys-random:随机移除一个任意key
# volatile-ttl:移除ttl值(过期时间)最少的key,即最快要过期的key
# noeviction:不移除任意key,仅仅在写操作的时候返回一个error

# 默认是noeviction
# maxmemory-policy noeviction

# LRU和LFU都并非精确的算法,而是估算值,因此你可以设置样本的大小,默认是5个
# maxmemory-samples 5

# 从节点是否忽略maxmemory配置,针对redis集群,并且是从redis 5开始才有这个配置
# replica-ignore-maxmemory yes

以上就是一些我们经常使用的配置,当然还有一部分与持久化有关的配置,我们会在后面介绍持久化的时候说。

Redis的持久化

Redis的一大特点就是可以将数据持久化,说白了就是将内存中的数据写入到磁盘保证不丢失,并且还能将数据从磁盘加载到内存。我们之前的操作都是基于内存,因此性能很高,然而一旦关闭程序,那么数据就丢失了。因此我们需要在指定的时间间隔内将内存的数据快照写入到磁盘,也就是行话讲的Snapshot快照,它恢复时是将快照文件直接写入到内存里面。

这也是 Redis 和 Memcached 的主要区别之一,因为 Memcached 不具备持久化功能。

而数据持久化,Redis为我们提供了以下几种方式:

  • 快照方式(RDB, Redis DataBase)将某一个时刻的内存数据,以二进制的方式写入磁盘;
  • 文件追加方式(AOF, Append Only File),记录所有的操作命令,并以文本的形式追加到文件中;
  • 混合持久化方式,Redis 4.0 之后新增的方式,混合持久化是结合了 RDB 和 AOF 的优点,在写入的时候,先把当前的数据以 RDB 的形式写入文件的开头,再将后续的操作命令以 AOF 的格式存入文件,这样既能保证 Redis 重启时的速度,又能减低数据丢失的风险。

因为每种持久化方案,都有特定的使用场景,我们分别介绍。

RDB

RDB(Redis DataBase)是将某一个时刻的内存快照(Snapshot),以二进制的方式写入磁盘的过程。

而触发RDB的方式也分为两种:一类是手动触发,另一类是自动触发。

1)手动触发

手动触发持久化的操作有两个: savebgsave ,它们主要区别体现在:是否阻塞 Redis 主线程的执行。

1. save命令

在客户端中执行 save 命令,就会触发 Redis 的持久化,但同时也会使 Redis 处于阻塞状态,直到 RDB 持久化完成,才会响应其他客户端发来的命令,所以在生产环境一定要慎用

root@da649abb5e8f:/data# ls -l dump.rdb 
-rw-r--r-- 1 redis redis 4490 Jul 13 06:18 dump.rdb
root@da649abb5e8f:/data# redis-cli
127.0.0.1:6379> save 
OK
127.0.0.1:6379> exit
root@da649abb5e8f:/data# ls -l dump.rdb 
-rw-r--r-- 1 redis redis 4490 Jul 13 07:57 dump.rdb
root@da649abb5e8f:/data# 

查看时间,显示06:18,当然这个时间并不是我机器上的时间,然后进入Redis客户端,执行save,然后退出查看,发现时间已经变了。说明我们成功触发了RDB持久化。save执行命令的流程如图所示:

2. bgsave命令

bgsave(background save)为后台保存, 它和 save 命令最大的区别就是 bgsave 会 fork() 一个子进程来执行持久化,整个过程中只有在 fork() 子进程时有短暂的阻塞,当子进程被创建之后,Redis 的主进程就可以响应其他客户端的请求了,相对于整个流程都阻塞的 save 命令来说,显然 bgsave 命令更适合我们使用。

127.0.0.1:6379> bgsave
Background saving started  # 提示开始后台保存
127.0.0.1:6379> 

bgsave执行命令的流程如图所示:

2)自动触发

说完手动触发之后,再来看看自动触发,关于自动触发的条件我们是可以在配置文件中进行配置的。

1. save m n

save m n 是指在 m 秒内,如果有 n 个键发生改变,则自动触发持久化。 参数 m 和 n 可以在 Redis 的配置文件中找到,例如,save 60 1 则表明在 60 秒内,至少有一个键发生改变,就会触发 RDB 持久化。 自动触发持久化,本质是 Redis 通过判断,如果满足设置的触发条件,自动执行一次 bgsave 命令。 注意:当设置多个 save m n 命令时,满足任意一个条件都会触发持久化。 例如,我们设置了以下两个 save m n 命令:

save 60 10
save 600 1

当 60s 内如果有 10 次 Redis 键值发生改变,就会触发持久化;如果 60s 内 Redis 的键值改变次数少于 10 次,那么 Redis 就会判断 600s 内,Redis 的键值是否至少被修改了一次,如果满足则会触发持久化。

2. flushall

flushall 命令用于清空 Redis 数据库,在生产环境下一定慎用,当 Redis 执行了 flushall 命令之后,则会触发自动持久化,把 RDB 文件清空。

3. 主从同步触发

在 Redis 主从复制中,当从节点执行全量复制操作时,主节点会执行 bgsave 命令,并将 RDB 文件发送给从节点,该过程会自动触发 Redis 持久化。

RDB配置说明

合理的设置 RDB 的配置,可以保障 Redis 高效且稳定的运行,下面一起来看 RDB 的配置项都有哪些?

################################ SNAPSHOTTING  ################################
# 如果满足以下策略,就会将数据同步到磁盘
# 900秒内有1次修改、300秒内有10次修改、60秒内有10000次修改
# 任何一个条件满足,都会将文件写入到磁盘上,当然这数值我们是可以修改的
# 如果想立刻备份,那么直接在命令行输入save即可,会立刻备份,此时会处于阻塞状态,其他所有命令都会阻塞
# 也可以输入bgsave命令进行备份,和save不同的是,bgsave是在后台异步进行快照。
# 并且还可以通过lastsave命令获取最后一次成功执行快照的时间
save 900 1
save 300 10
save 60 10000

# 当快照操作出错时停止写数据到磁盘,这样后面写操作均会失败。
# 比如内存4GB,但是当前主进程使用的3GB
# 那么将数据写入磁盘、fork一份主进程的时候就又需要额外的3GB,显然内存不够了,因此保存到硬盘的数据也就失败了
# 为了不影响后续写操作,可以将该项值改为no
stop-writes-on-bgsave-error yes

# 是否压缩,默认是yes,采用lzf方式压缩。
# 如果不想消耗CPU性能来进行文件压缩的话,可以设置为no,缺点是需要更多的空间来存储文件
rdbcompression yes

# 对rdb数据进行校验, 表示表示写入文件和读取文件时是否开启 RDB 文件检查
# 检查是否有无损坏,如果在启动是检查发现损坏,则停止启动。
# 这个过程耗费CPU资源,会大概增加10%的性能损耗,默认为yes
rdbchecksum yes

# rdb文件名,默认是rdb,并且也是默认开启rdb持久化
# 如果把上面所有的save给注释掉,那么就相当于关闭rdb
dbfilename dump.rdb

# 路径,这里的路径,如果你不单独指定,那么默认是redis的启动路径
# 也就是你是在哪个目录下启动的redis-server,那么dir就是哪里
# 但同时这也是rdb文件的所在路径,比如我是在/root下面执行的redis-server,那么dir就是/root,同时rdb文件的路径也是/root/dump.rdb
dir ./

Redis 中可以使用命令查询当前配置参数。查询命令的格式为:config get xxx ,例如,想要获取 RDB 文件的存储名称设置,可以使用 config get dbfilename ,执行效果如下:

127.0.0.1:6379> config get dbfilename
1) "dbfilename"
2) "dump.rdb"

设置 RDB 的配置,可以通过以下两种方式:

  • 1. 手动修改Redis配置文件
  • 2. 使用命令行设置,config set dir "/usr/data"就是修改RDB文件的存储命令

注意:手动修改 Redis 配置文件的方式是全局生效的,即重启 Redis 服务器设置参数也不会丢失,而使用命令修改的方式,在 Redis 重启之后就会丢失。但手动修改 Redis 配置文件想要立即生效需要重启 Redis 服务器,而命令的方式则不需要重启 Redis 服务器。

Redis 的配置文件位于 Redis 安装目录的根路径下,默认名称为 redis.conf。

RDB 文件恢复

当 Redis 服务器启动时,如果 Redis 根目录存在 RDB 文件 dump.rdb,Redis 就会自动加载 RDB 文件恢复持久化数据。 如果根目录没有 dump.rdb 文件,请先将 dump.rdb 文件移动到 Redis 的根目录。当然Redis 在启动时有日志信息,会显示是否加载了 RDB 文件。

Redis 服务器在载入 RDB 文件期间,会一直处于阻塞状态,直到载入工作完成为止。

RDB优缺点

1)RDB 优点

  • RDB 的内容为二进制的数据,占用内存更小,更紧凑,更适合做为备份文件;
  • RDB 对灾难恢复非常有用,它是一个紧凑的文件,可以更快的传输到远程服务器进行 Redis 服务恢复;
  • RDB 可以更大程度的提高 Redis 的运行速度,因为每次持久化时 Redis 主进程都会 fork() 一个子进程,进行数据持久化到磁盘,Redis 主进程并不会执行磁盘 I/O 等操作;
  • 与后面介绍的 AOF 格式的文件相比,RDB 文件可以更快的重启。

2)RDB 缺点

  • 因为 RDB 只能保存某个时间间隔的数据,如果中途 Redis 服务被意外终止了,则会丢失一段时间内的 Redis 数据;
  • RDB 需要经常 fork() 才能使用子进程将其持久化在磁盘上。如果数据集很大,fork() 可能很耗时,并且如果数据集很大且 CPU 性能不佳,则可能导致 Redis 停止为客户端服务几毫秒甚至一秒钟。

禁用持久化

禁用持久化可以提高 Redis 的执行效率,如果对数据丢失不敏感的情况下,可以在连接客户端的情况下,执行 config set save "" 命令即可禁用 Redis 的持久化。

总结

我们知道了RDB 持久化分为手动触发和自动触发两种方式,它的优点是存储文件小,Redis 启动时恢复数据比较快,缺点是有丢失数据的风险。RDB 文件的恢复也很简单,只需要把 RDB 文件放到 Redis 的根目录,在 Redis 启动时就会自动加载并恢复数据。

AOF

Redis的持久化除了RDB还有AOF,我们知道RDB是保存某个时间间隔的数据,而且要达到某个触发条件才会进行持久化。但是这样有一个风险,那就是在持久化之前机器突然宕机了,那么这个时间间隔内的最新数据就会丢失。

可能会操作 Redis 服务意外终止的条件:

  • 安装 Redis 的机器停止运行,蓝屏或者系统崩溃;
  • 安装 Redis 的机器出现电源故障,例如突然断电;
  • 使用 kill -9 Redis_PID 等。

那么如何解决以上的这些问题呢?Redis 为我们提供了另一种持久化的方案——AOF。

AOF(Append Only File)中文是附加到文件,顾名思义 AOF 可以把 Redis 每个键值对操作都记录到文件(appendonly.aof)中。

持久化查询和设置

1)查询 AOF 启动状态

使用 config get appendonly 命令,如下图所示:

127.0.0.1:6379> config get appendonly
1) "appendonly"
2) "no"
127.0.0.1:6379> 

第一行为AOF文件的名称,第二行表示AOF的启动状态:yes表示启动、no表示为启动。

2)开启 AOF 持久化

Redis 默认是关闭 AOF 持久化的,想要开启 AOF 持久化,有以下两种方式:

  • 通过命令行的方式;
  • 通过修改配置文件的方式(redis.conf)

分别看两种方式的实现:

1. 命令行启动 AOF,使用 config set appendonly yes 命令,如下所示:

127.0.0.1:6379> config set appendonly yes
OK
127.0.0.1:6379> config get appendonly
1) "appendonly"
2) "yes"
127.0.0.1:6379> 

命令行启动 AOF 的优缺点:命令行启动的优点是无需重启 Redis 服务,缺点是如果 Redis 服务重启,则之前使用命令行设置的配置就会失效。

2. 配置文件启动 AOF

Redis 的配置文件在它的根目录下的 redis.conf 文件中,获取 Redis 的根目录可以使用命令 config get dir 获取。

127.0.0.1:6379> config get dir
1) "dir"
2) "/data"
127.0.0.1:6379> 

只需要在配置文件/data/redis.conf中设置 appendonly yes 即可,默认 appendonly no 表示关闭 AOF 持久化。 配置文件启动 AOF 的优缺点:修改配置文件的缺点是每次修改配置文件都要重启 Redis 服务才能生效,优点是无论重启多少次 Redis 服务,配置文件中设置的配置信息都不会失效。

触发持久化

1)自动触发

有两种情况可以自动触发 AOF 持久化,分为是:满足 AOF 设置的策略触发 和 满足 AOF 重写触发。其中,AOF 重写触发会在本文的后半部分详细介绍,这里重点来说 AOF 持久化策略都有哪些。 AOF 持久化策略,分为以下三种:

  • always:每条 Redis 操作命令都会写入磁盘,最多丢失一条数据;
  • everysec:每秒钟写入一次磁盘,最多丢失一秒的数据;
  • no:不设置写入磁盘的规则,根据当前操作系统来决定何时写入磁盘,Linux 默认 30s 写入一次数据至磁盘。

这三种配置可以在 Redis 的配置文件(redis.conf)中设置,如下代码所示:

# 开启每秒写入一次的持久化策略
appendfsync everysec

因为每次写入磁盘都会对 Redis 的性能造成一定的影响,所以要根据用户的实际情况设置相应的策略,一般设置每秒写入一次磁盘的频率就可以满足大部分的使用场景了。

2)手动触发

在客户端执行 bgrewriteaof 命令就可以手动触发 AOF 持久化,我们查看AOF文件触发的前后时间。

root@da649abb5e8f:/data# ls -l appendonly.aof 
-rw-r--r-- 1 redis redis 4490 Jul 13 14:41 appendonly.aof

root@da649abb5e8f:/data# redis-cli
127.0.0.1:6379> bgrewriteaof  # 触发AOF持久化
Background append only file rewriting started

127.0.0.1:6379> exit
root@da649abb5e8f:/data# ls -l appendonly.aof 
-rw-r--r-- 1 redis redis 4490 Jul 13 14:50 appendonly.aof
root@da649abb5e8f:/data# 

可以看出执行完 bgrewriteaof 命令之后,AOF 持久化就会被触发。

AOF 文件重写

AOF 是通过记录 Redis 的执行命令来持久化(保存)数据的,所以随着时间的流逝 AOF 文件会越来越多,这样不仅增加了服务器的存储压力,也会造成 Redis 重启速度变慢,为了解决这个问题 Redis 提供了 AOF 重写的功能。

1)什么是AOF重写?

AOF 重写指的是它会直接读取 Redis 服务器当前的状态,并压缩保存为 AOF 文件。例如,我们增加了一个计数器,并对它做了 99 次修改,如果不做 AOF 重写的话,那么持久化文件中就会有 100 条记录执行命令的信息,而 AOF 重写之后,之后记录一条此计数器最终的结果信息,这样就去除了所有的无效信息。

2)AOF重写实现

触发 AOF 文件重写,要满足两个条件,这两个条件也是配置在 Redis 配置文件中的,它们分别是:

  • auto-aof-rewrite-min-size:允许 AOF 重写的最小文件容量,默认是 64mb。
  • auto-aof-rewrite-percentage:AOF 文件重写的大小比例,默认值是 100,表示 100%,也就是只有当前 AOF 文件,比最后一次(上次)的 AOF 文件大一倍时,才会启动 AOF 文件重写。

查询 auto-aof-rewrite-min-size 和 auto-aof-rewrite-percentage 的值,可使用 config get xxx 命令,如下所示:

127.0.0.1:6379> config get auto-aof-rewrite-min-size
1) "auto-aof-rewrite-min-size"
2) "67108864"
127.0.0.1:6379> config get auto-aof-rewrite-percentage
1) "auto-aof-rewrite-percentage"
2) "100"
127.0.0.1:6379> 

只有同时满足 auto-aof-rewrite-min-size 和 auto-aof-rewrite-percentage 设置的条件,才会触发 AOF 文件重写。

3)AOF重写流程

AOF 文件重写是生成一个全新的文件,并把当前数据的最少操作命令保存到新文件上,当把所有的数据都保存至新文件之后,Redis 会交换两个文件,并把最新的持久化操作命令追加到新文件上。

配置说明

合理的设置 AOF 的配置,可以保障 Redis 高效且稳定的运行,以下是 AOF 的全部配置信息和说明。

AOF 的配置参数在 Redis 的配置文件中,也就是 Redis 根路径下的 redis.conf 文件中,配置参数和说明如下:

############################## APPEND ONLY MODE ###############################
# aof意思是append only file,我们看到默认是no关闭的,因此持久化默认使用rdb
appendonly no


# 正如dump.rdb,aof方式持久化也就一个文件名,默认叫appendonly.aof
appendfilename "appendonly.aof"
# 另外aof和rdb持久化方式是可以同时指定的,后面会说
# 那我们知道当redis启动的时候,会加载文件,读进缓存。
# 如果既有rdb文件又有aof文件,那redis会读取哪个呢?实际上会读取aof文件
# 如果aof被人乱搞了一通,那么会发现redis无法启动,启动了也连接不上。
# 这个时候有两种办法,一种是删除相应的aof文件,但是这样数据就丢了
# 还有一种方法,就是redis-server所在路径(一般是/usr/local/bin)中,有一个redis-check-aof
# 通过redis-check-aof --fix appendonly.aof可以进行修复,同理还有一个redis-check-rdb,用来修复rdb文件。


# appendfsync:同步策略,支持三个参数
# 1.always:同步持久化,每次发生数据变更会被立即记录到磁盘,并完成同步,性能较差但是数据完整性较好
# 2.everysec:默认设置,异步操作,每秒记录,并完成同步,如果1s内宕机,只丢失1s内的数据
# 3.no:always和everysec都会和磁盘保持同步,而no表示写入aof文件但并不等待磁盘同步,也就是写入缓冲区,Linux中30s后自动同步到磁盘
# appendfsync always
appendfsync everysec
# appendfsync no


# 子进程重写aof文件时是否使用appendfsync,用默认no即可,保证数据安全性
# 如果使用yes,那么相当于将appendfsync设置为no,注意这个参数前面有一个no了,设置为yes,才表示不使用appendfsync,这个参数设计的有点绕
# 设置为yes,说明不会写入磁盘,只是写入缓冲区,因此不会造成阻塞,但如果redis挂掉,在linux系统默认设置下,会丢失30s的数据
# 使用no,表示使用appendfsync,表示子进程会写入到磁盘,这时候和主进程之间会有资源上的竞争,因为都要操作磁盘,所以会有阻塞的情况,但是不会丢失数据。
no-appendfsync-on-rewrite no


# aof文件增长比例,指当前aof文件比上次重写的增长比例大小。
# aof重写即在aof文件在一定大小之后,重新将整个内存写到aof文件当中,以反映最新的状态(相当于bgsave)。
# 这样就避免了,aof文件过大而实际内存数据小的问题(频繁修改数据问题).
auto-aof-rewrite-percentage 100


# aof文件重写最小的文件大小,即最开始aof文件必须要达到这个文件时才触发,后面的每次重写就不会根据这个变量了(根据上一次重写完成之后的大小)
# 此变量仅初始化启动redis有效.如果是redis恢复时,则lastSize等于初始aof文件大小.
auto-aof-rewrite-min-size 64mb


# 指redis在恢复时,会忽略最后一条可能存在问题的指令。
# 默认值yes。即在aof写入时,可能存在指令写错的问题(突然断电,写了一半)
# 这种情况下,yes会继续,而no会直接恢复失败,用户必须手动修复 AOF 文件才能正常启动 Redis 服务。
aof-load-truncated yes


# 4.0开始允许使用RDB-AOF混合持久化的方式,结合了两者的优点,通过 aof-use-rdb-preamble 配置项可以打开混合开关
aof-use-rdb-preamble yes

其中比较重要的是 appendfsync 参数,用它来设置 AOF 的持久化策略,可以选择按时间间隔或者操作次数来存储 AOF 文件,这个参数的三个值在文章开头有说明,这里就不再复述了。

数据恢复

1)正常数据恢复

正常情况下,只要开启了 AOF 持久化,并且提供了正常的 appendonly.aof 文件,在 Redis 启动时就会自定加载 AOF 文件并启动。

默认情况下 appendonly.aof 文件保存在 Redis 的根目录下。

持久化文件加载规则

  • 如果只开启了 AOF 持久化,Redis 启动时只会加载 AOF 文件(appendonly.aof),进行数据恢复;
  • 如果只开启了 RDB 持久化,Redis 启动时只会加载 RDB 文件(dump.rdb),进行数据恢复;
  • 如果同时开启了 RDB 和 AOF 持久化,Redis 启动时一样只会加载 AOF 文件(appendonly.aof),进行数据恢复。

在 AOF 开启的情况下,即使 AOF 文件不存在,只有 RDB 文件,也不会加载 RDB 文件。

2)简单异常数据恢复

在 AOF 写入文件时如果服务器崩溃,或者是 AOF 存储已满的情况下,AOF 的最后一条命令可能被截断,这就是异常的 AOF 文件。

在 AOF 文件异常的情况下,如果为修改 Redis 的配置文件,也就是使用 aof-load-truncated等于 yes 的配置,Redis 在启动时会忽略最后一条命令,并顺利启动 Redis。

3)复杂异常数据恢复

AOF 文件可能出现更糟糕的情况,当 AOF 文件不仅被截断,而且中间的命令也被破坏,这个时候再启动 Redis 会提示错误信息并中止运行,错误信息如下:

* Reading the remaining AOF tail...
# Bad file format reading the append only file: make a backup of your AOF file, 
# then use ./redis-check-aof --fix <filename>

出现此类问题的解决方案如下:

  • 首先使用 AOF 修复工具,检测出现的问题,在命令行中输入 redis-check-aof 命令,它会跳转到出现问题的命令行,这个时候可以尝试手动修复此文件;
  • 如果无法手动修复,我们可以使用 redis-check-aof --fix 自动修复 AOF 异常文件,不过执行此命令,可能会导致异常部分至文件末尾的数据全部被丢弃。

AOF 优缺点

AOF优点:

  • AOF 持久化保存的数据更加完整,AOF 提供了三种保存策略:每次操作保存、每秒钟保存一次、跟随系统的持久化策略保存,其中每秒保存一次,从数据的安全性和性能两方面考虑是一个不错的选择,也是 AOF 默认的策略,即使发生了意外情况,最多只会丢失 1s 钟的数据;
  • AOF 采用的是命令追加的写入方式,所以不会出现文件损坏的问题,即使由于某些意外原因,导致了最后操作的持久化数据写入了一半,也可以通过 redis-check-aof 工具轻松的修复;
  • AOF 持久化文件,非常容易理解和解析,它是把所有 Redis 键值操作命令,以文件的方式存入了磁盘。即使不小心使用 flushall 命令删除了所有键值信息,只要使用 AOF 文件,删除最后的 flushall 命令,重启 Redis 即可恢复之前误删的数据。

AOF缺点:

  • 对于相同的数据集来说,AOF 文件要大于 RDB 文件;
  • 在 Redis 负载比较高的情况下,RDB 比 AOF 性能更好;
  • RDB 使用快照的形式来持久化整个 Redis 数据,而 AOF 只是将每次执行的命令追加到 AOF 文件中,因此从理论上说,RDB 比 AOF 更健壮。

总结

AOF 保存数据更加完整,它可以记录每次 Redis 的键值变化,或者是选择每秒保存一次数据。AOF 的持久化文件更加易读,但相比与二进制的 RDB 来说,所占的存储空间也越大,为了解决这个问题,AOF 提供自动化重写机制,最大程度的减少了 AOF 占用空间大的问题。同时 AOF 也提供了很方便的异常文件恢复命令: redis-check-aof --fix ,为使用 AOF 提供了很好的保障。

混合持久化

我们说Redis的持久化有RDB和AOF,这两者的优缺点我们再来简单复习一下:

同步策略:

  • RDB:可以指定某个时间内发生多少个命令进行同步。比如一分钟内发生了两次命令,就进行一次同步。
  • AOF:每秒同步或者每次发生命令后同步。

存储内容:

  • RDB:存储的是redis里面具体的值。
  • RDB:存储的是执行的写操作命令。

优点:

  • RDB:1.存储数据到文件中会进行压缩,文件体积比AOF小。2.因为存储的是redis具体的值,并且会经过压缩,因此在恢复的时候比AOF块,并且适合远距离传输。3.非常适用于备份。
  • AOF:1.AOF的策略是每秒钟或者每次发生写操作的时候都会同步,因此即使服务器发生故障,也只会丢失一秒的数据。2.AOF存储的是redis命令并且直接追加到aof文件后面,因此每次备份的时候只要添加新的数据进去就可以了。3.如果AOF文件比较大,那么redis会进行重写,只保留最小的命令集合。

缺点:

  • RDB:1. RDB是在多少时间内发生了多少写操作的时候就会发出同步机制,因为采用压缩机制,RDB在同步的时候都重新保存整个redis中的数据,因此一般会设置在最少5分钟内才保存一次数据。在这种情况下,一旦服务器故障,就会造成5分钟的数据丢失。2.在数据保存进RDB的时候,redis会fork出一个子进程用来同步,在数据流比较大的时候可能会非常耗时。
  • AOF:1.AOF文件因为没有压缩,因此体积比RDB大。2.AOF是在每秒或者每次写操作都进行备份,因此如果并发量比较大,效率会有点低。3.因为存储的是命令,因此在灾难恢复的时候redis会重新运行AOF文件里的命令,速度不及RDB。

所以为了能同时使用 RDB 和 AOF 各种的优点,Redis 4.0 之后新增了混合持久化的方式。

在开启混合持久化的情况下,AOF 重写时会把 Redis 的持久化数据,以 RDB 的格式写入到 AOF 文件的开头,之后的数据再以 AOF 的格式化追加的文件的末尾。

开启混合持久化

查询是否开启混合持久化可以使用 config get aof-use-rdb-preamble 命令:

127.0.0.1:6379> config get aof-use-rdb-preamble
1) "aof-use-rdb-preamble"
2) "yes"
127.0.0.1:6379> 

其中 yes 表示已经开启混合持久化,no 表示关闭,Redis 5.0 默认值为 yes。 如果是其他版本的 Redis 首先需要检查一下,是否已经开启了混合持久化,如果关闭的情况下,可以通过以下两种方式开启:

  • 通过命令行开启:config set aof-use-rdb-preamble yes
  • 通过修改 Redis 配置文件开启,将配置文件中的aof-use-rdb-preamble no 改成 aof-use-rdb-preamble yes。

数据恢复和源码解析

混合持久化的数据恢复和 AOF 持久化过程是一样的,只需要把 appendonly.aof 放到 Redis 的根目录,在 Redis 启动时,只要开启了 AOF 持久化,Redis 就会自动加载并恢复数据。

1)混合持久化的加载流程

  • 1. 判断是否开启 AOF 持久化,开启继续执行后续流程,未开启执行加载 RDB 文件的流程;
  • 2. 判断 appendonly.aof 文件是否存在,文件存在则执行后续流程;
  • 3. 判断 AOF 文件开头是 RDB 的格式, 先加载 RDB 内容再加载剩余的 AOF 内容;
  • 4. 判断 AOF 文件开头不是 RDB 的格式,直接以 AOF 格式加载整个文件。

2)源码解析

Redis 判断 AOF 文件的开头是否是 RDB 格式的,是通过关键字 REDIS 判断的,RDB 文件的开头一定是 REDIS 关键字开头的,判断源码在 Redis 的 src/aof.c 中,核心代码如下所示:

char sig[5]; /* "REDIS" */
if (fread(sig,1,5,fp) != 5 || memcmp(sig,"REDIS",5) != 0) {
    // AOF 文件开头非 RDB 格式,非混合持久化文件
    if (fseek(fp,0,SEEK_SET) == -1) goto readerr;
} else {
    /* RDB preamble. Pass loading the RDB functions. */
    rio rdb;

    serverLog(LL_NOTICE,"Reading RDB preamble from AOF file...");
    if (fseek(fp,0,SEEK_SET) == -1) goto readerr;
    rioInitWithFile(&rdb,fp);
    // AOF 文件开头是 RDB 格式,先加载 RDB 再加载 AOF
    if (rdbLoadRio(&rdb,NULL,1) != C_OK) {
        serverLog(LL_WARNING,"Error reading the RDB preamble of the AOF file, AOF loading aborted");
        goto readerr;
    } else {
        serverLog(LL_NOTICE,"Reading the remaining AOF tail...");
    }
}
// 加载 AOF 格式的数据

可以看出 Redis 是通过判断 AOF 文件的开头是否是 REDIS 关键字,来确定此文件是否为混合持久化文件的。

AOF 格式的开头是 *,而 RDB 格式的开头是 REDIS。

优缺点

混合持久化优点:

  • 混合持久化结合了 RDB 和 AOF 持久化的优点,开头为 RDB 的格式,使得 Redis 可以更快的启动,同时结合 AOF 的优点,有减低了大量数据丢失的风险。

混合持久化缺点:

  • AOF 文件中添加了 RDB 格式的内容,使得 AOF 文件的可读性变得很差;
  • 兼容性差,如果开启混合持久化,那么此混合持久化 AOF 文件,就不能用在 Redis 4.0 之前版本了。

持久化最佳实践

持久化虽然保证了数据不丢失,但同时拖慢了 Redis 的运行速度,那怎么更合理的使用 Redis 的持久化功能呢? Redis 持久化的最佳实践可从以下几个方面考虑。

1)控制持久化开关

使用者可根据实际的业务情况考虑,如果对数据的丢失不敏感的情况下,可考虑关闭 Redis 的持久化,这样所以的键值操作都在内存中,就可以保证最高效率的运行 Redis 了。 持久化关闭操作:

  • 关闭 RDB 持久化,使用命令:config set save ""
  • 关闭 AOF 和 混合持久化,使用命令:config set appendonly no

2)主从部署

使用主从部署,一台用于响应主业务,一台用于数据持久化,这样就可能让 Redis 更加高效的运行。

3)使用混合持久化

混合持久化结合了 RDB 和 AOF 的优点,Redis 5.0 默认是开启的。

4)使用配置更高的机器

Redis 对 CPU 的要求并不高,反而是对内存和磁盘的要求很高(也正因为如此Redis在4.0之前才是单线程的,当然现在也默认是单线程),因为 Redis 大部分时候都在做读写操作,使用更多的内存和更快的磁盘,对 Redis 性能的提高非常有帮助。

以上是关于4. Redis的配置文件以及持久化的主要内容,如果未能解决你的问题,请参考以下文章

docker配置redis持久化

微信小程序的介绍和开发环境需求以及基本配置

redis的三种启动方式

Redis笔记4-持久化方案

15_redis replication以及master持久化对主从架构的安全意义

redis的几种启动方式(Linux)