栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Redis持久化机制详解

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Redis持久化机制详解

Redis 的强劲性能很大程度上是由于它所有的数据都存储在内存中,当然如果 redis 重启或者服务器故障导致 redis 重启,所有存储在内存中的数据就会丢失。但是在某些情况下,我们希望 Redis 在重启后能够保证数据不会丢失。

  1. 将 redis 作为 nosql 数据库使用。
  2. 将 Redis 作为高效缓存服务器,缓存被击穿后对后端数据库层面的瞬时压力是特别大的,所有缓存同时失效可能会导致雪崩。

这时我们希望 Redis 能将数据从内存中以某种形式同步到硬盘上,使得重启后可以根据硬盘中的记录来恢复数据。

Redis 支持两种方式的持久化,一种是 RDB 方式、另一种是 AOF(append-only-file)方式,两种持久化方式可以单独使用其中一种,也可以将这两种方式结合使用。

  • RDB:根据指定的规则 “ 定时” 将内存中的数据存储在硬盘上,
  • AOF:每次执行命令后将命令本身记录下来。
1. RDB 模式

RDB 的持久化方式是通过快照(snapshotting)完成的,它是 Redis 默认的持久化方式,配置如下。

# save 3600 1
# save 300 100
# save 60 10000

Redis 允许用户自定义快照条件,当符合快照条件时,Redis 会自动执行快照操作。快照的条件可以由用户在配置文件中配置。配置格式如下:

save  

第一个参数是时间窗口,第二个是键的个数,也就是说,在第一个时间参数配置范围内被更改的键的个数大于后面的 changes 时,即符合快照条件。当触发条件时,Redis 会自动将内存中的数据生成一份副本并存储在磁盘上。

这个过程称之为 “快照”,除了上述规则之外,还有以下几种方式生成快照。

  1. 根据配置规则进行自动快照
  2. 用户执行 SAVE 或者 BGSAVE 命令
  3. 执行 FLUSHALL 命令
  4. 执行复制 (replication) 时
1.1 根据配置规则进行自动快照
  • 修改 redis.conf 文件,表示 5 秒内,有一个 key 发生变化,就会生成 rdb 文件。
save 5 1                # 表示3600s以内至少发生1个key变化(新增、修改、删除),则重写rdb文件
save 300 100
save 60 10000
  • 修改文件存储路径
dir /data/program/redis/bin
  • 其他参数配置说明
参数说明
dirrdb 文件默认在启动目录下(相对路径) config get dir 获取
dbfilename文件名称
rdbcompression开启压缩可以节省存储空间,但是会消耗一些 CPU 的计算时间,默认开启
rdbchecksum使用 CRC64 算法来进行数据校验,但是这样做会增加大约 10% 的性能消耗,如果希望获取到最大的性能提升,可以关闭此功能。

如果需要关闭 RDB 的持久化机制,可以参考如下配置,开启 save,并注释其他规则即可

save ""
#save 900 1
#save 300 10
#save 60 10000
1.2 用户执行 SAVE 或者 GBSAVE 命令

除了让 Redis 自动进行快照以外,当我们对服务进行重启或者服务器迁移我们需要人工去干预备份。redis 提供了两条命令来完成这个任务:

  • save 命令

    如下图所示,当执行 save 命令时,Redis 同步做快照操作,在快照执行过程中会阻塞所有来自客户端的请求。当 redis 内存中的数据较多时,通过该命令将导致 Redis 较长时间的不响应。所以不建议在生产环境上使用这个命令,而是推荐使用 bgsave 命令。

  • bgsave 命令

    如下图所示,bgsave 命令可以在后台异步地进行快照操作,快照的同时服务器还可以继续响应来自客户端的请求。执行 BGSAVE 后,Redis 会立即返回 ok 表示开始执行快照操作,在 redis-cli 终端,通过下面这个命令可以获取最近一次成功执行快照的时间(以 UNIX 时间戳格式表示)。

    LASTSAVE
    
    • redis 使用 fork 函数复制一份当前进程的副本 (子进程)

    • 父进程继续接收并处理客户端发来的命令,而子进程开始将内存中的数据写入硬盘中的临时文件

    • 当子进程写入完所有数据后会用该临时文件替换旧的 RDB 文件,至此,一次快照操作完成。

    注意:redis 在进行快照的过程中不会修改 RDB 文件,只有快照结束后才会将旧的文件替换成新的,也就是说任何时候 RDB 文件都是完整的。 这就使得我们可以通过定时备份 RDB 文件来实现 redis 数据库的备份, RDB 文件是经过压缩的二进制文件,占用的空间会小于内存中的数据,更加利于传输。

    bgsave 是异步执行快照的,bgsave 写入的数据就是 fork 进程时 redis 的数据状态,一旦完成 fork,后续执行的新的客户端命令对数据产生的变更都不会反应到本次快照

    Redis 启动后会读取 RDB 快照文件,并将数据从硬盘载入到内存。根据数据量大小以及服务器性能不同,这个载入的时间也不同。

1.3 执行 FLUSHALL

该命令会清除 redis 在内存中的所有数据。执行该命令后,只要 redis 中配置的快照规则不为空,也就是 save 的规则存在。redis 就会执行一次快照操作。不管规则是什么样的都会执行。如果没有定义快照规则,就不会执行快照操作。

1.4 执行复制 (replication)

该操作主要是在主从模式下,redis 会在复制初始化时进行自动快照。

这里只需要了解当执行复制操作时,即时没有定义自动快照规则,并且没有手动执行过快照操作,它仍然会生成 RDB 快照文件。

1.5 RDB 数据恢复演示
  • 准备初始数据

    redis> set k1 1
    redis> set k2 2
    redis> set k3 3
    redis> set k4 4
    redis> set k5 5
    
  • 通过 shutdown 命令关闭触发 save

    redis> shutdown
    
  • 备份 dump.rdb 文件 (用来后续恢复)

    cp dump.rdb dump.rdb.bak
    
  • 接着再启动 redis-server (systemctl restart redis_6379),通过 keys 命令查看,发现数据还在

    keys *
    
1.6 文件的优势和劣势

一、优势

  • RDB 是一个非常紧凑 (compact) 的文件,它保存了 redis 在某个时间点上的数据集,这种文件非常适合用于进行备份和灾难恢复。
  • 生成 RDB 文件的时候,redis 主进程会 fork () 一个子进程来处理所有保存工作,主进程不需要进行任何磁盘 IO 操作。
  • RDB 在恢复大数据集时的速度比 AOF 的恢复速度要快。

二、劣势

  • 1、RDB 方式数据没办法做到实时持久化 / 秒级持久化。因为 bgsave 每次运行都要执行 fork 操作创建子进程,频繁执行成本过高
  • 2、在一定间隔时间做一次备份,所以如果 redis 意外 down 掉的话,就会丢失最后一次快照之后的所有修改(数据有丢失)。

如果数据相对来说比较重要,希望将损失降到最小,则可以使用 AOF 方式进行持久化。

2. AOF 模式

AOF (Append only File):Redis 默认不开启。AOF 采用日志的形式来记录每个写操作,并追加到文件中。开启后,执行更改 Redis 数据的命令时,就会把命令写入到 AOF 文件中。

Redis 重启时会根据日志文件的内容把写指令从前到后执行一次以完成数据的恢复工作。

2.1 AOF 配置开关
# 开关
appendonly no  /yes
# 文件名
appendfilename "appendonly.aof"

通过修改 redis.conf 重启 redis 之后,再次运行 redis 的相关操作命令,会发现在指定的 dir 目录下生成 appendonly.aof 文件,通过 vim 查看该文件内容如下:

2.2 AOF 配置相关问题

问题 1:数据都是实时持久化到磁盘吗?

虽然每次执行更改 Redis 数据库内容的操作时,AOF 都会将命令记录在 AOF 文件中,但是事实上,由于操作系统的缓存机制,数据并没有真正地写入硬盘,而是进入了系统的硬盘缓存。在默认情况下系统每 30 秒会执行一次同步操作。以便将硬盘缓存中的内容真正地写入硬盘。

在这 30 秒的过程中如果系统异常退出则会导致硬盘缓存中的数据丢失。一般来说能够启用 AOF 的前提是业务场景不能容忍这样的数据损失,这个时候就需要 Redis 在写入 AOF 文件后主动要求系统将缓存内容同步到硬盘中。在 redis.conf 中通过如下配置来设置同步机制。

参数说明
appendfsync everysecAOF 持久化策略(硬盘缓存到磁盘),默认 everysec 1 no 表示不执行 fsync,由操作系统保证数据同步到磁盘,速度最快,但是不太安全; 2 always 表示每次写入都执行 fsync,以保证数据同步到磁盘,效率很低; 3 everysec 表示每秒执行一次 fsync,可能会导致丢失这 1s 数据。通常选择 everysec ,兼顾安全性和效率。

问题 2:文件越来越大,怎么办?

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

例如 set name tom,执行 1000 次,结果都是 name=tom。

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

可以使用命令下面这个命令主动触发重写

bgrewriteaof

AOF 文件重写并不是对原文件进行重新整理,而是直接读取服务器现有的键值对,然后用一条命令去代替之前记录这个键值对的多条命令,生成一个新的文件后去替换原来的 AOF 文件。

重写触发机制如下

参数说明
auto-aof-rewrite-percentage默认值为 100。表示的是当目前的 AOF 文件大小超过上一次重写时的 AOF 文件大小的百分之多少时会再次进行重写,如果之前没有重写过,则以启动时 AOF 文件大小为依据
auto-aof-rewrite-min-size默认 64M。表示限制了允许重写的最小 AOF 文件大小,通常在 AOF 文件很小的情况下即使其中有很多冗余的命令我们也并不太关心

在启动时,Redis 会逐个执行 AOF 文件中的命令来将硬盘中的数据载入到内存中,载入的速度相对于 RDB 会慢一些。

问题3:重写过程中,AOF 文件被更改了怎么办?

Redis 可以在 AOF 文件体积变得过大时,自动地在后台对 AOF 进行重写: 重写后的新 AOF 文件包含了恢复当前数据集所需的最小命令集合。

重写的流程是这样,

  • 主进程会 fork 一个子进程出来进行 AOF 重写,这个重写过程并不是基于原有的 aof 文件来做的,而是有点类似于快照的方式,全量遍历内存中的数据,然后逐个序列到 aof 文件中。
  • 在 fork 子进程这个过程中,服务端仍然可以对外提供服务,**那这个时候重写的 aof 文件的数据和 redis 内存数据不一致了怎么办?**不用担心,这个过程中,主进程的数据更新操作,会缓存到 aof_rewrite_buf 中,也就是单独开辟一块缓存来存储重写期间收到的命令,当子进程重写完以后再把缓存中的数据追加到新的 aof 文件。
  • 当所有的数据全部追加到新的 aof 文件中后,把新的 aof 文件重命名正式的文件名字,此后所有的操作都会被写入新的 aof 文件。
  • 如果在 rewrite 过程中出现故障,不会影响原来 aof 文件的正常工作,只有当 rewrite 完成后才会切换文件。因此这个 rewrite 过程是比较可靠的。

Redis 允许同时开启 AOF 和 RDB,既保证了数据安全又使得进行备份等操作十分容易。如果同时开启后,Redis 重启会使用 AOF 文件来恢复数据,因为 AOF 方式的持久化可能丢失的数据更少。

2.3 AOF 的优劣势

优点:

  • AOF 持久化的方法提供了多种的同步频率,即使用默认的同步频率每秒同步一次,Redis 最多也就丢失 1 秒的数据而已。

缺点:

  • 对于具有相同数据的的 Redis,AOF 文件通常会比 RDB 文件体积更大(RDB 存的是数据快照)。RDB 在恢复大数据集时的速度比 AOF 的恢复速度要快。

  • 根据同步策略的不同,AOF在运行效率上往往会慢于RDB。总之,每秒同步策略的效率是比较高的,同步禁用策略的效率和RDB一样高效。

二者选择的标准,就是看系统是愿意牺牲一些性能,换取更高的缓存一致性(aof),还是愿意写操作频繁的时候,不启用备份来换取更高的性能,待手动运行save的时候,再做备份(rdb)。rdb这个就更有些 eventually consistent的意思了。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/605453.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号