天啦!成都8月限电,突然拉闸,几十亿数据丢了...

2022-09-24 20:52:25 浏览数 (1)

2022年8月,成都不再像以往一样突发暴雨,而是持续高温天气,最高温度42°,在8月第三周15号开始,陆陆续续成都多个写字楼限电,工业用电直接关停,空调不能使用,大多都居家远程办公或放假几天,政府的目标是优先保证生活用电,恰巧作者所在的写字楼中途有次突然断电,我们的多个服务下线,其中就有物理机单机redis数据和集群redis数据丢失的情况,接下来我就redis的存储方案做一个简单的介绍:

一、redis持久化的引出

redis的数据都放在内存中,以速度快著称,那么当突然断电来临,如果没有把内存中的数据保存在物理磁盘上,那么下次重启redis就不会存在之前的数据了,势必就会引入持久化策略,redis的持久化策略是RDBAOF,这两种策略都是将redis内存中的数据存储到磁盘上,保证数据不丢失,接下来我们就详细的聊一聊RDBAOF各自的特征。

二、RDB

1.概念

RDB(Redis DataBase)持久化是把当前进程数据生成快照保存到硬盘的过程,即快照模式,它是 Redis 默认的数据持久化方式,它会将数据的快照保存在 dump.rdb 这个二进制文件中。

引申:假设是你自己来设计RDB存储,你要怎么做?

  1. 我们来实现复制8点的数据到磁盘,并且这个过程需要30分钟

此时redis对外服务不可用,我们用这30分钟来将数据写到磁盘。

  1. redis对外提供服务并且也向磁盘中写,但是在写的时候数据变了,持久化的数据就不具备时点性了
  1. 同样是非阻塞,利用fork调用开启一个子进程去干

redis自身是怎么做的呢?

  1. 手动触发分别对应为save和bgsave命令
  • save命令:阻塞当前Redis服务器,直到RDB过程完成为止,对于内存比较多的实例会造成时间阻塞。线上环境不建议使用。
  • bgsave命令:Redis进程执行fork操作创建子进程,RDB持久化过程由子进程负责,完成后自动结束。阻塞只发生在fork阶段,一段时间很短。
  1. 配置默认开启自动持久化规则

思考:redis是单进程的,在bgsave的时候是怎么操作的呢,这个时候它是靠操作系统的的 COW(Copy On Write) 机制,这里不展开写时复制的讲解,大家可自行根据自身情况进行探索,写时复制机制实现了数据段分离且保证父子进程不受影响,父进程能持续对外提供服务,子进程自己去写磁盘。

2、RDB持久化触发策略

RDB 持久化提供了两种触发策略:一种是手动触发,另一种是自动触发。

1) 手动触发策略

手动触发是通过SAVAE命令或者BGSAVE命令将内存中的数据保存到物理磁盘文件

代码语言:javascript复制
127.0.0.1:6379> SAVE
OK
127.0.0.1:6379> BGSAVE
Background saving started
127.0.0.1:6379>  LASTSAVE
(integer) 1159560

BGSAVE优于SAVE 命令。

SAVE 命令会阻塞 Redis 服务进程,直到 dump.rdb 二进制文件创建完毕为止,在这个过程中,服务器不能处理任何的命令请求,对外不能提供服务。

BGSAVE命令是非阻塞的,所谓非阻塞指的是在该命令执行的过程中,redis能正常对外提供服务。是因为 Redis 服务器会 fork() 开启一个子进程来进行持久化操作(创建新的 dunp.rdb 文件),而父进程则继续处理客户端请求。当子进程处理完毕之后后会告知向父进程已经处理完毕。此时,父进程会用新的 dump.rdb 文件覆盖掉原来的旧文件。

LASTSAVE 命令用于查看 BGSAVE 命令是否执行成功。

2) 自动触发策略

自动触发策略,是指 Redis 在指定的时间内,数据发生了多少次变化时,会自动执行BGSAVE命令。自动触发的条件包含在了 Redis 的配置文件中,如下所示:

上图所示, save x y 的含义是在时间 x 秒内,如果 Redis 数据至少发生了 y 次变化,那么就自动执行BGSAVE命令。配置策略说明如下:

  • save 900 1 表示在 900 秒内,至少更新了 1 条数据,Redis 自动触发 BGSAVE 命令,将数据刷写到磁盘。
  • save 300 10 表示在 300 秒内,至少更新了 10 条数据,Redis 自动触 BGSAVE 命令,将数据刷写到磁盘。
  • save 60 10000 表示 60 秒内,至少更新了 10000 条数据,Redis 自动触发 BGSAVE 命令,将数据刷写到磁盘。

上述三个条件任意满足一个,服务器就会自动执行BGSAVE命令。

3、RDB的优缺点与适用情况

优点:
  • RDB是一个非常紧凑的文件,它保存了某个时间点及其之前的数据集,非常适用于数据集的备份。
  • RDB是一个紧凑的单一文件,很方便传送到另一个远端数据中心或者亚马逊的S3(可能加密),非常适用于灾难恢复。
  • RDB在保存RDB文件时父进程唯一需要做的就是fork出一个子进程,接下来的工作全部由子进程来做,父进程不需要再做其他IO操作,所以RDB持久化方式可以最大化redis的性能。
  • 与AOF相比,在恢复大的数据集的时候,RDB方式会更快一些。
缺点:
  • 如果你希望在redis意外停止工作(例如电源中断)的情况下丢失的数据最少的话,那么RDB不适合你.虽然你可以配置不同的save时间点(例如每隔5分钟并且对数据集有100个写的操作),是Redis要完整的保存整个数据集是一个比较繁重的工作,你通常会每隔5分钟或者更久做一次完整的保存,万一在Redis意外宕机,你可能会丢失几分钟的数据。
  • RDB 需要经常fork子进程来保存数据集到硬盘上,当数据集比较大的时候,fork的过程是非常耗时的,可能会导致Redis在一些毫秒级内不能响应客户端的请求.如果数据集巨大并且CPU性能不是很好的情况下,这种情况会持续1秒,AOF也需要fork,但是你可以调节重写日志文件的频率来提高数据集的耐久度。
  • dump.rdb 文件不支持拉链,全程只有一个,假如你想恢复到前面某一天是无法实现的。
适用情况:

RDB 数据持久化适合于大规模的数据恢复,并且恢复速度快,如果对数据的完整性要求不高(可能存在最后的一段时间丢失的情况),那么 RDB 持久化方式非常合适。

三、AOF

1、概念 

AOF(append only file)持久化:以独立日志的方式记录每次写命令,它和mysql的binlog比较类似,一直将命令挨个写入文件,redis在重启的时候,读取AOF文件中一行行的命令执行就能恢复数据。AOF它的主要作用是解决了实时存储数据,就是数据持久化的实时性,目前AOF持久化方式已经是Redis持久化的主流。

AOF 重写和 RDB 创建快照一样,都巧妙地利用了操作系统COW(Copy On Write)写时复制机制:

  • Redis 执行 fork() ,开辟一个子进程,现在同时拥有父进程和子进程;
  • 子进程开始将新AOF文件的内容写入到一个临时文件中;
  • 对于所有新执行的写入命令(在子进程进行的过程中),父进程一边将它们放到内存缓存中,一边将这些改动命令增量追加到现有的AOF文件末尾,这样样即使在重写的中途发生停机,现有的 AOF 文件也还是安全的;
  • 当子进程完成重写工作时,它给父进程发送一个信号,父进程在接收到信号之后,将内存缓存中的所有数据追加到新AOF文件的末尾;
  • 最后 Redis 用新文件替换旧文件,之后所有命令都会直接追加到新 AOF 文件的末尾,之前的AOF文件丢掉。

2、配置

3、日志重写

因为 AOF 的写命令方式是不断地将命令追加到文件的末尾, 所以随着写入命令的不断增加, AOF 文件会变得越来越大。举个例子, 如果你对一个计数器调用了 1000 次 INCR , 那么仅仅是为了保存这个计数器的当前值, AOF 文件就需要使用 1000 条记录(entry)。然而在实际上, 只使用一条 SET 命令已经足以保存计数器的当前值了, 其余 99 条记录实际上都是多余的。

为了处理这种情况, Redis 支持一种有趣的特性:可以在不打断服务客户端的情况下, 对 AOF 文件进行重建(rebuild),对应的命令式 BGREWRITEAOF 命令, Redis 将生成一个新的 AOF 文件, 将重复命令或者几个命令合并,这个文件包含重建当前数据集所需的最少命令。Redis 2.2 需要自己手动执行 BGREWRITEAOF 命令;Redis 2.4以后 则可以自动触发 AOF 重写。

4、AOF有多耐用?

你可以配置 Redis 多久才将数据 fsync 到磁盘一次。有三种方式:

  • no的级别就是等一个buffer满了在向磁盘去写,可能会丢失一个buffer的数据,从不 fsync ,将数据交给操作系统来处理,数据可靠性完全依靠操作系统保证,速度更快,也是更加不安全的选择;
  • always的级别就是来一个就写一个到磁盘,数据可靠性是最强的,顶多就只丢一条数据,每次有新命令追加到 AOF 文件时就执行一次 fsync ,非常慢,也非常安全;
  • everysec每秒写,最大可能会丢失一个buffer的数据,这个是概率事件了,每秒 fsync 一次,足够快(和使用 RDB 持久化差不多),并且在故障时只会丢失 1 秒钟的数据。

注意:推荐(并且也是默认)的措施为每秒 fsync 一次, 配置成everysec,这种 fsync 策略可以兼顾速度和安全性。

5、如果AOF文件损坏了怎么办?

服务器可能在程序正在对 AOF 文件进行写入时停机, 如果停机造成了 AOF 文件出错(corrupt), 那么 Redis 在重启时会拒绝载入这个 AOF 文件, 从而确保数据的一致性不会被破坏。当发生这种情况时, 可以用以下方法来修复出错的 AOF 文件:

  • 为现有的 AOF 文件创建一个备份。
  • 使用 Redis 附带的 redis-check-aof 程序,对原来的 AOF 文件进行修复: $ redis-check-aof –fix
  • (可选)使用 diff -u 对比修复后的 AOF 文件和原始 AOF 文件的备份,查看两个文件之间的不同之处。
  • 重启 Redis 服务器,等待服务器载入修复后的 AOF 文件,并进行数据恢复。

6、aof实操

1)、操作步骤
  1. ps -fe | grep redis
  2. vi /etc/redis/6379.conf 为了看实验效果,关闭后台运行:daemonize no 注释日志文件:#logfile /var/log/redis_6379.log rdb:正常设置 追加:appendonly yes 混合模式先关闭看下老版本效果:aof-use-rdb-preamble no
  3. 删除之前redis启动时运行落的rdb文件, cd /var/lib/redis/6379/   --rm -fr ./*
  4. redis-server /etc/redis/6379.conf
  5. 另起一个窗口连接redis,set k1 hello
  6. 在起一个窗口查看 /var/lib/6379下的 appendonly.aof文件

,$数字>表示几个字符,*数字>表示后面取几行,比如这条指令就是选择0号库,设置一个k1,value为hello

  1. 现在就看见一个aof的文件,怎么不见rdb的文件呢,如果想要,直接在另一个客户端执行bgsave
  1. vi dump.rdb------

,

2)、查看重写
  1. 将原有key改下值---

,相应的aof文件中会有修改的操作记录

,这个时候其实就相当于给k1赋一个值,aof文件中就记录了很多垃圾,可以用BGREWRITEAOF命令压缩aof文件,压缩前160多,压缩后查看aof文件82,

  1. vi appendonly.aof

,可以看见操作合并了

3)、查看新版本
  1. 重复实操步骤,这个配置aof-use-rdb-preamble改成yes
  2. 先不触发重写,直接设置一个k1 k2查看aof文件---
  1. 这时执行 set k1 set k2触发重写,再执行BGREWRITEAOF,和之前做对比

,vi appendonly.aof查看,可以看见这个aof文件前面也有个REDIS了

  1. 这个时候在设置1.2个新的key,set k3 set k4等,在看aof文件--

,前边是二进制的rdb,加快恢复速度,后边是明文操作

  1. 如果想出一个rdb文件,可以执行BGSAVE,接着BGREWRITEAOF,在查看文件下--

四、怎样从RDB方式切换为AOF方式

在 Redis 2.2 或以上版本,可以在不重启的情况下,从 RDB 切换到 AOF :

  • 为最新的 dump.rdb 文件创建一个备份。
  • 将备份放到一个安全的地方。
  • 执行以下两条命令:
  • redis-cli config set appendonly yes
  • redis-cli config set save “”
  • 确保写命令会被正确地追加到 AOF 文件的末尾。
  • 执行的第一条命令开启了 AOF 功能:Redis 会阻塞直到初始 AOF 文件创建完成为止, 之后 Redis 会继续处理命令请求, 并开始将写入命令追加到 AOF 文件末尾。

执行的第二条命令用于关闭 RDB 功能。这一步是可选的, 如果你愿意的话, 也可以同时使用 RDB 和 AOF 这两种持久化功能。

重要:别忘了在 redis.conf 中打开 AOF 功能!否则的话, 服务器重启之后, 之前通过 CONFIG SET 设置的配置就会被遗忘, 程序会按原来的配置来启动服务器。

五、AOF和RDB之间的相互作用

在版本号大于等于 2.4 的 Redis 中, BGSAVE 执行的过程中, 不可以执行 BGREWRITEAOF 。反过来说, 在 BGREWRITEAOF 执行的过程中, 也不可以执行 BGSAVE。这可以防止两个 Redis 后台进程同时对磁盘进行大量的 I/O 操作。

如果 BGSAVE 正在执行, 并且用户显示地调用 BGREWRITEAOF 命令, 那么服务器将向用户回复一个 OK 状态, 并告知用户, BGREWRITEAOF 已经被预定执行:一旦 BGSAVE 执行完毕, BGREWRITEAOF 就会正式开始。当 Redis 启动时, 如果 RDB 持久化和 AOF 持久化都被打开了, 那么程序会优先使用 AOF 文件来恢复数据集, 因为 AOF 文件所保存的数据通常是最完整的,生成的文件是一个混合体,下面是二进制,上面是aof追加的命令

六、回答标题疑问

相信通过对RDB和AOF的了解,可以这样回答:在Redis单实例情况下,RDB方式最大丢失了从断电到上一次bgsava之间的数据,aof方式(默认配置)最多丢失1s的数据,在Redis集群情况下,如果都同单机一样全部挂掉丢失情况和单机一致,如果是集群中某个Redis实例挂掉,当它重新上线可以完全恢复数据,不丢失数据。

总结

今天主要跟大家聊的是Redis持久化的策略以及对RBD和AOF的原理有简单的阐述,相信经过此篇文章你可以应对面试官对Redis持久化的相关问题,后续也会持续介绍Redis相关的知识,欢迎持续关注!

0 人点赞