redis-持久化

目录

一、RDB

RDB触发保存的两种方式

优劣势总结

二、AOF

AOF持久化流程:

1、开启AOP

2、异常恢复

3、AOF的同步频率设置

4、ReWrite压缩

5、优劣势总结

Redis 4.0 混合持久化


redis是内存数据库,所有的数据都会默认存在内存中,如果不进行持久化操作,当出现断电等问题,数据都不会保存

一、RDB


是指在时间间隔内将内存中的数据集快照写入磁盘。Redis会单独创建一个子进程来进行持久化,会先将数据写入一个临时文件中,待持久化都结束了,再用这个临时文件替换上一次持久化好的文件。整个过程中,主进程是不进行任何IO操作的,这就确保了极高的性能,如果需要进行大规模的数据恢复,且对于恢复的完整性不是非常敏感,那RDB方式要比AOF方式更加高效,RDB的缺点是最后一次持久化后的数据可能会丢失。在redis启动的时候会自动将rdb文件的数据读到内存中。

RDB触发保存的两种方式


1、自动触发
进入配置文件中将sava注释打开  

 首先 在默认配置下我们很难演示这个过程,所以需要对它进行修改

 新增了一条配置,在10秒内执行两次即可实现写入操作,修改完配置之后重启redis进行测试

现在data目录下是没有文件的

在10秒内输入三条命令

会将数据写入dump.rdb文件中

每次触发保存只会保存两条,根据save的条件进行保存。

-----------------------------------------------------------------------------------------------------------------------------

  • stop-writes-on-bgsave-error :默认值为yes。当启用了RDB且最后一次后台保存数据失败,Redis是否停止接收数据。这会让用户意识到数据没有正确持久化到磁盘上,否则没有人会注意到灾难(disaster)发生了。如果Redis重启了,那么又可以重新开始接收数据了
  • rdbcompression ;默认值是yes。对于存储到磁盘中的快照,可以设置是否进行压缩存储。如果是的话,redis会采用LZF算法进行压缩。如果你不想消耗CPU来进行压缩的话,可以设置为关闭此功能,但是存储在磁盘上的快照会比较大。
  • rdbchecksum :默认值是yes。在存储快照后,我们还可以让redis使用CRC64算法来进行数据校验,但是这样做会增加大约10%的性能消耗,如果希望获取到最大的性能提升,可以关闭此功能。
  • dbfilename :设置快照的文件名,默认是 dump.rdb
  • dir:设置快照文件的存放路径,这个配置项一定是个目录,而不能是文件名。默认是和当前配置文件保存在同一目录。
  • 也就是说通过在配置文件中配置的 save 方式,当实际操作满足该配置形式时就会进行 RDB 持久化,将当前的内存快照保存在 dir 配置的目录中,文件名由配置的 dbfilename 决定。

2、手动触发
①、save
        该命令会阻塞当前Redis服务器,执行save命令期间,Redis不能处理其他命令,直到RDB过程完成为止。
        显然该命令对于内存比较大的实例会造成长时间阻塞,这是致命的缺陷,为了解决此问题,Redis提供了第二种方式。
②、bgsave

        执行bgsave命令的时候,redis会自己fork出一条子进程,由这条子进程去执行,这样就不会影响到客户端对于redis 的正常操作 有意思的是,我们都知道,进程与进程之间的内存不是共享的,那么子进程是如何获取到主进程的内存数据呢?
真像是在主进程fork子进程的同时,会把自己内存中的数据同时复制一份给子进程,这样就相当于子进程可以读取到主进程的数据了,然后子进程就可以愉快的进行io操作了.(将内存中的数据写入磁盘中).有的小伙伴可能会问,那么这个复制内存的操作是立即执行的吗,其实并不是的,正常情况下redis的服务大部分都是读操作,在fork子进程的时候,子进程其实并没有直接复制一份主进程的数据,而是给他分配了一个虚拟的内存地址,指向了父进程的内存地址,如果在fork期间客户端发起了新的操作,父进程的内存数据发生改变的时候才会进行复制内存的操作,此时子进程使用副本内存进行写入rdb文件,而主进程使用原始内存继续进行写入操作。为了性能,基本上 Redis 内部所有的RDB操作都是采用 bgsave 命令,也就是自动提交。

写时复制:

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

③、flushall

执行执行 flushall 命令,也会产生dump.rdb文件,但里面是空的,没有意义。

save于bgsave对比

命令

save

bgsave

IO类型

同步

异步

是否阻塞redis其它命令

否(在生成子进程执行调用fork函数时会有短暂阻塞)

复杂度

O(n)

O(n)

优点

不会消耗额外内存

不阻塞客户端命令

缺点

阻塞客户端命令

需要fork子进程,消耗内存

优劣势总结

优势

  • 适合大规模数据恢复
  • 对数据完整性和一致性要求不高更适合使用
  • 节省磁盘空间(rdb文件一般来说都会比aof文件要小很多)
  • 数据恢复快

劣势

  • 数据不完整性
  • 在fork子进程的时候需要消耗两倍的内存。

二、AOF


以日志的形式来记录每个写操作(增量保存),将Redis执行过的所有指令记录下(读操作不记录),只需追加文件但不可以改写文件,Redis启动之初会读取该文件重新构建数据,换言之,redis重启的话就根据日志文件的内容将写指令从头到尾执行一次以完成数据恢复工作。

AOF持久化流程:

  1. 客户端的请求写命令会被append追加到AOF缓冲区;
  2. AOF缓冲区根据AOF持久化策略【always,everysec,no】将操作sync同步到磁盘的AOF文件中;
  3. AOF文件大小超过重写策略或手动重写时,会对AOF文件rewrite重写,压缩AOF容量;
  4. redis服务重启时,会重新load加载AOF文件中的写操作达到数据恢复的目的

1、开启AOP


在Redis中AOF是默认不开启的需要我们手动开启

 搜索appendonly找到该位置

redis-持久化_第1张图片

将no改成yes

redis-持久化_第2张图片

 重启redis即可看到aof文件

要点: 当AOF和RDB同时开启的时候,系统默认读取AOF的数据(数据不会丢失),所以之前如果用的是rdb持久化数据再转成AOF,那么就读取不到之前的数据。

打开了之后每执行一指令就会自动持久化

2、异常恢复


当AOF文件出现异常的时候,redis的客户端时不能正常连接的,这时候需要我们修复文件

现在先模拟一下异常情况:

①、先存入几条数据

②、打开编辑aof文件

redis-持久化_第3张图片

在里面加入自定义字符串让文件出错

redis-持久化_第4张图片

然后重启一下redis,重新启动redis客户端,会发现已经不能连接了

 ③、解决方案

 容器启动不起来,我们不能进入容器中的/usr/local/bin/找到redis-check-aof。但是有其他的方法

输入 :

docker inspect 容器id  


Ⅰ、先找到备份的aop叫什么名字(以防不是默认文件名的情况)

redis-持久化_第5张图片

找到了data,就是我们存放aof文件的位置,而source就是宿主机数据卷的位置,复制一下source的路径进入其中

可以看到aof文件,这里我用的是默认名字

Ⅱ、找到修复文件工具(redis-check-aof)

我们知晓这个工具的具体名字 可以直接通过find命令找到

find  / --name “文件名”  

 找到文件后直接执行

找到的文件名加上 --fix  后面跟着aof文件的路径执行即可

3、AOF的同步频率设置

  •  1、appendfsync always  

始终同步,每次Redis的写入都会立刻计入日志;性能较差但数据完整性较好。

  • 2、appendfsync everysec

每秒同步,每秒计入日志一次,如果宕机,本秒的数据可能会丢失

  • 3、appendfsync no

redis不主动进行同步,把同步时机交给操作系统

4、ReWrite压缩


Aof采用文件追加方式,文件会越来越大,为了避免出现这种情况,新增了重写机制,当AOF文件大小超过所设定的阈值时,Redis就会启用AOF文件的内容压缩,只保留可以恢复的数据的最小指令集,也可以使用bgrewriteaof手动压缩

如何实现?

AOF文件持续增长时,会fork出一条新进程来将文件重写(也就是先写入临时文件,最后再rename),而父进程继续接受命令,现在的写操作命令都会被额外添加到一个aof_rewrite_buf_blocks缓冲中当子进程rewrite结束后,父进程收到子进程退出信号,把aof_rewrite_buf_blocks的缓冲添加到rewrite后的文件中,然后切换AOF的文件fd。

重写策略?

 如上图所示,上图配置的大体意思为当AOF文件大小超过了64m并且超过了64m的100%(128m)就开始重写。

# auto-aof-rewrite-min-size 64mb //aof文件至少要达到64M才会自动重写,文件太小恢复速度本来就很快,重写的意义不大

# auto-aof-rewrite-percentage 100 //aof文件自上一次重写后文件大小增长了100%则再次触发重写

appendfsync-on-rewrite

同时在执行bgrewriteaof操作和主进程写aof文件的操作,两者都会操作磁盘,而bgrewriteaof往往会涉及大量磁盘操作,这样就会造成主进程在写aof文件的时候出现阻塞的情形,现在no-appendfsync-on-rewrite参数出场了。如果该参数设置为no,是最安全的方式,不会丢失数据,但是要忍受阻塞的问题。如果设置为yes呢?这就相当于将appendfsync设置为no,这说明并没有执行磁盘操作,只是写入了缓冲区,因此这样并不会造成阻塞(因为没有竞争磁盘),但是如果这个时候redis挂掉,就会丢失数据。丢失多少数据呢?在linux的操作系统的默认设置下,最多会丢失30s的数据

5、优劣势总结

优势

  • 备份机制更加稳健,丢失数据概率更低
  • 可读的日志文本,通过操作AOF稳健,可以处理错误操作

劣势

  • 比起rdb更占用磁盘(除了要记录数据,还记录了指令)
  • 恢复备份速度更慢
  • 每次读写都同步的话,有一定的性能压力
     

Redis 4.0 混合持久化

重启 Redis 时,我们很少使用 RDB来恢复内存状态,因为会丢失大量数据。我们通常使用 AOF 日志重放,但是重放 AOF 日志性能相对 RDB来说要慢很多,这样在 Redis 实例很大的情况下,启动需要花费很长的时间。 Redis 4.0 为了解决这个问题,带来了一个新的持久化选项——混合持久化。

通过如下配置可以开启混合持久化(必须先开启aof):

# aof-use-rdb-preamble yes

原理

如果开启了混合持久化,AOF在重写时,不再是单纯将内存数据转换为RESP命令写入AOF文件,而是将重写这一刻之前的内存做RDB快照处理,并且将RDB快照内容和增量的AOF修改内存数据的命令存在一起,都写入新的AOF文件,新的文件一开始不叫appendonly.aof,等到重写完新的AOF文件才会进行改名,覆盖原有的AOF文件,完成新旧两个AOF文件的替换。

于是在 Redis 重启的时候,可以先加载 RDB 的内容,然后再重放增量 AOF 日志就可以完全替代之前的 AOF 全量文件重放,因此重启效率大幅得到提升。

混合持久化AOF文件结构如下

redis-持久化_第6张图片

你可能感兴趣的:(redis,redis)