Java架构直通车——Redis持久化和宕机恢复机制

Redis持久化机制

我们都知道Redis是基于内存的,那么当Redis节点宕机后,要保证宕机恢复,Redis必须要有一个持久化的机制,持久化的话是Redis高可用中比较重要的一个环节。

Redis持久化有两种方式:

  • RDB:RDB 持久化机制,是对 Redis 中的数据执行周期性的持久化。
  • AOF:AOF 机制对每条写入命令作为日志,以 append-only 的模式写入一个日志文件中,因为这个模式是只追加的方式,所以没有任何磁盘寻址的开销,所以很快,有点像Mysql中的binlog。

持久化文件类型

  • RDB(redis database)

原理:将redis在内存的数据库中的数据定时dump到硬盘上,实现rdb持久化。

在rdb持久化过程中,是在规定的时间间隔之内将内存中的数据集快照写入磁盘,实际操作过程是fork一个子进程,先将数据集写入到临时文件中,写入成功后,再替换之前的文件,再用二进制压缩存储。那么此操作是一种间隔存储的,类似一种快照形式。(典型的:Copy-On-Write,写时复制机制)。


  • AOF(append of file)

原理:将redis的操作日志以追加的形式写入到文件中(顺序写)。

通过只增不改,不删方式。Aof持久化以日志的形式记录服务器所处理的每一个写、删除操作,查询操作不会记录,文本的形式记录,可以打开文件看到详细的操作记录。当 Redis 收到客户端修改指令后,会先进行参数校验、逻辑处理,如果没问题,就 立即(或者每隔1s) 将该指令文本 存储 到 AOF 日志中(由于是顺序追加写,所以很快)。

可以看出aof是一个粒度比较小的操作。精确到每一条操作。且每条操作的前后都不影响。

持久化时机

在这里插入图片描述
持久化的过程很容易理解,那么什么时候发生持久化的操作呢?
我们知道Mysql可以使用“双1设置”来保障持久化,不丢失内存中的数据(参考:双“1”设置为什么还是要经过磁盘?)。那么Redis又是怎么做的呢?

Redis发起系统调用后,并不是所有的写操作都会被立即写入磁盘(从磁盘缓冲到磁盘),而是要先经过一个缓冲区,默认情况下,Linux 将在 30 秒 后实际提交写入。但是很明显,30 秒 并不是 Redis 能够承受的,这意味着,如果发生故障,那么最近 30 秒内写入的所有数据都可能会丢失

幸好 PROSIX API 提供了另一个解决方案:fsync,该命令会 强制 内核将 缓冲区 写入 磁盘,但这是一个非常消耗性能的操作,每次调用都会 阻塞等待 直到设备报告 IO 完成,所以一般在生产环境的服务器中,Redis 通常是每隔 1s 左右执行一次 fsync 操作

注:无论是AOF还是RDB都是这样操作的。

RDB:COW怎么屏蔽修改的?

还有一个重要的问题是,我们在 持久化的同时,内存数据结构还可能在变化,比如一个大型的 hash 字典正在持久化,结果一个请求过来把它删除了,可是这才刚持久化结束,咋办?

操作系统多进程 COW(Copy On Write) 机制 拯救了我们。Redis 在持久化时会调用 glibc 的函数 fork 产生一个子进程,简单理解也就是基于当前进程 复制 了一个进程,主进程和子进程会共享内存里面的代码块和数据段

在这里插入图片描述
快照持久化 可以完全交给 子进程 来处理父进程 则继续 处理客户端请求

这个时候就会使用操作系统的 COW 机制来进行 数据段页面 的分离。数据段是由很多操作系统的页面组合而成,当父进程对其中一个页面的数据进行修改时,会将被共享的页面复 制一份分离出来,然后 对这个复制的页面进行修改。这时 子进程 相应的页面是 没有变化的,还是进程产生时那一瞬间的数据

fork()之后,kernel把父进程中所有的内存页的权限都设为read-only,然后子进程的地址空间指向父进程。当父子进程都只读内存时,相安无事。当其中某个进程写内存时,CPU硬件检测到内存页是read-only的,于是触发页异常中断(page-fault),陷入kernel的一个中断例程。中断例程中,kernel就会把触发的异常的页复制一份,于是父子进程各自持有独立的一份

参考:Java架构直通车——避不开的COW奶牛

AOF:重写

Redis 在长期运行的过程中,AOF 的日志会越变越长。如果实例宕机重启,重放整个 AOF 日志会非常耗时,导致长时间 Redis 无法对外提供服务。所以需要对 AOF 日志 “瘦身”。

Redis 提供了 bgrewriteaof 指令用于对 AOF 日志进行瘦身。其 原理 就是 开辟一个子进程 对内存进行 遍历 转换成一系列 Redis 的操作指令,序列化到一个新的 AOF 日志文件 中。序列化完毕后再将操作期间发生的 增量 AOF 日志 追加到这个新的 AOF 日志文件中,追加完毕后就立即替代旧的 AOF 日志文件了,瘦身工作就完成了。

Redis宕机恢复机制

重启 Redis 时,我们很少使用 rdb 来恢复内存状态,因为会丢失大量数据。我们通常使用 AOF 日志重放,但是重放 AOF 日志性能相对 rdb 来说要慢很多,这样在 Redis 实例很大的情况下,启动需要花费很长的时间。

Redis 4.0 为了解决这个问题,带来了一个新的持久化选项——混合持久化。将 rdb 文件的内容和增量的 AOF 日志文件存在一起。这里的 AOF 日志不再是全量的日志,而是 自持久化开始到持久化结束 的这段时间发生的增量 AOF 日志,通常这部分 AOF 日志很小。

简单来说,内存快照以一定的频率执行,在两次快照之间,使用 AOF 日志记录这期间的所有命令操作。

也就是,Redis在重启的时候会默认使用AOF去重新构建数据,因为AOF的数据是比RDB更完整的。

RDB更适合做冷备,AOF更适合做热备。

热备份针对归档模式的数据库,在数据库仍旧处于工作状态时进行备份。而冷备份指在数据库关闭后,进行备份,适用于所有模式的数据库。
热备份的优点在于当备份时,数据库仍旧可以被使用并且可以将数据库恢复到任意一个时间点。
冷备份的优点在于它的备份与恢复操作相当简单,并且由于冷备份的数据库可以工作在非归档模式下。

两者对比:

  1. RDB是快照文件,都是默认五分钟甚至更久的时间才会生成一次,这意味着你这次同步到下次同步这中间五分钟的数据都很可能全部丢失掉。但是AOF是一秒一次去通过一个后台的线程fsync操作,那最多丢这一秒的数据。
  2. AOF在对日志文件进行操作的时候是以append-only的方式去写的,他只是追加的方式写数据,自然就少了很多磁盘寻址的开销了,写入性能惊人,文件也不容易破损。
  3. 一样的数据,AOF文件比RDB还要大。相比之下,使用RDB做恢复更快,而使用AOF做恢复更全。

单独用RDB你会丢失很多数据,单独用AOF,数据恢复没RDB来的快,真出什么问题的时候第一时间用RDB恢复,然后AOF做数据补全。冷备热备一起上,才是互联网时代一个高健壮性系统的王道。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值