快捷搜索:  汽车  科技

redis持久化的机制(Redis的持久化)

redis持久化的机制(Redis的持久化)持久化策略的配置项为:save N M,//让redis在“N秒内至少有M个改动”才会触发一次rdb的持久化操作。Redis DataBase 快照持久化。所谓的快照,在这里指的是某一时刻的内存数据,而持久化则是将这一时刻的数据以二进制形式写入到磁盘中,文件名字为dump.rdbredis的持久化机制可以分为两种,即RDB与AOF。RDB:Redis DataBase,将某一时间点的当前数据以快照的形式保存下来,存储格式简单,关注点在于数据,存储的是二进制数据AOF:Append Only File,将数据的操作过程(读命令不记录)以日志形式进行存储,存储格式复杂,关注点在操作过程。

为什么需要持久化

我们知道Redis是一款内存数据库,为提升性能,它把所有数据全部存储在内存中,而内存内的数据并不是永久地保留下来,服务器出现宕机或重启后,内存数据会先清空。redis在此之前存在内存的数据也会被清空,这样有问题吗?

不,不一定有问题,这是一款定位为内存型的数据库,数据存在内存上被清空了,不是很正常吗?这么说,好像也有道理。我说不一定有问题是有前提下,例如在某些场景下,我们使用redis来缓存一些配置数据,数据量不大,原始数据都在关系型数据上存着,如果重启后,内存没数据,调用一次数据库查询命令,把数据加载回来就好了。这种场景似乎也是可以不用持化的。

那说了不一定有问题的场景后,哪些场景不用持久化会有问题呢?在现代的互联网时代,高并发,高性能,高可用,大数据量都是基本的需求了,在这种高压的情况下,如果redis没有持久化,这大量的请求与大量的数据查询命令打到数据库上,不用说,数据库也被打垮了,这时就会牵一发死全身,整个平台涉及到这个数据库的业务都不可用了,而依赖这些服务的其他业务也变得不可用了,这种场景,不敢想像。所以,综合,redis需要持久化吗?

持久化使得redis服务器重启时,可以通过重新加载存储在硬盘中的数据,快速地恢复到redis服务器宕机前的状态。那么redis的持久化有哪些方式呢?这些方式都有哪些差别与优缺点呢?请看下文介绍

持久化有哪些方式

redis的持久化机制可以分为两种,即RDB与AOF。

RDB:Redis DataBase,将某一时间点的当前数据以快照的形式保存下来,存储格式简单,关注点在于数据,存储的是二进制数据

AOF:Append Only File,将数据的操作过程(读命令不记录)以日志形式进行存储,存储格式复杂,关注点在操作过程。

redis持久化的机制(Redis的持久化)(1)

redis持久化的机制(Redis的持久化)(2)

一、RDB

Redis DataBase 快照持久化。所谓的快照,在这里指的是某一时刻的内存数据,而持久化则是将这一时刻的数据以二进制形式写入到磁盘中,文件名字为dump.rdb

1、自动触发机制

持久化策略的配置项为:save N M,//让redis在“N秒内至少有M个改动”才会触发一次rdb的持久化操作。

例如redis的默认策略有:(这里的配置是使用bgsave来完成)

save 900 1 -- 900秒内至少有一个改动 save 300 10 -- 300秒内至少有10个改动 save 60 10000 -- 60秒内至少有10000个改动

上述的配置是使redis满足一定的条件后,会自动触发一次生成快照,同样也可以使用手动触发生成快照文件,即命令save或bgsave。

redis持久化的机制(Redis的持久化)(3)

2、手动触发机制2.1 save命令-阻塞式持久化

Redis处理命令的方式是以单线程形式进行的,客户端的请求都会放到一个队列里,当执行save命令时,如果执行时间很长的话,后面的命令请求就会被阻塞,客户端所发送的命令都会被拒绝

redis持久化的机制(Redis的持久化)(4)

2.2 bgsave命令-利用子进程,非阻塞式持久化

与save不同的是,执行过程中,它并不会阻塞客户端的请求。它将持久化的工作交给了子进程来执行,主进程还是可以如常地处理来前客户端的请求

Redis借助了linux系统的写时复制(Copy-On-Write)技术,在生成快照的同时,仍然可以接收命令处理数据。简单来说,bgsave线程是由主线程fork生成的子线程,可以共享主线程所有的内存数据。bgsave线程运行后,开始读取主线程的内存数据,也就是redis的内存数据,将内存数据写入到dump.rdb文件中。此时如果主线程处理的命令都是读操作,则bgsave线程不受影响。如果主线程处理了写操作,则会对该命令操作的数据复制一份,生成副本,bgsave线程把这个副本写入到dump.rdb文件中,而这个过程中,主线程仍可执行命令。

redis持久化的机制(Redis的持久化)(5)

2.3 save与bgsave的对比

save

bgsave

IO类型

同步

异步

是否阻塞其它命令

否(调用系统生成子进和fork时会阻塞)

复杂度

O(n)

O(n)

优点

不会消耗内存

不阻塞其它命令

缺点

阻塞操作

会消耗额外的内存

配置自动生成rdb文件后台使用的是bgsave方式。

RDB的优缺点:

  • 优点:
    • RDB是一个紧凑压缩的二进制文件,存储效率高
    • RDB内部存储的是redis在某个时间点的数据快照,非常适合用于数据备份,全量复制等场景
    • RDB恢复数据的速度要比AOF快得多
    • 应用:服务器中每X小时执行bgsave备份,并将RDB文件拷贝到远程机器中,用于灾难恢复
  • 缺点
    • RDB方式无论是执行指令还是利用配置,无法做到实时持久化,具有较大的丢数据的可能性
    • bgsave指令每次运行都要执行fork操作创建子进程,要牺牲一些性能
    • Redis的众多版本中未进行RDB文件格式的版本统一,有可能出现各版本之间数据格式无法兼容现像(处理方式:可以降低版本的rdb读出来,然后存在高版本的大redis)
二、AOF

AOF:append only file,以独立日志的方式来记录每次命令(查询命令除外),只允许追加文件,不允许修改文件,类似于mysql的binlog日志文件一样。Redis启动时会读取AOF文件中的所有操作命令,然后执行,这就有点像一个人一生所有事件的回顾,直至到把所有事件执行完成,启动成功,并完成数据的恢复工作。

AOF写数据过程
  1. redis收到来自客户端的操作命令,先存一个在队列中,命令得一个一个执行
  2. redis把命令执行成功后,会把该命令执行的日志写到系统的缓冲区(Buffer)
  3. redis并不会对命令进行语法检验,只记录执行成功的命令,失败的命令不会记录下来,避免日后恢复时也出现失败的情况
  4. 写到buffer的数据,redis会按照设置的策略(always everysec no)调用操作系统的write函数把buffer中的数据刷到磁盘中去
  • always:每次写操作都同步到 AOF 文件中,数据零误差,性能较低,不建议使用。
  • everysec:每秒将缓冲区中的指令同步到 AOF 文件中,数据准确性较高,性能较高,是默认配置中,建议使用。(在系统突然宕机的情况下丢失1秒内的数据)
  • no:由操作系统控制每次同步到 AOF 文件的周期,整体过程不可控。

不管是always还是everysec,都是redis调用系统的write函数方法来把缓冲区的数据刷到磁盘,而no的策略是依操作系统而定,有可能是缓冲区的数据满了或达到某一时间后,会自行地调用内核函数方法刷到磁盘上,但这种方式往往不可控,因为不知道要隔多久才会被刷到磁盘上,如果此时redis宕机了,丢失的就是缓冲区里的所有数据,这些数据是多长时间,多少,不知道。

redis持久化的机制(Redis的持久化)(6)

AOF的相关配置

appendonly yes|no #是否开启 AOF 持久化功能,默认为不开启状态 appedsync always|everysec|no #AOF 写数据策略 appendfilename filename #AOF 持久化文件名,默认文件名未 appendonly.aof,建议配置为 appendonly-端口号.aofAOF的恢复流程

redis持久化的机制(Redis的持久化)(7)

AOF的重写

随着命令不断地写入AOF,AOF的文件只会越来越大,为了解决这个问题,Redis引入了AOF的重写机制,用于压缩文件的体积,简单来说就是将同一数据的若干条指令简化为一条指令进行记录

AOF重写的作用

  • 降低磁盘占用量,提高磁盘的利用率
  • 降低持久化写的时间,提高持久化效率
  • 降低数据恢复用时,提高数据恢复效率

AOF重写配置如下

auto-aof-rewrite-percentage 100 //AOF文件距离上次文件增长超过多少百分比 auto-aof-rewrite-min-size 64mb //AOF文件体积最小多大以上触发

同时满足所设置的条件时,会自动触发 AOF 重写,此时 Redis 会扫描整个实例的数据,重新生成一个 AOF 文件来达到瘦身的效果。

当然我们也可以用手动方式来执行AOF的重写:bgrewriteaof

AOF的重写流程

  1. bgrewriteaof触发重写,判断是否存在save或bgsave正在执行,存在则等待执行结束再执行
  2. 主进程foak子进程,防止主进程阻塞而无法对外提供服务
  3. 子进程遍历Redis内存快照中数据写入临时AOF文件,同时会将新的写指令写入aof_buf各aof_rewrite_buf两个缓冲区,前者是为了写回旧的AOF文件,后者是为了后续刷新到临时AOF文件中,防止快照内存遍历时新的写入操作丢失
  4. 子进程结束临时AOF文件写入后,通知主进程
  5. 主进程会将上面的aof_rewrite_buf缓冲区的数据写入到子进程生成的临时AOF文件中
  6. 主进程使用临时AOF文件替换旧AOF文件,完成整个重写过程

redis持久化的机制(Redis的持久化)(8)

三、混合RDB与AOF的对比

优点

缺点

RDB

1、文件体积小:RDB 的文件内容是二进制格式,因此体积比实例内存小

2、恢复速度快

1、数据缺失:RDB 保存的是某一时刻的数据,当 Redis 实例某一时刻异常时,会导致数据丢失

2、消耗资源:RDB 文件的生成会消耗大量的 CPU 和内存资源,有一定代价

AOF

1、数据更完整:AOF 中是及时写入的方式,数据保存更完整。恢复时降低数据的损失。

2、易读性强:AOF 中保存的数据格式是客户端的写入命令,可读性性强。

1、文件体积大:AOF 中存储客户端所有的写命令,未经压缩,随着命令的写入,文件会越来越大。

2、增加磁盘IO:AOF 文件刷盘如果采用每秒刷一次的方式会导致磁盘IO升高,影响性能

结合着以上两种方式的优缺点,Redis4.0推出了一种混合型持久化方式,其实就是RDB与AOF的结合,吸收其优点,规避其缺点

持久化方式

通过 aof-use-rdb-preamble 参数来开启的。它的操作方式是这样的,在写入的时候先把数据以 RDB 的形式写入文件的开头,再将后续的写命令以 AOF 的格式追加到文件中。这样既能保证数据恢复时的速度,同时又能减少数据丢失的风险。

文件恢复

在 Redis 重启时,先加载 RDB 的内容,然后再重放增量 AOF 格式命令。这样就避免了 AOF 持久化时的全量加载,从而使加载速率得到大幅提升。

总结

混合型的持久化似乎更符合我们的各个需求场景,但如果我们之前使用了4.0之前的版本,我双该如何选择呢?下面给一下参考吧,因为没有哪一个方案是完美的,一个技术选型,如果不考虑场景与业务,都是瞎搞。

1、综合的参数对比

RDB

AOF

占用存储空间

小(数据级:压缩)

大(指令级:重写)

存储速度

恢复速度

数据安全性

会丢失数据

依据策略而定

性能要求越高,数据丢失概率越大,丢失数据越多

资源消耗

高/重量级

低/轻量级

启动优先级

启动优先级解释: 如果两者都选择了情况下,重启 redis 服务器加载数据会先选择 AOF

2、对数据非常敏感, 建议使用默认的 AOF 持久化方案

(1)AOF持久化策略使用 everysec,每秒钟 fsync 一次。该策略下 redis 仍可以保持很好的处理性能, 当出现问题时,最多丢失0-1秒内的数据。

(2)注意:由于AOF文件存储体积较大,且恢复速度较慢

3、数据呈现阶段有效性,建议使用 RDB 持久化方案

(1)数据可以良好地做到阶段内无丢失(该阶段是开发者或运维人员手工维护的),且恢复速度较快,阶段点数据恢复通常采用 RDB 方案

(2)注意:利用 RDB 实现紧凑的数据持久化会使 Redis 效率降的很低

4、综合而言

a、RDB 与 AOF 的选择实际上是在做一种权衡,每种都有利有弊

b、如不能承受数分钟以内的数据丢失,对业务数据非常敏感, 选用 AOF

c、如能承受数分钟以内的数据丢失, 且追求大数据集的恢复速度, 选用 RDB

d、灾难恢复选用 RDB

e、双保险策略, 同时开启 RDB 和 AOF, 重启后, Redis 优先使用 AOF 来恢复数据,降低丢失数据的量

猜您喜欢: