【7.0】Redis持久化

发布时间 2023-09-10 13:45:16作者: Chimengmeng

【一】Redis持久化

【1】什么是持久化

  • redis的所有数据保存在内存中,对数据的更新将异步的保存到硬盘上
  • 持久化是指将Redis的数据保存到硬盘上,以确保数据在重启、断电等异常情况下的持久性。
  • Redis提供了三种持久化方式:RDB、AOF和混合持久化。

【2】持久化的实现方式

  • 数据库(mysql,redis,mongodb,rabbitmq,infludb,clickhose,kafak)

  • 持久化方法通常是以下两种

    • 快照:某时某刻数据的一个完成备份,

    • mysql的Dump

      • redis的RDB
    • 写日志:任何操作记录日志,要恢复数据,只要把日志重新走一遍即可

      • mysql的 Binlog

      • Hhase的 HLog

      • Redis的 AOF

(1)RDB持久化(快照方式):

  • RDB持久化是将某个时间点上的数据保存到磁盘上,并生成一个二进制的RDB文件。
  • 使用RDB持久化可以实现快速的全量恢复,适用于备份、灾难恢复等场景。
  • 配置说明:
# 开启RDB持久化
save 900 1      # 在900秒内如果至少有1个键发生改变,则触发RDB持久化操作
save 300 10     # 在300秒内如果至少有10个键发生改变,则触发RDB持久化操作
save 60 10000   # 在60秒内如果至少有10000个键发生改变,则触发RDB持久化操作

# 指定RDB文件名
dbfilename dump.rdb
  • 示例代码:
# 手动执行RDB持久化
SAVE

# 后台异步执行RDB持久化
BGSAVE
  • 场景需求分析:

    • RDB持久化适合用于备份和恢复场景,例如在Redis重启后快速恢复数据。
    • 另外,也可以基于RDB文件进行数据迁移、复制等操作。

(2)AOF持久化(写日志方式):

  • AOF持久化是将Redis的写操作以日志的形式追加到AOF文件中,恢复时重新执行AOF文件中的命令,实现数据的恢复。
  • 使用AOF持久化可以提供较高的数据安全性和可靠性,适用于要求数据不丢失的场景。
  • 配置说明:
# 开启AOF持久化
appendonly yes

# 指定AOF文件名
appendfilename "appendonly.aof"

# 指定AOF持久化策略
appendfsync always   # 每个写命令都立即同步到AOF文件,最安全但可能性能较差
appendfsync everysec # 每秒同步一次AOF文件,兼顾安全性和性能
appendfsync no       # 不主动同步AOF文件,交由操作系统自行决定同步时间,性能最好但可能丢失部分数据
  • 示例代码:
# 手动执行AOF持久化
BGREWRITEAOF
  • 场景需求分析:

    • AOF持久化适用于对数据安全性要求较高的场景,例如金融交易系统、社交媒体应用等。
    • AOF文件记录了每个写操作,可以提供更好的容灾性和数据一致性。

(3)混合持久化:

  • Redis也支持混合持久化,即同时开启RDB和AOF持久化方式。
  • 这种方式可以兼顾快速恢复和数据安全性的需求。
  • 配置示例:
# 同时开启RDB和AOF持久化
save 900 1
save 300 10
save 60 10000

appendonly yes
  • 场景需求分析:

    • 混合持久化适用于对数据可靠性和灾难恢复速度都有较高要求的场景,例如金融系统的生产环境。
  • 综上所述,根据实际应用需求选择适当的持久化方式可以提升数据的安全性和可靠性。
  • 通常情况下,可以使用RDB进行周期性全量备份,并结合AOF进行增量持久化,以实现数据的万无一失。

【二】RDB

【1】什么是RDB

  • RDB是Redis的一种持久化方式,它将数据以二进制格式保存在硬盘上。
  • RDB通过生成一个全量备份文件来实现持久化,该备份文件包含了Redis在某个时间点上的所有数据。
  • RDB文件可以在Redis重启时用于恢复数据,因为它是一个完整且紧凑的数据快照。

[image-20230416224901757](http://photo.liuqingzheng.top/2023 04 16 22 55 25 /image-20230416224901757.png)

【2】触发机制-主要三种方式

(1)save命令(同步)

  • save(同步)
    • 1 客户端执行save命令----》redis服务端----》同步创建RDB二进制文件
    • 2 会造成redis的阻塞(数据量非常大的时候)
    • 3 文件策略:如果老的RDB存在,会替换老的
    • 4 复杂度 o(n)
  • 当客户端执行save命令时,Redis服务端会阻塞所有的写命令,并在此期间创建一个RDB二进制文件。
  • 这种方式的复杂度为O(n),并且会造成Redis的阻塞,适用于需要完全阻塞Redis进行备份的场景。

(2)bgsave命令(异步)

  • bgsave(异步,Backgroud saving started)

    • 1 客户端执行save命令----》redis服务端----》异步创建RDB二进制文件(fork函数生成一个子进程(fork会阻塞reids),执行createRDB,执行成功,返回给reids消息)
    • 2 此时访问redis,会正常响应客户端
    • 3 文件策略:跟save相同,如果老的RDB存在,会替换老的
    • 4 复杂度 o(n)
  • 当客户端执行bgsave命令时,Redis服务端会异步创建一个RDB二进制文件,而不会阻塞其他的写命令。
  • bgsave使用fork函数创建一个子进程执行RDB创建操作,并在创建成功后返回消息给Redis。
  • 适用于需要实现后台持久化且不影响Redis正常响应的场景。

(3)自动触发机制

  • 自动(通过配置)
配置   seconds   changes
save   900        1
save   300        10
save   60         10000
  • 如果60s中改变了1w条数据,自动生成rdb
  • 如果300s中改变了10条数据,自动生成rdb
  • 如果900s中改变了1条数据,自动生成rdb
  • 以上三条符合任意一条,就自动生成rdb,内部使用bgsave
  • 通过配置save参数,可以实现自动触发RDB持久化。
  • 配置中的参数表示在一定时间间隔内,如果发生了指定数量的数据改变,就会自动生成RDB文件。
  • 这种方式利用了bgsave来实现异步备份,并根据数据改变情况来触发RDB持久化操作。
# # # 配置 # # # 
#配置一条
save 900 1 
#配置一条
save 300 10 
#配置一条
save 60 10000 

#rdb文件的名字,默认为dump.rdb
dbfilename dump.rdb  
#rdb文件存在当前目录
dir ./ 

#如果bgsave出现错误,是否停止写入,默认为yes
stop-writes-on-bgsave-error yes 
#采用压缩格式
rdbcompression yes 
#是否对rdb文件进行校验和检验
rdbchecksum yes 


# # # 最佳配置 # # # 
save 900 1 
save 300 10 
save 60 10000 

#以端口号作为文件名,可能一台机器上很多reids,不会乱
dbfilename dump-${port}.rdb  
#保存路径放到一个大硬盘位置目录
dir /bigdiskpath 
#出现错误停止
stop-writes-on-bgsave-error yes 
#压缩
rdbcompression yes 
#校验
rdbchecksum yes

【3】触发机制-不容忽略的方式

  • 1 全量复制
    • 没有执行save和bgsave没有添加rdb策略,还会生成rdb文件
    • 如果开启主从复制,主会自动生成rdb
  • 2 debug reload
    • debug级别的重启,不会将内存中的数据清空
  • 3 shutdown save
    • 关闭会出发rdb的生成

(1)全量复制

  • 当Redis执行全量复制(主从复制)时,如果没有执行save或bgsave命令并且没有添加配置策略,主节点会自动生成RDB文件,并传输给从节点进行数据同步。

(2)debug reload

  • 在调试级别中重新启动Redis时,不会清空内存中的数据,这意味着原有的RDB文件仍然有效,即使未执行保存操作。

(3)shutdown save

  • 当执行shutdown命令关闭Redis时,默认会触发RDB的生成,以保证数据的持久化。

【4】演示

  • redis.conf配置
save 900 1 
save 300 10 
save 60 10000 
dbfilename dump-${port}.rdb
dir /bigdiskpath
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
  • Python代码示例:
import redis

# 连接Redis服务端
r = redis.Redis(host='localhost', port=6379)

# 执行save命令
r.save()

# 执行bgsave命令
r.bgsave()

【5】场景需求分析

  • RDB持久化适用于需要进行完整数据恢复的场景,例如在Redis重启后快速恢复数据。
  • 由于save命令会阻塞Redis写操作,通常推荐使用bgsave命令进行异步持久化,以避免影响Redis的正常响应。
  • 另外,通过配置自动触发RDB持久化机制可以根据实际业务需要灵活地进行备份设置。

【三】AOF

【1】AOF介绍

  • AOF(Append-only File)是Redis持久化机制之一,用于将写入Redis的命令以日志的形式追加到文件中。
  • 客户端每写入一条命令,都记录一条日志,放到日志文件中,如果出现宕机,可以将数据完全恢复

【2】RDB问题 和 AOF的优势

(1)RDB问题

  • 耗时,耗性能:
  • 不可控,可能会丢失数据

(2)AOF的优势

  • 数据完整性
    • AOF记录了每个写入Redis的命令,因此在Redis宕机后可以通过重新执行AOF文件中的命令来完全恢复数据。
  • 灵活性
    • AOF采用追加方式记录命令,避免了需要全量数据转存的问题,对于大规模数据集非常有优势。
  • 可靠性
    • AOF文件的写入是通过操作系统的缓冲区实现的,根据配置不同,可以选择不同的同步策略,确保数据写入硬盘的可靠性。

【3】AOF的三种策略

  • 日志不是直接写到硬盘上,而是先放在缓冲区,缓冲区根据一些策略,写到硬盘上
  • 根据什么时候将数据写入硬盘的策略不同,AOF有三种同步策略:always、everysec和no

(1)always策略

  • redis–》写命令刷新的缓冲区—》每条命令fsync到硬盘—》AOF文件
  • 在每次写入命令后,会把命令刷新到缓冲区,并直接将缓冲区中的数据进行fsync操作,将数据同步到硬盘,然后再写入到AOF文件中。
  • 该策略能够保证数据的完整性,但IO开销最大。

(2)everysec策略(默认值)

  • everysec(默认值):redis——》写命令刷新的缓冲区—》每秒把缓冲区fsync到硬盘–》AOF文件
  • 每秒钟将缓冲区中的数据进行fsync同步操作,将数据写入硬盘并刷新到AOF文件中。
  • 相较于always策略,everysec策略可以减少IO开销,但会丢失一秒钟的数据。

(3)no策略

  • no:redis——》写命令刷新的缓冲区—》操作系统决定,缓冲区fsync到硬盘–》AOF文件
  • 将命令写入缓冲区后,操作系统决定何时将缓冲区的数据刷新到硬盘,然后再写入到AOF文件中。
  • 这种策略下,不会控制命令何时真正写入硬盘,可能会存在数据丢失的情况。

(4)比较

命令 always everysec no
优点 不丢失数据 每秒一次fsync,丢失1秒数据 不用管
缺点 IO开销大,一般的sata盘只有几百TPS 丢1秒数据 不可控

【4】AOF 重写

  • AOF重写是为了解决AOF文件不断增大而引入的机制。
  • 随着命令的不断写入和并发量的增加,AOF文件会越来越大,占用磁盘空间,并且对于数据恢复的速度也会产生影响。
  • AOF重写通过优化AOF文件中的命令,去除过期、无用、重复和可以优化的命令,从而减小AOF文件的大小,提高恢复速度。
  • 随着命令的逐步写入,并发量的变大, AOF文件会越来越大,通过AOF重写来解决该问题

(1)原生AOF

set hello world 
set hello java 
set hello hehe 
incr counter 
incr counter 
rpush mylist a 
rpush mylist b 
rpush mylist c 
过期数据

(2)AOF重写

set hello hehe 
set counter 2 
rpush mylist a b c

(3)小结

  • 本质就是把过期的,无用的,重复的,可以优化的命令,来优化
  • 这样可以减少磁盘占用量,加速恢复速度

【5】实现方式

  • AOF重写的实现方式是通过执行bgrewriteaof命令来触发的。
  • 这个命令会导致Redis服务fork一个子进程,在子进程中完成AOF文件的重写工作。
  • bgrewriteaof:
    • 客户端向服务端发送bgrewriteaof命令,服务端会起一个fork进程,完成AOF重写

【6】AOF重写配置:

配置名 含义
auto-aof-rewrite-min-size AOF文件重写需要尺寸
auto-aof-rewrite-percentage AOF文件增长率
统计名 含义
aof_current_size AOF当前尺寸(单位:字节)
aof_base_size AOF上次启动和重写的尺寸(单位:字节)

(1)自动触发时机(两个条件同时满足):

  • 当前AOF文件大小超过配置的auto-aof-rewrite-min-size
  • AOF文件的当前大小相较于上一次重写的大小,增长比例超过了配置的 auto-aof-rewrite-percentage
  • aof_current_size>auto-aof-rewrite-min-size
    • 当前尺寸大于重写需要尺寸
  • (aof_current_size-aof_base_size)/aof_base_size>auto-aof-rewrite-percentage
    • (增长率)当前尺寸减去上次重写的尺寸,除以上次重写的尺寸如果大于配置中的增长率

(2)重写流程

  • Redis启动一个子进程进行内存快照,将数据库中的数据以Redis RDB格式保存到临时文件。
  • 在子进程中,遍历保存命令的数据结构,生成新的AOF文件,只保留最新的数据库状态和经过优化的命令。
  • 替换原来的AOF文件并删除临时文件。

[image-20230416224919150](http://photo.liuqingzheng.top/2023 04 16 22 55 35 /image-20230416224919150.png)

(3)配置

appendonly yes #将该选项设置为yes,打开
appendfilename "appendonly-${port}.aof" #文件保存的名字
appendfsync everysec #采用第二种策略
dir /bigdiskpath #存放的路径
no-appendfsync-on-rewrite yes #在aof重写的时候,是否要做aof的append操作,因为aof重写消耗性能,磁盘消耗,正常aof写磁盘有一定的冲突,这段期间的数据,允许丢失
  • auto-aof-rewrite-min-size:触发AOF重写所需的AOF文件的最小大小。
  • auto-aof-rewrite-percentage:触发AOF重写的AOF文件大小增长百分比。
  • appendonly:设置为'yes'开启AOF功能。
  • appendfilename:AOF文件的名称。
  • appendfsync:控制AOF缓冲区的写入同步策略。
  • dir:指定AOF文件的存放路径。
  • no-appendfsync-on-rewrite:在执行AOF重写时,是否要进行AOF文件的追加操作,以减少对性能的影响。

【四】RDB和AOF的选择

【1】rdb和aof的比较

(1)启动优先级

  • RDB的启动优先级较低,而AOF的优先级较高。
  • 当Redis重启时,如果AOF文件存在,则会加载AOF记录的数据来恢复数据库。

(2)体积

  • RDB文件相对较小,因为它是在某个时间点上保存整个数据库状态。
  • 而AOF文件相对较大,因为它是以日志的形式记录数据库操作指令。

(3)恢复速度

  • RDB的恢复速度较快,因为它只需加载一个文件。
  • 而AOF的恢复速度较慢,因为需要逐条执行记录的指令还原数据库状态。

(4)数据安全性

  • RDB可能会丢失一部分数据,因为它是周期性地进行快照,如果系统在快照之后发生故障,则会丢失最后一次快照之后的修改。
  • 而AOF的数据安全性取决于策略的设置,默认情况下是每秒钟同步到磁盘一次,可以通过设置更高的同步频率来提高数据安全性。

(5)轻重

  • RDB对系统的负载较重,因为每次进行快照操作时需要fork()子进程来处理。
  • 而AOF对系统的负载较轻,因为将写操作追加到AOF文件并不会造成太大的开销。

(6)小结

命令 rdb aof
启动优先级 高(挂掉重启,会加载aof的数据)
体积
恢复速度
数据安全性 丢数据 根据策略决定
轻重

【2】rdb最佳策略

  • rdb关掉,主从操作时
  • 集中管理:按天,按小时备份数据
  • 主从配置,从节点打开
  • 在主从操作时,建议关闭RDB功能,以避免不必要的持久化操作。

  • 集中管理数据备份,可以按天或按小时备份RDB文件,以便在需要时恢复数据。

  • 在主从配置中,从节点打开RDB功能,用于持久化从节点的数据。

  • 例如,可以通过以下命令禁用RDB并配置从节点进行RDB持久化:

    # redis.conf配置文件中的设置
    save ""
    
    # 从节点启动时通过命令行设置
    config set save ""
    

【3】aof最佳策略

  • 开:缓存和存储,大部分情况都打开,
  • aof重写集中管理
  • everysec:通过每秒刷新的策略
  • 对于大部分情况,建议始终将AOF持久化功能打开,以确保数据的持久化和灾难恢复能力。

  • 使用AOF重写功能来优化AOF文件大小,防止其无限增长。可以根据实际情况配置AOF重写的触发条件,如设置自动重写或定期手动重写。

  • 默认情况下,Redis采用每秒同步策略(everysec),即将AOF缓冲区中的指令每秒钟同步到磁盘一次。可以根据数据安全性需求调整同步策略,如使用always策略可以最大程度上提高数据安全性,但也会增加磁盘写入开销。

  • 例如,可以通过以下命令开启AOF持久化和配置AOF重写:

    # redis.conf配置文件中的设置
    appendonly yes
    auto-aof-rewrite-percentage 100
    auto-aof-rewrite-min-size 64mb
    
    # 手动执行AOF重写命令
    BGREWRITEAOF
    

【4】最佳策略

  • 小分片:每个redis的最大内存为4g
  • 缓存或存储:根据特性,使用不通策略
  • 时时监控硬盘,内存,负载网络等
  • 有足够内存
  • 在使用Redis时,建议将数据进行小分片处理,以保证每个Redis实例的内存占用不会过大,通常建议将每个Redis实例的最大内存设置为4GB左右。
  • 根据业务特点和需求选择适当的持久化策略,如对于缓存场景可以使用RDB方式,而对于存储场景可以选择AOF方式进行持久化,或者根据实际情况使用RDB和AOF的组合持久化方式。
  • 时刻监控硬盘、内存、网络负载等关键指标,以确保系统整体性能和稳定性。
  • 确保Redis实例具备足够的内存,以容纳数据集并提供高性能的读写操作。

【五】Redis混合持久化

【1】Redis 4.0 混合持久化

  • 重启Redis时,我们很少使用RDB来恢复内存状态,因为会丢失大量数据。我们通常使用AOF日志重放。

  • 但是重放AOF日志性能相对RDB来说要慢很多,这样在Redis实例很大的情况下,启动需要花费很长的时间。

  • Redis4.0 为了解决这个问题,带来了一个新的持久化选项 --- 混合持久化。

  • 通过如下配置可以开启混合持久化(必须先开启AOF)

aof‐use‐rdb‐preamble yes
  • 如果开启了混合持久化,AOF在重写时,不再是单纯将内存数据转换为RESP命令写入AOF文件,而是将重写这一刻之前的内存做RDB快照处理

  • 并且将RDB快照内容和增量的AOF修改内存数据的命令存在一起,都写入新的AOF文件,新的文件一开始不叫appendonly.aof,等到重写完新的AOF文件才会进行改名,覆盖原有的AOF文件,完成新旧两个AOF文件的替换。

  • 于是在Redis重启的时候,可以先加载RDB的内容,然后再重放增量AOF日志就可以完全替代之前的AOF全量文件重放,因此重启效率大幅得到提升

  img

【2】Redis 数据备份策略

  • 1 写crontab 定时调度脚本,每小时copy一份rdb或aof的备份到一个目录中去,仅仅保留最近48小时的备份
  • 2 每天都保留一份当日的数据备份到一个目录中去,可以保留最近一个月的备份
  • 3 每次copy备份的时候,都把太旧的备份给删了
  • 4 每天晚上将当前机器上的备份复制一份到其他机器上,以防机器损坏