分布式缓存之Redis持久化
迪丽瓦拉
2025-05-29 07:16:42
0
单点Redis的问题:
1.Redis是内存存储,服务重启 可能会丢失数据。
2.单节点Redis并发能力虽然不错,但也无法满足如618这样的高并发场景。
3.如果Redis宕机,则服务不可用,需要一种自动的故障恢复手段。
4.Redis基于内存,单节点能存储的数据量难以满足海量数据需求。
解决:
1.数据丢失问题:实现数据持久化,将数据写入磁盘
2.并发能力问题:搭建主从集群,实现读写分离
3.故障恢复问题:利用Redis哨兵,实现健康检测和自动恢复
4.存储能力问题:搭建分片集群,利用插槽机制实现动态扩容

1.RDB持久化

RDB全称Redis Database Backup file(Redis数据备份文件),也被叫做Redis数据快照。简单来说就是把内存中的所有数据都记录到磁盘中。当Redis实例故障重启后,从磁盘读取快照文件,恢复数据。
      快照文件称为RDB文件,默认保存在当前运行目录。

1.如何启动RDB:直接redis-cli -> save

注意:由Redis主进程来完成,但Redis是单线程的,RDB是将数据写到磁盘,磁盘的IO比较慢,如果数据量又很大就要耗时很久,在此期间,无法处理其他的请求,只适合停机时使用。(不推荐)


2.bgsave

运行那一刻就返回结果,在后台异步执行保存操作。主进程不受影响,可以正常处理请求。


3.主动停机时会自动进行一次RDB,在运行目录生成dump.rdb文件。

./redis-cli -a 密码 shutdown:如果redis是后台启动可以这样关闭。
       如果要查看Redis输出日志需要在redis.conf中找到logfile "",后面填写路径(绝对路径),loglevel是日志等级默认notice,有debug,verbose,notice,warning.

问题1:

redis会在自己正常停机时保存,但如果redis是宕机的就不会保存了。

解决:

每隔一段时间,数据就备份一次。


4.Redis内部有触发RDB的机制,可以在redis.conf文件中找到


存入一个值后在日志中就可以看到这样一个日志

实现了每隔一段时间保存一次。RDB的时间不能设置过长(没有持久化,在这段时间宕机的话数据会丢失),也不能过短(频率过高,来不及处理),一般就默认。所以还要有其他持久化方案来弥补RDB方案。


5.RDB的其他配置


RDB如何实现异步持久化

bgsave开始时会fork主进程得到子进程,子进程共享主进程的内存数据。完成fork后读取内存数据并写入RDB文件。 
    问题2:

主进程的子进程是异步执行的,但fork是主进程执行的会堵塞其他请求

解决:尽量缩短fork的时间

fork底层实现

        在Linux系统中所有的进程度无法直接操作物理内存,而是操作系统给每个进程分配虚拟内存,主进程只能操作虚拟内存,而操作系统会维护一个虚拟内存与物理内存之间的映射关系表,这个表称之为页表。所以主进程操作于虚拟内存,而虚拟内存基于页表的映射关系到物理内存真正的存储位置。这样就能实现对物理内存数据的读写。

执行fork时,会去创建一个子进程,拷贝主进程的页表,也就是把映射关系拷贝给子进程。而子进程有了和主进程一样的映射关系,当子线程在操作自己的虚拟内存时,由于映射关系和主进程一样,所以可以映射到相同的物理内存区域,这样就实现了子进程和主进程内存空间的共享。

这样就无需拷贝内存中的数据,直接实现内存共享,这个速度就会变得非常快,堵塞的时间就尽可能缩短了,而后子进程就可以读取自己的数据了,而后写入磁盘的文件中去。这样异步持久化就实现了。


问题3:

子进程在写数据到磁盘中的时候,主进程是可以接收请求修改内存中的数据的,这样可能会出现脏数据。

解决:

fork采用的是copy-on-write技术:

1.当主进程执行读操作时,访问共享内存;

     2.当主进程执行写操作时,则会拷贝一份数据,执行写操作;


fork会将主进程和子进程共享的数据标记成read-only(只读模式),如果主进程要写的话就需要先将数据拷贝出来再执行写操作。如果执行了拷贝,主进程以后读也要到拷贝出来的地方读。


问题4:

在极端情况下可能会发生子进程写得比较慢,耗时比较久,而在写的过程中,不断有新的请求来修改共享数据,导致所有的数据都修改了,那么这种情况下所有数据都要拷贝一份新的导致内存翻倍。

解决:

一般情况下Redis都要预留一些内存空间,防止在做RDB时有内存溢出问题。


RDB总结

1.RDB方式bgsave的基本流程

1.fork主进程得到一个子进程,共享内存空间

      2.子进程读取内存数据并写入新的RDB文件

      3.用新RDB文件替换旧的RDB文件

2.RDB的执行时间

  1. 默认是服务停止时。(save)

  1. 满足配置文件中save条件时(bgsave)

3.RDB的缺点

  1. RDB执行间隔时间长,两次RDB之间写入数据有丢失的风险

  1. fork子进程,压缩,写出RDB文件都比较耗时


2.AOF持久化

AOF全称为Append Only File(追加文件)。Redis处理的每一个写命令都会记录在AOF文件,可以看做是命令日志文件。

注意:AOF默认是关闭的,需要修改redis.conf配置文件来开启AOF


注意:AOF的命令记录的频率也可以通过redis.conf来配置

appendfsync always:    主进程立即将接收到的命令写到内存再记录AOF文件。
appendfsync everysec:将接收到的命令写到内存,再放到缓冲区,每隔一秒将缓冲区的内容写到AOF文件,不是主进程往磁盘里写,性能得到了提高(内存方式的读写)

配置项

刷盘时机

优点

缺点

Always

同步刷盘

可靠性高,几乎不丢失数据

性能影响大

everysec

每秒刷盘

性能适中

最多丢失1秒数据

no

操作系统控制

性能最好

可靠性较差,可能丢失大量数据


更改配置后重启

1.输入写命令后会生成AOF文件

2.关闭redis时会有AOF数据的再次检查

3.重启后数据会从AOF文件做一次加载

这样就实现了持久化和故障恢复


问题5:

RDB记录的是文件的值,而AOF记录的是操作,如果对同一个值做多次修改操作,RDB记录的只是最后的值,而AOF会记录每次的值,这样的话会导致AOF文件比RDB文件大很多。并且前面的操作都是多余的。

解决:

   因为是记录命令,AOF文件会比RDB文件大得多。而且AOF会记录对同一个key的多次写操作,但只有最后一次写操作才有意义。通过执行bgrewriteaof命令,可以让AOF文件执行重写功能,用最少的命令达到同样的效果。


注意:

Redis也会在触发阈值时自动去重写AOF文件。阈值可以在redis.conf中配置


3.RDB和AOF的区别

RDB和AOF各自有自己的优缺点,如果对数据安全性要求较高,在实际开发中往往会结合两者来使用。

RDB

AOF

持久化方式

定时对整个内存做快照

记录每一次执行的命令

数据完整性

不完整,两次备份之间会丢失

相对完整,取决于刷盘策略

文件大小

会有压缩,文件体积小

记录命令,文件体积很大

宕机恢复速度

很快

数据恢复优先级

低,因为数据完整性不如AOF

高,因为数据完整性更高

系统资源占用

高,大量CPU和内存消耗

低,主要是磁盘IO资源,但AOF重写时会占用大量CPU和内存资源

使用场景

可以容忍数分钟的数据丢失,追求更快的启动速度

对数据安全性要求较高常见

相关内容