持久化通俗地理解就是把内存中的数据,存到硬盘中。
Redis是一种内存数据库,它的数据是存放在内存中的,也就是说如果断电,数据就会丢失(RAM断电失忆)。
Redis中的数据就是键值对。
Redis持久化,把数据存到硬盘上,可以防止服务器出现故障造成数据丢失,这时只需要从硬盘中存放的数据重新加载到内存,那么Redis就可以恢复状态

如何恢复状态?
这里恢复状态就有两种方案了:

  1. 把原来的数据存放到硬盘上,恢复时直接重新读入内存。
  2. 把操作存放到硬盘上,恢复时把这些操作重新执行一遍,同样可以恢复到之前的状态。

如何理解上面两种方案呢?
看下面python代码:

a = 1
b = 2
a = 3

上边代码的执行结果是在名字空间中存放了一对约束:{a:3, b:2}
现在我们要保存程序的执行结果:

就有两种方式:

  1. 直接把结果a:3, b:2存放起来,恢复时,直接把这对约束放到名字空间。
  2. 我们存放a=1,b=2,a=3, 这几条语句,恢复时,重新把这三条语句执行一遍,同样也可以恢复到{a:3, b:2}这个状态。

这就是Redis的两种持久化方式:RDB, AOF

RDB持久化:

cluster节点恢复 redis redis断电数据恢复_持久化


rdb.c [代码已删减]

核心代码在上面列出,其实很明显,就是把所有的键值对取出,然后保存。对应我们讨论的第一种持久化方式,直接保存要恢复的状态(最后的结果)。

AOF持久化:

aof持久化比较复杂,与整个服务器进程都有很大的关系,不做过多分析。

只做一些简要说明:

  1. 并不是每执行一条命令都把这条命令(操作)直接保存到硬盘,而是先放到缓冲区中。
  2. Redis会对这些命令进行优化:比如上面我们列举的三条赋值语句a=1, b=2, a=3, 如果直接存放三条语句,那么第一条语句是没有用的,只需要存放b=2, a=3, 即可恢复状态。所以redis的优化就是先读出当前键值对的值,然后组织出语句,再放到缓冲区中。(读出当前名字空间中的键值对为{a:3, b:2}, 那么就组织出语句a=3, b=2, 存放这两条语句)

事件溯源:

AOF就相当于是事件溯源,只存储记录,不存放状态,需要具体状态时,只要从头计算所有记录(执行所有操作)即可。所需要的存储空间更大。
事件溯源由于没有更新和删除,只有增加(新增一条语句)和查询(执行所有语句),不维护可变变量,也就没有并发的问题。所有的并发问题(竞争,死锁,并发更新),都是由可变变量导致的:如果变量不能被更改,就不会有竞争和并发更新问题,如果锁状态不能更改,就不会有死锁问题。
如果存储状态,这个状态就是可变变量。(Redis中的键值对可能被随时修改)。

用Redis的RDB与AOF(事件溯源)相比,可能不太准确。因为RDB是把所有数据库的所有键值对全部存放起来的。不是单个修改,也不是事务。

用事务中大家最熟悉的存取款来解释事件溯源的优点:
如果我们存放的是状态,也就是账户的余额,那么每次存取款时,就要同时修改余额记录(这是个可变变量,要保证并发安全)。
如果我们存放的是所有的操作,不存放状态,需要具体状态时,只要从头计算所有记录(执行所有操作)即可。由于没有更新和删除,只有增加(新增一条语句)和查询(执行所有语句),不维护可变变量,也就没有并发的问题。

本文主要是讨论两种持久化的思路,对于细节没有做过多讨论。
后续应该会更新。


参考:《Redis设计与实现》
《Clean Architecture》