本文主要介绍redis持久化的相关内容,上一文介绍redis淘汰策略,补充知识点:进入redis-cli模式,使用info命令可以查看redis内存的使用情况。图中我们看出maxmemory默认为0,在64位的系统下默认不限制内存,32位的最多只能用3GB内存。maxmemory默认是按照字节来计算,1M=1048576字节。在redis.conf文件里maxmemory内存大小配合manmemory-policy进行使用。

06fb956facbc99744dc53baf8099785f.png

redis的持久化 知识结构图:

10c54d78e9d8c249ebddcb29629494a2.png

一、RDB持久化

简介: RDB持久化方式是通过快照(snapshotting)完成的,当满足特定条件下,redis会自动将内存的数据以二进制方式形成备份保存在磁盘。redis重启时,当AOF持久化没有开启,redis就会读取RDB备份(默认名称dump.rdb)进行数据恢复。停用rdb可以使用命令config set save "" 或者配置文件配置,当系统只用到缓存不需要持久化的场景。当redis出现故障,如果有rdb和aof文件,redis优先从aof读取数据,但rdb就会被读取。

使用命令info persistence可以查看持久化相关信息

ecb3e3b6092e1e0809a63950d88d376e.png

使用命令config get dafilename可知道RDB二进制文件默认名,也可以通过设置dbfilename进行修改

0a248a079aec2876e7561ea5f77953f5.png

220c116faae99908ef91b3eee4ea9604.png

快照文件位置查看命令:config get dir

0732d3b93fd47cacb28e683c6b907da7.png

快照触发条件:RDB可自动触发生成快照,也可以手动触发。redis触发执行快照条件:    1.客户端执行命令save和bgsave会生成快照    2.根据配置文件save m n规则生成快照    3.主从复制时,从库全量复制同步主库数据,主库会执行bgsave命令进行快照。    4.客户端执行数据库清空命令flushall,触发快照。    5.客户端执行shutdowm关闭redis时,触发快照。save命令触发客户端执行save命令,会强制redis执行快照,redis这时会处于堵塞,不会响应其他客户端发来的请求,直到RDB文件执行完毕,需谨慎使用。使用info persistence 命令查看最近一次持久化时间:

0381b8e97ba02b941a502fa59821c5eb.png

我们执行save命令,然后再查看就是最新生成快照时间。

a78cdfbca03b07596b6b826b6ab9ad5d.png

bgsave命令触发bgsave命令执行时,redis会fork出一个子进程来执行生成快照操作,注意:redis在fork子进程这个简短的时间是堵塞的,此时不会响应客户端请求,当子进程创建完成redis会响应客户端请求。redis自动快照就是使用bgsave完成的。39ea6eaab3526eb2803ca2b310261967.png创建快照过程:1.客户端执行bgsave命令,redis主进程收到命令并判断是否在执行bgrewriteaof(AOF文件重写过程),如果此时正好在执行则bgsave直接返回,不fork子进程,如果没有执行,进入下一个阶段2.主进程调用fork方法创建子进程,在创建过程中redis主进程堵塞,不能响应客户端请求。3.子进程创建完成后,bgsave命令返回"Background saving started",此时redis可以正常响应客户端请求。4.子进程根据主进程的内存副本创建临时快照文件,当快照完成以后对原快照文件进行替换。5.子进程发送信号给redis主进程完成快照操作,主进程更新统计信息,子进程退出。执行bgsave命令:7468773e7ff6d847dbea1a651e09ab17.png查看日志docker logs 容器名,如果是在linux直接去linux查看redis-server.log即可。

28663aa366b1c7608069643febcb65aa.png

再看查看RDB最后一次的保存时间已经更新。

fac678feb61ba47fb23ad6f4470d2237.png

save m n规则触发

在指定的m秒内,redis中有n个键发生改变,则自动触发bgsave。该规则可在redis.conf进行配置,并且可组合使用,满足其中一个规则,则会触发bgsave。

f23369d8b348a29f152b0b698f8e86c7.png

save 900 1 说明900秒内至少有一个键发生改变,redis就会触发bgsave

cbb56699eb2f213bc7d9e70e42b316e3.png

然后使用docker logs日志,就可以查看到redis会马上响应bgsave操作

flushall触发

flushall用于清空数据库,当使用该命令清空数据时,redis也会对快照文件进行清空,就会触发bgsave。(慎重使用)

9e9b7c87f4c1f9424cae6595ee2642d9.png

使用docker logs查看,测试发现如果没有设置内存大小,使用默认0,则使用flushall就不会触发bgsave。

04d7c155233b111dd256d2731f5a83c5.png

shutdown触发

redis在关闭之前为了防止数据丢失,会将所有数据全部保存下来,以便下次启动快速启动。

5e2ac6d7d1c25ea59a99989980ec4651.png

查看日志

e1fee1d675dd8c97dd01331ce0df5352.png

主从触发

redis主从复制中,从节点执行全量复制操作,主节点会执行bgsave命令,并将rdb文件发送给从节点。

故障恢复

当redis意外崩溃或者关闭再次启动时,当AOF持久化未开启时,将使用RDB快照文件恢复数据。

模拟场景:先关掉redis,在启动redis

f494e34cecd44f856c8ce46ec3674f74.png

7a6aad4fff5d308da199bf1ffd368fcc.png

       查看日志:

93397155b6c7961a8d77eb271a479839.png

RDB持久化配置

be5d20f4868d5c48ba01e53c2c599414.png

RDB自动保存原理

redis服务器状态结构:

af4ab1795591c6aa3ab5dd6d3bae53d9.png

1.查看记录保存save条件的数组saveparam,每个元素都是一个saveparam结构

940c225d6b6bc93eb16a44bf2360028a.png

save 900  1 如果900秒内有一个key值发生变化,就会触发save。此时saveparan数组在服务器状态的样子如下:

baafce4b2cfc9a7813d7996cdd373465.png

2.dirty计数器和lastsave属性

   dirty计数器记录上一次成功执行save/bgsave命令之后,redis服务器进行了多少次修改(写入、删除和更新操作)

   lastsave属性是一个时间戳,记录上一次成功执行save/bgsave命令的时间戳。

    通过这俩个命令,服务器成功执行一次修改操作,dirty计数器会加1,lastsave属性会记录上一次执行save/bgsave时间,redis服务器有个周期性操作函数serverCron,默认每隔100毫秒执行一次,检查saveparams数组中所有保存条件,只要有一个条件满足,就会执行bgsave命令。

 执行完成之后.dirty计数器重置为0,lastsave更改为该次执行命令的完成时间。

二、AOF持久化

当保存非临时数据时,为了降低redis故障而导致数据丢失,redis提供了aof持久化。aof将redis执行的每一条写命令追加到磁盘文件中,对性能有一定的影响,大部分情况这种影响可以接受,也可以使用读写速率高的磁盘来提高aof性能。redis启动优先选择从aof文件恢复数据。对比rdb,aof持久化丢失数据更少,消耗内存更多,因为rdb执行bgsave会有内存拷贝。开启AOF    使用命令config set或者配置文件修改,默认不开启。使用config rewriet同步到配置文件,不用重启redis,直接生效,修改配置文件需重启。

040fbf763cf855ef6d522b1eb7acb76d.png

  AOF持久化过程

       1.追加写入

          redis将每一条写命令以redis通讯协议添加至缓冲区aof_buf,在大量写请求的场景可以利用缓冲区暂存一部分命令,根据策略一次性写入磁盘,这样可以减少磁盘的I/O,提高性能。

       2.同步命令到硬盘

          当写命令写入aof_buf缓冲区后,redis会将缓冲区的命令写入文件,redis提供了三种同步策略,redis.conf 配置参数appendfsync。

         no: 不使用fsync方法同步,而是交给操作系统write函数去执行同步操作,linux大约30s刷一次缓冲。这种情况,缓冲区数据同步不可控,在大量的写操作下,aof_buf缓存区堆积会越来越严重,一旦redis出现故障,数据会丢失。

        always:每次有写请求会调用fsync方法强制内核将数据写入到aof文件。数据相对比较安全,但是每次写操作都会同步到aof文件中,性能会有一定影响,频繁的IO操作会影响硬盘的使用寿命。

        everysec:将调用操作系统write写入文件,并使用fsync每秒一次从内核刷新到磁盘。redis默认推荐使用该配置,这种方案能兼顾性能和数据安全。

        3.文件重写

           随的时间推移aof文件越来越大,redis会触发aof文件重写时候,使用bgrewirteaof对aof文件进行重写。这样可以减少aof文件大小且有利于数据恢复。

        如图:

dc5abee3a220734f0e4f0bc1b8c03e72.png

此时aof文件会记录三条命令,这显然不合理,因为文件中应只保留set lmf lmf3这条命令,前面的set命令都是多余的。重写时候策略条件:

       a.重复或者无效的命令不写入文件 

       b.过期的数据不再写入文件

       c.多条命令合并写入(当多个命令能合并一条命令时候会对其优化合并作为一个命令写入 如:rpush list1 a rpush list b 合并为"rpush list1 a b")

重写触发条件

aof文件触发条件分为手动触发和自动触发。

手动触发:客户端会执行bgrewriteaof命令。

自动触发:通过俩个配置协议生效。

auto-aof-rewrite-min-size:aof文件最小重写大小,当aof文件大于设置值才可能重写。auto-aof-rewrite-percentage:当aof文件大小和最后一次重写后大小之间的比率等于或者等于指定的增长百分比。如100代表代表当前aof文件是上次重写的倆倍时候才重写。redis开启aof时,会维持三个变量,分别是:a.记录当前aof文件大小的变量aof_current_sizeb.记录最后一次aof重写之后,aof文件大小的变量aof_rewrite_base_sizec.增长百分比变量aof_rewrite_perc

每次当serverCron(服务器周期性操作函数)函数执行时,它会检查条件是否满足,满足就会触发自动的aof重写操作。条件如下:

a.没有bgsave命令(rdb持久化)/aof持久化在执行

b.没有bgrewriteaof在进行

c.当前aof文件大小大于server.aof_rewrite_min_size的值

d.当前aof文件大小和最后一次重写后的大小之间的比率等于或者大于指定的增长百分比(auto-aof-rewrite-percentage参数)

重写过程

aof文件重写过程与rdb快照basave工作过程类似,都是通过fork子进程,由子进程完成响应的操作,同样的在fork子进程简短的时间内,redis是堵塞的。

        

aa7820315af1c3dce11d45518c1d3e71.png

过程解析:aof_rewrite_buf 代表重写缓冲区 aof_buf代表写命令存放的缓冲区
  1. 开始bgrewriteaof,判断当前有没有bgsave命令/bgrewriteaof在执行,有等这些命令执行完在执行。

  2. 主进程fork出子进程,这个极端的过程,redis是堵塞的。

  3. 主进程fork完子进程继续接受客户端请求,所有写命令依然写入aof文件缓冲区并根据appendfsync策略同步到磁盘,保证原有aof文件完整和正确。由于fork的子进程仅仅只共享主进程fork时的内存,因此redis采用重写缓冲区机制保存fork之后的客户端的写请求,防止新的aof文件生成期间丢失这部分数据。此时,客户端的写请求不仅仅写入原来aof_buf缓冲,还写入重写缓冲区。

  4. 子进程通过内存快照,按照命令重写策略写入到新的aof文件

    4.1 子进程写完新的aof文件后,向主进程发信号,父进程更新统计信息

    4.2  主进程把aof_rewirte_buf中的数据写入到新的aof文件(避免写文件数据丢失)

  5. 使用新的aof文件覆盖旧的aof文件,标志aof重写完成。

AOF实现本质

aof实现本质是基于redis通讯协议,将命令以纯文本方式写入到文件中。

redis协议:

以行来划分,每行以\r\n行结束。每一行都有一个消息头,消息头共分为5种分别如下:

(+) 表示一个正确的状态信息,具体信息是当前行+后面的字符。

(-)  表示一个错误信息,具体信息是当前行-后面的字符。

(*) 表示消息体总共有多少行,不包括当前行,*后面是具体的行数。

($) 表示下一行数据长度,不包括换行符长度\r\n,$后面则是对应的长度的数据。

(:) 表示返回一个数值,:后面是相应的数字节符。

查看我们aof文件的格式如图:

5852facffe2f3afe30211cf1a5fbcfd5.png

数据恢复

  aof开启后,redis数据恢复优秀选择aof进行数据恢复。

  模拟redis故障场景:先关闭redis 在启动redis

90c3125fe223b05a2d488d7a19f556c2.png

查看日志

16b71defa4b072fb6cb6050bf20c67fa.png

AOF配置参数

edee2d2f0181e47c02c3463316e511e9.png

6def29388a5ef3e7df0273a364b0c2c3.png

d8ab1587ff9a6340a870a8c91fdd9b57.png

模拟重写场景:

fed60ccd8637b456796638d947a51688.png

查看日志

1a493a8030429825982e0ee39874a6f5.png

三、RDB-AOF 混合持久化

redis4.0添加混合持久化方式,混合持久化同时使用rdb持久化和aof持久化混合写入aof文件,结合俩者的优点,快速加载同时避免丢失过多的数据,缺点aof的rdb部分压缩格式不再是aof方式,可读性差。

开启混合持久化

通过aof-user-rdb-preamble配置控制,yes开启,no禁用,5.0默认开启

a40d46420baa729ce2ffaed4cb2b6e8b.png

混合持久化过程

混合持久化也通过bgrewriteaof完成,当开启混合持久化时,fork子进程先将共享的内存副本全量的以RDB方式写入到aof文件,然后在将重写缓存区的增量命令以aof方式写入文件,写入完成后通知主进程更新统计信息,并将新的含有rdb格式和aof格式的aof文件替换旧的aof文件。新的aof文件前半段是rdb格式的全量数据,后半段是aof格式的增量数据。如图:

2222b5a79860db1567e80fd7aece4cf4.png

数据恢复

开启了混合持久化,启动redis依然优先加载aof文件,aof文件加载可能有俩种情况:
  1. aof文件开头是rdb格式,先加载rdb在加载aof

  2. aof文件开头不是rdb格式,直接以aof格式加载文件

模拟场景:

bb457d8d3aec2c3662300d38387d828f.png

查看日志:

4192063e863976154575ad39cca26d15.png

查看aof文件dc36bcc73335c22e152f6ad6c81af5f2.png四、RDB、AOF 、混合持久化优缺点RDB优点:
  1. rdb是一个非常紧凑的文件,体积小,传输速度快,适合灾难恢复。

  2. rdb可以最大化redis性能,父进程在保存rdb文件时只需fork子进程,子进程就会进行保存操作,父进程无需执行任何磁盘I/O操作。

  3. rdb在恢复大数据集速度比aof快。

缺点:

  1.  rdb是快照过程,无法完成保存所有数据,特别在数据量大的时候,发生故障丢失的数据更多。

  2. 当redis数据量大,rdb需要对数据进行完成拷贝并生成快照文件,fork子进程会消化cpu,数据量越大,耗时越多。

  3. rdb文件是特定的格式,阅读性差,因格式固定,可能会存在不兼容情况

AOF优点:
  1. 数据更完整,秒级数据丢失(取决于fsync策略设置)

  2. 兼容性好,aof文件是明文,基于reids通讯协议而形成的命令追加方式,阅读性好

缺点:

  1. 数据文件体积较大,即使有重写机制,在相同的数据集,aof文件比rdb大

  2. aof速度比rdb慢,数据量大的时候,恢复速度也比rdb慢

  3. aof由于要频繁将命令同步到文件中,对性能的影响也比rdb大,但这种影响可接受

混合持久化

优点:

      结合了rdb和aof持久化的优点,由于绝大部分都是rdb格式,加载速度快,同时结合aof,增量的数据以aof方式保存,数据更少的丢失

缺点:

        兼容性差,redis 版本<4 无法识别该aof文件,阅读性差,前部分是rdb格式

五、相关命令

aof文件检查 

b8b4aee24088f533e096e39ba9517f9f.png

rdb 文件检查:redis-check-rab  rab存放位置查看持久化信息 info persistence

aeca537272266951813c9e62285dd206.png

查看状态信息

f15fca8f48861afeeeac47878a160c07.png

本文相关系列文章redis 知识梳理(一)redis 知识梳理(二)如果有兴趣的小伙伴可以关注我,一起学习redis。

625392bbd34bbf2c9e0c83e5b7ef2cb2.png

更多推荐