十五、Redis进阶-Redis两种持久化方式记录

作者: 温新

分类: 【Redis】

阅读: 2314

时间: 2020-09-03 15:18:32

什么是Redis持久化

Redis持久化是将存储在内存中的数据永久保存在硬盘中。

Redis为什么需要持久化

Redis的强大性能很大程度上是因为将所有数据都存储中了内存当中,当Redis重启之后,所有存储中内存中的数据就会丢失。在某些情况下,希望Redis重启之后数据不丢失,这就需要用到持久化了。如下面的情况就需要持久化:

1)将Redis作为数据库使用时;

2)将Redis作为缓存服务器,由于缓存被穿透后会对性能造成较大的影响,所有缓存同时失效会导致缓存雪崩,从而使服务器无法响应。

因此,需要将内存中的数据以某种形式同步到硬盘中,使得重启之后可以根据硬盘中的记录恢复数据。

Redis持久化方式

Redis支持RDB和AOF两种方式的持久化。RDB持久化根据指定的规则“定时”将内存中的数据存储到硬盘上;AOF则是在每次执行命令之后将命令本身记录下来。

两种持久化方式可以单独使用其中一种,更多的是将2种结合使用。

方式一、RDB方式实现持久化

RBD方式的持久化是通过快照(snapshotting)完成的,当符合一定条件时Redis会自动将内存中的所有数据生成一份副本并存储在硬盘上,这个过程就是“快照”。

【理解快照】什么是快照?类型VM中的快照,使用系统时,可以使用VM中的快照功能对当前系统进行拍照,拍完照之后使用系统时,系统发生了故障,就可以通过快照对系统系统恢复。

如下几种情况时,Redis会对数据进行快照:

  • 根据配置规则进行自动快照
  • 用户执行SAVE或BGSAVE命令
  • 执行FLUSHALL命令
  • 执行复制(replication)时

1)根据配置规则进行自动快照

对配置文件进行save配置,即配置自动进行快照功能。Redis配置文件已经默认了3条不同条件的配置,如下

<span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(103, 110, 149)"># 900秒后,有一个或一个以上的键被更改,则进行快照</span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">save <span style="box-sizing: border-box;color: rgb(255, 83, 112)">900</span> <span style="box-sizing: border-box;color: rgb(255, 83, 112)">1</span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(103, 110, 149)"># 300后,至少有10键被修改,则进行快照</span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">save <span style="box-sizing: border-box;color: rgb(255, 83, 112)">300</span> <span style="box-sizing: border-box;color: rgb(255, 83, 112)">10</span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(103, 110, 149)"># 60秒内,至少有10000键被修改,则进行快照</span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">save <span style="box-sizing: border-box;color: rgb(255, 83, 112)">60</span> <span style="box-sizing: border-box;color: rgb(255, 83, 112)">10000</span></span>

如上可以看到:每条快照以save开头,且每条快照条件独占一行。可以同时存在多个条件,条件之间是“或”关系。

实现

a)注释默认的配置文件并设置新快照条件

<span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(103, 110, 149)">#save 900 1</span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(103, 110, 149)">#save 300 10</span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(103, 110, 149)">#save 60 10000</span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(103, 110, 149)"># 60秒后如果修改3次,则进行快照</span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">save <span style="box-sizing: border-box;color: rgb(255, 83, 112)">60</span> <span style="box-sizing: border-box;color: rgb(255, 83, 112)">3</span></span>

b)删除dump.rdb文件

c)设置值,并等待60秒后查看是否有dump文件生成

<span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(255, 83, 112)">127</span>.0.0.1:6379> <span style="box-sizing: border-box;color: rgb(199, 146, 234)">set</span> k1 v1 </span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">OK</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(255, 83, 112)">127</span>.0.0.1:6379> <span style="box-sizing: border-box;color: rgb(199, 146, 234)">set</span> k2 v2 </span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">OK</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(255, 83, 112)">127</span>.0.0.1:6379> <span style="box-sizing: border-box;color: rgb(199, 146, 234)">set</span> k3 v3</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">OK</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(255, 83, 112)">127</span>.0.0.1:6379> <span style="box-sizing: border-box;color: rgb(199, 146, 234)">set</span> k4 v4</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">OK</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(255, 83, 112)">127</span>.0.0.1:6379> <span style="box-sizing: border-box;color: rgb(199, 146, 234)">set</span> k5 v5</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">OK</span>

d)60秒已经生成dump文件,重启虚拟机,强制退出redis,假设突然断电

e)重新启动redis,查看数据是否恢复

<span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(255, 83, 112)">127</span>.0.0.1:6379> <span style="box-sizing: border-box;color: rgb(255, 203, 107)">get</span> k1</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(195, 232, 141)">"v1"</span></span>

可以看到数据已经恢复了。没错,这就是自动执行快照。

2)用户执行save或bgsave命令

除了自动快照之外,还可以进行手动快照。当服务重启、手动迁移以及备份时,可以使用手动进行快照操作。

save命令

当执行save指令时,Redis同步进行快照操作,在快照执行的过程中会阻塞所有来自客户端的请求。当数据过多时,save会导致Redis长时间不响应。

<span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(255, 83, 112)">127</span>.0.0.1:6379> <span style="box-sizing: border-box;color: rgb(199, 146, 234)">set</span> k6 v6</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">OK</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(255, 83, 112)">127</span>.0.0.1:6379> save</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">OK</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(255, 83, 112)">127</span>.0.0.1:6379> <span style="box-sizing: border-box;color: rgb(199, 146, 234)">set</span> k7 v7</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">OK</span>

bgsave命令

手动执行快照,推荐使用bgsave。bgsave命令可以在后台异步进行快照操作,快照的同时服务可以继续响应来自客户端的请求。执行bgsave后,Redis会立即返回OK,表示开始执行快照操作。通过lastsave命令查看最近一次成功执行快照的时间。

3)执行flushall命令

当执行flushall命令时,Redis清除数据库中的所有数据。无论清空数据库的过程中是否触发了自动快照条件,只要自动快照条件不为空,Redis就会执行一次快照操作。

4)执行复制时

当设置了主从模式时,Redis会在复制初始化时进行自动快照。

快照原理

Redis默认会将快照文件存储在Redis当前进程的工作目录中的dump.rdb文件中。通过配置dir和dbfilename两个参数分别指定快照文件的存储路径和文件名。

快照执行过程如下:

1)Redis使用fork函数复制一份当前进程(父进程)的副本(子进程);

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

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

方式二、AOF方式实现

当使用Redis存储非临时数据时,一般需要打开AOF持久化来降低进程中止导致的数据丢失。

1)开启AOF

Redis默认不开启AOF(append only file)方式持久化,通过修改配置文件appendonly参数启用:

appendonly yes

appendfsync always

2)写入命令

<span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(255, 83, 112)">127</span>.0.0.1:6379> <span style="box-sizing: border-box;color: rgb(199, 146, 234)">set</span> name wangwu</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">OK</span>

3)查看appenonly.aof文件

-rw-r--r--. 1 root root       58 Sep  4 06:50 appendonly.aof

这样AOF就实现了。

AOF重写

为什么需要重写?有些命令是冗余的,也会被记录。随着命令不断写入,AOF文件越来越大,这时希望对该文件进行优化,针对冗余命令,可以进行删除,保留一条。

手动后台重写 bgrewriteaof

<span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(255, 83, 112)">127</span>.0.0.1:6379> bgrewriteaof</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">Background append only file rewriting started</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box"></span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">[root@192 bin]<span style="box-sizing: border-box;color: rgb(103, 110, 149)"># ll</span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">total <span style="box-sizing: border-box;color: rgb(255, 83, 112)">45668</span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(199, 146, 234)">-rw-r--r--</span>. <span style="box-sizing: border-box;color: rgb(255, 83, 112)">1</span> root root       <span style="box-sizing: border-box;color: rgb(255, 83, 112)">58</span> Sep  <span style="box-sizing: border-box;color: rgb(255, 83, 112)">4</span> <span style="box-sizing: border-box;color: rgb(255, 83, 112)">06</span>:50 appendonly.aof</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">[root@192 bin]<span style="box-sizing: border-box;color: rgb(103, 110, 149)"># ll</span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">total <span style="box-sizing: border-box;color: rgb(255, 83, 112)">45668</span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(199, 146, 234)">-rw-r--r--</span>. <span style="box-sizing: border-box;color: rgb(255, 83, 112)">1</span> root root      <span style="box-sizing: border-box;color: rgb(255, 83, 112)">110</span> Sep  <span style="box-sizing: border-box;color: rgb(255, 83, 112)">4</span> <span style="box-sizing: border-box;color: rgb(255, 83, 112)">07</span>:05 appendonly.aof</span>

可以清楚的看到,aof文件变小了

自动重写

<span style="box-sizing: border-box;padding-right: 0.1px">auto-aof-rewrite-percentage spercentage</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(103, 110, 149)"># 如:auto-aof-rewrite-percentage 100</span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box"></span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">auto-aof-rewrite-min-size size</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(103, 110, 149)"># 如:auto-aof-rewrite-min-size 64mb</span></span>
重写的作用

1)降低磁盘占用量,提高磁盘利用率

2)提高持久化效率,降低持久化写时间,提高O/I性能

3)降低数据恢复用时,提高数据恢复效率

同步硬盘数据

虽然每次执行命令,aof都会将命令记录在aof文件中,而实际上,由于操作系统缓存机制,数据并没有真正写入硬盘,而是进入了系统的硬盘缓存。默认情况下系统每30秒会执行一次同步操作,这时才是真正写入硬盘。

如果在这30秒的过程中,系统异常退出,则会导致硬盘缓存中的数据丢失,这是aof持久化无法容忍的损失。可以通过appendfsync参数设置同步时机:

appendfsync always/everysec/no

always表示每次执行写入都会执行同步

no表示不主动进行同步操作

everysec表示每秒进行同步

我是夕阳何处寻,期待和优秀的你一起同行!

小白

2020年09月03日

请登录后再评论