ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Redis-持久化

2026/8/25 7:24:29 拓冰建站 浏览量
Redis-持久化

先来回顾一下mysql的事务特性:

事务: 多条语句,要么全部执行成功,要么全部失败.

1.原子性:

组成一个事务的多个数据库操作是一个不可分割的原子单位,只有所有的操作都执行成功,整个事务才会提交;任何一个操作失败,已经执行的任何操作都要撤销,恢复到执行前的状态。

2.一致性:

事务中执行的操作和状态改变是一致的,写入的数据必须符合规则,即数据不会被破坏。

例如:a向b转账100元,不管操作是否,a ,b的账户总额是不变的。

3.持久性:

一旦事务提交成功,事务中的所有操作必须持久化到数据库中。

4.隔离性.:

在并发数据操作时,不同的事务有各自的数据空间,他们的操作不会对彼此产生干扰。


mysql数据库里的持久性就是这里的持久化,将数据存储在硬盘上就是持久的;而保存在内存上是不持久的。即重启进程或主机后,数据是否还存在。

目录

redis的持久性:

数据插入,查找策略:

redis实现持久化策略:

RDB:

1.手动触发:save

2.自动触发:bgsave

dump.rdb文件:

触发快照执行流程:

观察快照替换过程:

redis生成快照时机:

1.通过配置文件,自己设定触发条件

2.通过shutdown命令,关闭redis服务器,

当rdb文件坏了,会咋样呢?

RDB存在的问题:

AOF:

开启aof文件:

aof的实时存储:

appendfsync:

重写机制:

重写流程:

混合持久化:


redis的持久性:

redis是把数据存储在内存中的,但内存中的数据不具有持久性,一旦重启进程,原来的数据就不存在了,要想做到持久化,就需要将数据存储到硬盘上,但是redis相较于mysql的优势是操作数据效率高,当将数据存储到硬盘上时,就要通过硬盘读写数据,又没法保证其特性,于是redis将数据在内存和硬盘中都存储了一份数据。代价是同一份数据存储了两遍,消耗了更多的空间。(但硬盘相对来说比较便宜,成本并没有很高)

数据插入,查找策略:

当要插入一个新的数据时,将这个数据同时写到内存和硬盘中(根据不同的策略写入,保证效率);当查询数据的时候,直接从内存中读取;硬盘中的数据是在redis重启的时候,恢复内存中的数据的。

redis实现持久化策略:

redis实现持久化策略有两种:

1.RDB(redis dataBase): 定期备份

2.AOF(append only file):实时备份

RDB:

定期将redis内存中的所有数据,写入到硬盘中,生成一个“快照”;后续redis一旦重启了,内存中的数据就会消失,就可以根据“快照”,将内存中的数据恢复。

定期存储又分为两种方式:

1.手动触发:save

程序员通过redis客户端执行特定的命令save,来触发快照,执行save命令的时候,redis会全力以赴的进行“快照生成”操作,由于redis是单线程的,此时就会阻塞redis其他客户端的命令,因此手动触发不建议使用

2.自动触发:bgsave

在redis的配置文件conf中,进行设置,让redis每隔多长时间/产生多少次数据修改 就自动触发快照。(当然,也可以通过手动执行bgsave的命令,触发快照)

redis的自动触发是通过多进程来实现并发编程的.

dump.rdb文件:

redis生成的镜像文件(快照)是存储在dump.rdb文件中的,可以在redis的配置文件中看到。dump.rdb是二进制文件,而非文本文件,由于该文件是在内存中存于的,以二进制形式存储就是为了将文件中的数据进行压缩,这样虽然消耗一定的cpu资源,但能节省空间。(很多数据都会采取这样的方式存储,都是为了节省内存空间)

注意:不要对dump.rdb文件进行乱改,当发现格式错误,很可能会加载数据失败。(即使自己没有对其修改,该文件也有可能被破环,通过网络传输引起文件被破环等,此时redis服务器就无法去启动)

由于该文件很有可能被修改,于是redis为dump.rdb文件提供了一个检查工具:redis-check-rdb*.

打开dump.rdb文件看一下:

可以看到这里已经存储一些二进制数据了,是之前操作设置的数据的快照.

手动执行bgsave:

再插入2条数据:

查看dump.rdb文件,新插入的数据已经存在,说明是新的快照.

注:  这里的仅插入了两条数据, bgsave命令是立即完成的,若是数据量很大,执行bgsave就需要花费一些时间了.

触发快照执行流程:

当一个redis客户端触发bgsave命令的时候,先会判断是否有其他进程也触发了该命令,若有其他进程正在执行,就直接返回;若没有,就执行fork命令:将父文件(保存在内存中的文件)复制一份,作为子文件,存储到dump.rdb文件中。

当第一次生成rdb镜像的时候,将快照保存到dump.rdb文件中,但非首次生成镜像时,又是怎样的流程呢?

当执行 生成rdb镜像的操作的时候,会将要生成快照的数据先保存到一个临时文件中,当这个快照生成完毕后,再将之前的rdb文件删除,将这个临时文件重命名为dump.rdb.

自始至终,rdb文件只有一个。

注意: 若执行save命令,是不存在快照的逻辑的,会直接向已经存在的dump.rdb文件中写数据.

观察快照替换过程:

bgsave命令执行速度太快了,无法观察到,但可以通过查看新旧文件替换的过程,感受替换,可以通过linux的stat 命令查看文件的innode编号,若是两个不同的文件,inode编号是不同的.

现在重启服务器:

可以看到,两次查看rdb文件的inode编号,是不同的,说明是不同的文件.

redis生成快照时机:

redis生成快照不仅是手动执行命令bgsave才触发,也会因为某些操作自动触发!

1.通过配置文件,自己设定触发条件

注意:当对配置文件修改后,并不会立即生效,需要重启服务器。

命令: service redis-server restart

打开配置文件,可以找到这样的设定,指定时间和修改次数,当时间达到并且修改次数也满足的条件下就会自动触发快照,当两个条件有一个不满足,就不会触发快照:

save " ":关闭自动生成快照。

save 900 1:指的是在900秒(15分钟)后,有一次数据修改,就会触发快照操作.别的命令同理.

配置原则:尽量减少执行的次数,不要让其执行的太频繁。因为生成一次rdb快照的成本比较高。

2.通过shutdown命令,关闭redis服务器,

执行(service redis-server restart)命令,这属于正常关闭,会触发自动快照.

现在redis是空的状态,查看当前状态下的dump.rdb文件:

现在插入3条数据,再次查看dump.rdb文件:

和之前没有变化,因为还未触发快照条件,现在重启redis服务器(需要先退出redis客户端:ctrl+d),

看到原来的数据还存在,就说明触发了快照,再看看dump.rdb文件就更加确定了:

dump.rdb中的内容和原来的内容不同了,由于是二进制文件,看不懂内容,但可以隐约的看到有k1,k2,k3的存在:

这就说明在重启redis服务器的时候,触发了快照.

3.redis进行主从复制,主节点会自动生成rdb快照,然后把rdb快照文件内容传输给从节点。

(这个后面再说).

当rdb文件坏了,会咋样呢?

当手动把rdb文件内容修改,重启服务器,就有可能启动失败,或启动成功,但可能得到的数据有问题。

注意:

1.重启的时候,不能通过service redis-server restart 命令重启,因为这属于正常退出,redis在正常退出的时候,会重新生成rdb快照,就会把修改过的文件给替换程成正常的文件了。

要通过 kill -9 进程ip  命令杀死进程,再重启.(查看进程ip命令:ps  aux | grep redis-server)

2.若修改的是文件的末尾,可能不会产生影响,若修改的是中间位置,就不一定了。

RDB存在的问题:

不能实时持久化保存数据,在两次生成快照之间,实时的数据可能会因重启而丢失。

当在两次“存档”之间,操作了大量的数据,但在第二次出发快照之前,由于异常情况,redis服务器异常退出,并未触发快照,那么这之间的数据就丢失了,再次重启服务器,就回到了上次“存档”的状态。(下面要谈的aop就可以解决这个问题)

AOF:

AOF:实时存储.会把用户的所有操作都存储的aof文件中.当重启redis服务器的时候,就会读取这个aof文件,把数据进行恢复.

aof默认是关闭状态,需要在配置文件中进行设置,将其打开.

当aof文件和rdb文件同时存在时,就会以aof文件为准,rdb文件就不生效了.即使把rdb文件给删了也没事.

开启aof文件:

进入redis.conf文件: 默认是no(关闭状态):

开启aof文件:

aop文件的位置和rdb文件位置是一样的 /var/lib/redis/,也是可配置的.

重新配置文件后,需要重启redis服务器才能生效.

查看aof文件位置:

打开aof文件:

aof文件保存的是用户执行的命令,是以文本的方式保存命令的,通过一些特殊符号作为分隔符.

aof的实时存储:

aof是实时存储的,即使异常退出服务器了,在退出之前的所有命令也已经被保存了,下面来执行看一下:

现在向redis中插入3条数据,然后通过kill -9 ip 命令让redis服务器异常退出,查看数据是否还存在:

杀死进程:

再次查看redis进程,会发现进程还存在,是因为在windos系统中,当发现进程异常终止时,会立即重启一个新的新的进程,当再次查看进程时,还存在,但ip已经变了,就是重新启动了一个新的进程.

可以看到,原来的数据都还存在,说明aof文件进行了实时存储.

查看aof文件,可以看到刚存储数据的操作:

redis的特点是效率高,较mysql相比,执行速度快.但是aof需要每执行一个命令就往硬盘中写一个命令,这是否会降低redis的执行效率呢?

其实,并不会.

redis的aof文件,往硬盘中写数据,并不是用户每进行一次操作就立即写的,而是先写入一个内存缓冲区,等积攒了一定的操作量后,再一起写入硬盘的.(每次写入到文件的末尾)这就会大大提高执行效率.

但是内存缓冲区还是在内存中的,万一掉电重启,内存缓冲区中的数据就不存在了,

是的,但"人有悲欢离合,月有阴晴圆缺",无法保证完美,这里redis给出了一些选项,让程序员根据实际情况来决定aof刷新缓冲区的频率.

appendfsync:

刷新频率越高,性能就越高,数据的可靠性就越高;反之,刷新频率越低,性能就越低,数据的可靠性就越低;

Redis 提供了多种 AOF 缓冲区同步⽂件策略,由参数 appendfsync 控制,
 

always:实时刷新,性能最高,可靠性最高;

evertsec:没隔一分钟刷新一次,性能较高,可靠性次之;

no:每次重启服务器的时候刷新一次,性能最低,可靠性也最低.

在配置文件中可以设置隔离级别: 默认的配置为everysec:

aof文件的刷新,是每次将内存缓冲区中的内容放在原文件的末尾的,

重写机制:

aof一直存储,体积会越来越大,是否会影响到redis的下次重启呢,这个是不会的,redis存在重写机制.

在操作过程中有很多冗余的操作存储.

像:

lpush k1 11lpush k1 22lpush k1 33

这三个操作,等价于:lpush k1 11 22 33

还有:

set k1 11set k1 22set k1 33

这三个操作,等价于: set  k1 33,

还有:

set k1 11 set k2 22 del k1 k2

等价于啥都没有操作.等等.

这些冗余的操作时没有必要记录的.只需要得到最终的一个结果就可以了.

因此,redis在每次重启的时候,能够针对aof文件进行整理,剔除掉一些冗余的操作,并合并一些操作,得到"瘦身"的效果,这就是重写机制.

重写流程:

aof的重写可以手动触发,也可以自动触发,

触发流程如下:


当执行bgrewriteaof命令的时候, 父类就会执行fork创建子进程,

父进程还是负责接收数据,子进程就负责重写操作: 创建一个新的aof文件,将数据最终操作结果写入到新的文件中.

父进程在创建子进程后,当有新的数据操作时,还是会将数据存储到aof文件中(防止意外的发生,突然掉电导致子进程的数据尚未备份完成,父进程也没有将新的数据保存起来),并且会将创建子进程后新的数据再存储到另一文件aof_rewrite_buf中.

当子进程重写完后,通知父进程重写完了;

然后,父进程就会将aof_rewrite_buf中的数据追加到新的aof文件中,这样就做到了实时存储的效果了.

执行完后,就会将新的aof文件替换旧的aof文件,就完成了重写过程.

当重启redis的时候,就会根据aof中的数据恢复原来的数据了.

此外, 在执行bgrewriteaof命令的时候, 当发现当前进程正在执行aof重写时,或刚完成重写,当前请求就不再执行,直接返回了.

若发现此时rdb文件正在备份,就会等待rdb文件执行快照完,再执行aof备份操作.

重写操作:

现在执行3条命令,查看aof文件: 

就会看到刚在执行的命令了,

查看此时aof文件的inode值:

当执行重写操作后,再次查看aof文件:

就会发现,重写后,只剩下重写前最终的值了,

查看inode:

两次查看的inode值不同,表示aof文件发生了替换,不再是原来的aof文件了.

混合持久化:

当重写后,再次查看aof文件时,会发现文件中的内容不是以文本格式存储,而是以二进制的形式存储,这又是怎么回事呢?

redis为了节省空间,aof采用混合持久化的机制存储数据,就是当重写的时候,会将重写前的数据以二进制的形式存储起来,当又有新的操作数据时,再以文本格式存储.

现在再执行两条命令:

查看aof文件内容:新执行的命令以文本格式存储,而重写前的命令就以二进制的形式存储了,这就是混合持久化.

这个机制也是可以通过配置文件进行设置的:

为yes时,就采用混合持久化机制,若不想采用这个机制,将其设为no,再重启服务器即可,这样,当重写后,aof文件中的数据就是都以文本格式存储了.