redis持久化

redis如何实现数据不丢失:为了保证Redis数据不丢失,要把数据从内存存储到磁盘上,这就是Redis的数据持久化。Redis 数据持久化有三种方式:
1)AOF日志(Append Only File,文件追加方式):

  先执行命令把数据写入内存,然后再记录命令日志到文件中,重启时重新执行AOF文件中的命令以恢复数据,是目前redis持久化的主流方式。工作流程如下:记录客户端每一次写操作命令,并将这些写操作保存到aof文件末尾,在Redis服务器重启时,会加载并运行aof文件的命令,以达到恢复数据的目的。
  Redis为什么要先执行命令,再把数据写入日志?
由于Redis在写入日志之前,不对命令进行语法检查,所以只记录执行成功的命令,避免出现记录错误命令的情况,而且在命令执行后再写日志不会阻塞当前的写操作。
  Redis先执行命令,再把数据写入日志,有什么风险?
如果Redis刚执行完命令,此时发生故障宕机,会导致这条命令存在丢失的风险。AOF日志其实也是在主线程中执行,所以当Redis把日志文件写入磁盘的时候,还是会阻塞后续的操作无法执行。redis如果直接追加到硬盘,由于Redis是单线程,性能完全取决于硬盘负载,先写入缓冲区还可以提供多种同步到硬盘的策略。
  Redis默认不开启AOF持久化方式,我们可以在配置文件中开启并进行更加详细的配置,如下面的redis.conf文件

      # 开启aof机制
      appendonly yes
      # aof文件名
      appendfilename "appendonly.aof"
      # 写入策略,always表示每个写操作都保存到aof文件中,也可以是everysec或no
      appendfsync always
      # 默认不重写aof文件
      no-appendfsync-on-rewrite no
      # 保存目录
      dir ~/redis/
  

  aof文件的同步操作:通过appendfsync控制,取值有三种always、everysec、no。redis会启动一个线程把aof_buf即缓冲区的命令同步到磁盘aof文件中。

always: 命令写入aof_buf后,主线程同步调用系统fsync操作同步到AOF文件,fsync完成后线程返回
everysec: 默认写入策略,缓冲区每秒写入一次aof文件,因此,最多可能会丢失1s的数据
no: redis服务器不负责写入aof,而是交由操作系统来处理什么时候写入aof文件。更快,但也是最不安全的选择,不推荐使用

  大key对这三种策略的影响?always:主线程在执行fsync()函数的时候,阻塞的时间会比较久,因为当写入的数据量很大的时候,数据同步到硬盘这个过程是很耗时的。当使用 Everysec 策略的时候,由于是异步执行 fsync() 函数,所以大 Key 持久化的过程(数据同步磁盘)不会影响主线程。当使用 No 策略的时候,由于永不执行 fsync() 函数,所以大 Key 持久化的过程不会影响主线程

   aof文件过大,会占用磁盘空间,而且恢复过程很慢,所以引入aof重写机制。

  aof重写机制:aof文件存入了redis的写入命令,为了解决aof文件过大的问题,引入了aof重写。为了减小aof文件的体量,可以手动发送“bgrewriteaof”指令,通过子进程生成更小体积的aof,然后替换掉旧的、大体量的aof文件。大致工作原理:主进程创建子进程,子进程把数据转为写指令存入新的AOF文件时,记录的只是每个数据的最后一次写指令,也就是最新的数据,不会记录之前冗余的操作,所以这样会很大程度的缩小AOF的体量。与此同时父进程把新的写操作会同时写入旧的aof文件和缓冲队列中,子进程重写完成后会通知父进程,父进程把缓冲队列中的命令写入临时文件中,最后父进程用临时文件替换老的aof文件,完成aof重写

  aof对过期键怎么处理的?文件写入阶段:如果数据库某个过期键还没被删除,那么AOF文件会保留此过期键,当此过期键被删除后,Redis会向AOF文件追加一条DEL命令来显式地删除该键值。

  AOF 重写阶段:执行AOF重写时,会对Redis中的键值对进行检查,已过期的键不会被保存到重写后的 AOF 文件中,因此不会对 AOF 重写造成任何影响

 

 2)RDB快照(Redis DataBase):将某一个时刻的内存数据,写到二进制文件中,然后将文件写入磁盘中。RDB记录的是某一时刻的数据而不是操作,所以采用RDB方法做故障恢复时只需要直接把RDB文件读入内存即可,实现快速恢复,是redis默认的数据持久化方式

  RDB做快照时会阻塞线程吗?

  Redis提供了三个命令生成RDB快照文件,分别是save,bgsave。

save 命令在主线程中执行,会导致阻塞,直到RDB操作完成。bgsave命令会创建一个子进程,该子进程用于RDB持久化过程,避免了对主线程的阻塞,这也是Redis RDB的默认配置。子进程会根据父进程的内存生成快照文档,对磁盘原来的RDB文件进行原子替换。bgsave创建子进程的时候对主进程会有略微阻塞,时间很短,微秒级别。bgsave期间服务器拒绝执行save、bgsave、bgrewriteaof这三个命令,主要是防止线程间竞争产生问题。子进程创建RDB文件(dump.rdb)是一个压缩的二进制文件,压缩后的文件远远小于内存中的大小,保存在dir配置指定的目录下,通过它可以恢复Redis内存中的数据

  RDB生成快照文件时,数据还能被增删改吗?
可以的,如果生成快照文件期间数据不能被修改,是会有潜在问题的。假如生成快照的20s时间里,如果数据不能被修改,Redis就不能处理对这些数据的写操作,那无疑会给业务服务造成巨大影响。

如果是bgsave模式:

如果是读请求,正常执行。如果是写操作,则被修改的数据会复制一份副本,然后bgsave子进程会把该副本数据写入RDB文件,在这个过程中,主线程仍然可以直接修改原来的数据。这既保证了快照的完整性,也允许主线程同时对数据进行修改,避免了对正常业务的影响。

如果是save模式:

主线程被save命令阻塞,不能响应读写请求。

  可以每秒做一次快照么?
如果频繁地执行全量快照,会带来两方面开销:一是频繁将全量数据写入磁盘,会给磁盘带来很大压力。二是bgsave子进程需要从主线程fork出来,fork创建过程本身会阻塞主线程,而且主线程的内存越大,阻塞时间越长。

     既然频繁执行全量快照不行,那还有什么其他好方法吗?可以使用混合持久化
混合持久化是在AOF日志重写过程中完成的,当开启了混合持久化时,在AOF重写日志时,fork 出的子进程先将当前全量数据以RDB方式写入新的AOF文件,然后主进程处理的操作命令会被记录在重写缓冲区里,重写缓冲区里的增量命令会以AOF方式写入到AOF文件,写入完成后通知主进程将新的含有RDB格式和AOF格式的AOF文件替换旧的的AOF文件。也就是说,使用了混合持久化,AOF文件的前半部分是RDB格式的全量数据,后半部分是AOF格式的增量数据。
优点:前半部分RDB格式文件,使得redis可以快速恢复数据,同时结合了aof的优点,有减低了大量数据丢失的风险。
缺点:
a、AOF文件中添加了RDB格式的内容,使得AOF文件的可读性变得很差。
b、兼容性差,如果开启混合持久化,那么此混合持久化AOF文件,就不能用在Redis4.0之前版本了。

 

  上述介绍的是RDB的手动触发,下面介绍下自动触发方式,配置文件redis.conf,这种方式不建议,因为因为设置触发的时间太短,则容易频繁写入rdb文件,影响服务器性能,时间设置太长则会造成数据丢失

  配置 save m n,例如 save 900 1,表示900(saveparam.seconds)秒内数据集出现1次(saveparam.changes)修改时,执行bgsave。

     RDB方式,过期键是如何处理的?

     RDB 文件生成阶段:从内存状态持久化成 RDB(文件)的时候,会对 key 进行过期检查,过期的键「不会」被保存到新的 RDB 文件中,因此 Redis 中的过期键不会对生成新 RDB 文件产生任何影响。
      RDB加载阶段:RDB加载阶段时,要看服务器是主服务器还是从服务器,分别对应以下两种情况:
如果Redis是「主服务器」运行模式的话,在载入RDB文件时,程序会对文件中保存的键进行检查,过期键「不会」被载入到数据库中。所以过期键不会对载入RDB文件的主服务器造成影响;
如果Redis是「从服务器」运行模式的话,在载入RDB文件时,不论键是否过期都会被载入到数据库中。但由于主从服务器在进行数据同步时,从服务器的数据会被清空。所以一般来说,过期键对载入RDB文件的从服务器也不会造成影响

     大key对RDB的影响?AOF重写机制和 RDB 快照(bgsave 命令)的过程,都会分别通过 fork() 函数创建一个子进程来处理任务。会有两个阶段会导致阻塞父进程(主线程):

a、创建子进程的途中,由于要复制父进程的页表等数据结构,阻塞的时间跟页表的大小有关,页表越大,阻塞的时间也越长;
b、创建完子进程后,如果父进程修改了共享数据中的大 Key,就会发生写时复制,这期间会拷贝物理内存,由于大 Key 占用的物理内存会很大,那么在复制物理内存这一过程,就会比较耗时,所以有可能会阻塞父进程。

    数据量过大对RDB的影响?fork时子进程会复制父进程的页表等数据结构,父进程数据空间越大,页表越大,fork耗时越大。意味着主线程无法响应客户端请求,延迟较大 

 

3) 两种的优缺点以及应该选择哪种方式

RDB的优缺点:
优点:
a、RDB文件,压缩的二进制文件,是redis某个时间点的数据快照,适用于备份、全量复制、拷贝到远程机器或文件系统中用于灾备。
b、加载RDB文件恢复数据,远快于AOF
缺点:
a、无法实时持久化/秒级持久化,bgsave每次执行都要fork操作执行子进程,属于重量级操作,频繁执行成本过高。
b、RDB是特定二进制格式的文件,演进过程中有多个格式的RDB版本,存在老版本redis服务无法兼容新版RDB格式的问题。

AOF的优缺点:
优点:
可支持秒级的持久化(取决fsync策略,如果是everysec,最多丢失1秒的数据)
缺点:
对于相同的数据集,AOF文件的体积要大于RDB文件,数据恢复也会比较慢。

 

当RDB与AOF两种方式都开启时,Redis会优先使用AOF恢复数据,因为AOF保存的文件比RDB文件更完整
如果能够承受几分钟的数据丢失,比如缓存等,只需要使用RDB即可。
如果只用AOF,优先使用everysec的配置选择,因为它在可靠性和性能之间取了一个平衡

 

posted @   MarkLeeBYR  阅读(60)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
点击右上角即可分享
微信分享提示