J.A.R.V.I.S

life is not just live

Redis持久化

为什么要持久化数据

由于Redis是在内存中进行存储的,当机器重启后内存里面的数据就会丢失。我们不希望这些数据是临时数据,希望它能在重启之后仍然存在,或者我们能将数据导出在其他机器上直接进行导入。这时候都需要进行持久化,将数据落盘。

持久化的方式

持久化的方式在Redis 4.x版本后有了一些区别!

持久化方式主要有两种:

  • RDB
  • AOF

RDB

在指定的时间间隔内生成数据集的时间点快照。

假如我们设定每两个小时保存一次,那么它就会每两个小时将当时的数据保存到文件中,文件是以二进制的格式保存的。

为了保证性能,在进行RDB持久化的时候,父进程在保存RDB文件时fork出一个子进程,然后子进程处理保存工作。并且为了保证数据安全,子进程先生成一个临时RDB文件,全部执行完成后再替换之前的RDB文件。

优点:

  1. 文件体积小,使用二进制存储,减少了文件的体积
  2. 使用用于备份,容灾。
  3. 性能高,fork()一个子进程来进行处理
  4. 恢复数据速度比AOF快。

缺点:

  1. 由于是定时存储,假设是两小时,如果在这期间宕机,那么中间的数据就没有保存,丢失了数据。

  2. 由于保存文件时fork()了一个子进程,如果当时数据量很大,fork()可能会非常耗时,造成服务器在一段时间内停止响应。

AOF

AOF是将对数据有修改的命令保存到文件中。

记录服务器执行的所有写操作命令,并在服务器启动时,通过重新执行这些命令来还原数据集。AOF文件中的命令全部以Redis协议的格式来保存,新命令会被追加到文件的末尾。还可以在后台对AOF文件进行重写,使得AOF文件的体积减小。

优点:

  1. 持久化时间间隔默认为每秒钟一次,这样就算发生故障也只会丢失非常少的数据。一共有三种保存策略:不保存,每秒一次,每次执行命令写入。

  2. AOF文件是一个只进行追加操作的日志文件(append only log),所以对文件写入不需要再进行寻址操作。并且即便因为某些原因未写入完整的命令,通过redis-check-aof也可以对文件进行恢复。

  3. Redis可以在AOF文件体积变得过大时,自动的在后台对AOF进行重写:重写后的新AOF文件包含了恢复当前数据集的最小命令集合(假如我们有一个计数器,执行了100次加1,我们可以将它重写为1次加100)。重写过程是安全的,开始重写后命令仍然可以写到现有的AOF文件中,即便重写过程中发生错误,现有的AOF文件也不会丢失,只是新文件未生成。而当新文件生成后,Redis就会从旧AOF文件切换到新AOF文件,并开始对新AOF文件进行追加操作。

    在创建新文件过程中可能会继续执行命令,Redis在开始重写后会开启一个缓冲区,将执行命令写到现有AOF文件和缓存区中。当新文件创建完成后,会先将缓冲区内数据写入到新AOF文件中,然后再进行替换

    – 此过程仍有疑问

  4. AOF文件有序的保存了对数据库执行的命令,这些命令以Redis协议的格式保存,因此AOF文件的内容非常容易被人读懂。当我们错误的执行一条命令后,我们可以找到未被重写的AOF文件,手动删除这条命令,然后重启后,就可以恢复到之前的状态。

缺点:

  1. 对于相同的数据集,AOF文件的体积会大于RDB文件的体积。

  2. 根据不同的保存策略,AOF的速度可能会慢与RDB。

如何开启两种持久化以及配置

RDB

手动触发:

  • SAVE:阻塞Redis的服务器线程,直到RDB文件被创建完成
  • BGSAVE:fork出一个子进程来创建RDB文件,不阻塞服务器进程,写时复制。可以通过lastsave命令来查看最近备份时间。

自动触发:

  • 根据redis.conf中的配置定时触发,用的是bgsave

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    # 备份策略
    # save ""
    save 900 1
    save 300 10
    save 60 10000

    # 备份进程出错主进程是否停止写入操作
    stop-writes-on-bgsave-error yes

    # 是否压缩rdb文件
    rdbcompression yes

    # 导入时是否检查
    rdbchecksum yes

    # 存储的文件名称
    dbfilename dump.rdb

    # 文件存储地址
    dir ./

    关于RDB的配置项主要有几个:

    • 备份策略

      如果需要关闭RDB备份,则使用save ""即可,否则使用save m n方式表示当m秒内有n条数据变动,则触发产生一次快照,即进行一次备份。

      其实从上面可以看出使用了多条save策略,当900秒内有1条数据变动就进行备份,当300秒内有10条数据变动就备份。为什么要使用多条规则呢?因为Redis中每个时段的读写请求不均衡,所以为了更好的使用,可以定制多种备份策略。

    • 子进程出错后父进程是否停止

      当备份进程出错后,主进程就停止接收新的写入操作,可以保护持久化的数据一致性问题。

    • 文件名称,文件路径

AOF

手动触发:

- 调用`BGREWRITEAOF`命令

自动触发

  • 在配置文件中开启AOF:
1
2
3
4
5
6
7
8
9
10
# 是否开启AOF
appendonly yes

# AOF文件保存的名称
appendfilename "appendonly.aof"

# 持久化的选项,分别是每次操作都进行aof操作;每秒一次;不主动执行,30秒一次,默认就是每秒1次
# appendfsync always
appendfsync everysec
# appendfsync no

通过上面的配置开启AOF持久化,并且指定文件名称,持久化策略。

关于AOF还有一些其他的配置项:

1
2
3
4
5
6
7
8
9
# 重写方式
no-appendfsync-on-rewrite no
# 重写阈值
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
# 恢复数据遇到错误时是否抛弃错误项
aof-load-truncated yes
# 重要的区别!混合持久化
aof-use-rdb-preamble yes
  • 什么时候重写

    从上面可以了解到AOF是写入的执行命令,当文件太大时就执行重写命令。那么如何定义文件太大呢?可以通过auto-aof-rewrite-percentageauto-aof-rewrite-min-size两个配置项定义。

    auto-aof-rewrite-min-size表示文件重写最小的文件大小,只有当aof文件超过这个值后才会进行触发重写,后面的重写就跟这个配置项没有关系了,这个配置项只能生效一次。

    auto-aof-rewrite-percentage文件增长比例,当前文件比上次重写的增长比例大小。即当前文件是上一次重写完成后的两倍。

  • 重写是否阻塞

    文件进行重写时,可能会有新的执行命令过来,此时是否需要阻塞服务器来等待重写完成,这个通过no-appendfsync-on-rewrite配置完成。当配置项为no是表示服务器需要阻塞,此时不能再执行更改数据的命令,直到重写完成。当数据量大了之后,重写的时间就会变长,那么此时可能会影响系统的响应时间。我们也可以将配置项设置为yes,此时的流程有不同的说法,我也还有些疑惑,后面了解清楚再更新,如果您了解这个过程,期待您的见解。

  • 恢复数据

    aof文件写入时如果命令只写入一半,此时aof文件就出现错误,当开启aof-load-truncated后如果遇到错误会抛弃这个错误继续执行,否则会抛出错误停止运行。

  • 混合持久化

    使用aof-use-rdb-preamble开启混合持久化,开启后aof文件会在重写时将此时的数据写成RDB格式,将从开始后到下一次重写之间的命令以命令格式保存到aof文件中

参考