前言
持久化其实在任何存储系统中,都是避不开的话题,比如数据库系统就有ACID进行数据、日志的持久化。将文件写入到内存、缓存、磁盘中。在比如消息队列Kafka也有消息的持久化机制,为防止数据的丢失也需要将数据持久化存储。目的其实就是为了当出现系统宕机的或者异常崩溃的时候,防止数据的丢失。而具体的实现机制可能各不相同。而缓存的本质就是为了提升数据的读取性能。
Redis持久化
Redis的持久化为两种模式,一种是实时数据的操作命令追加,也就是AOF,另一种就是对某一个时间进行数据的快照数据存储。
需要注意的是默认是不开启AOF,需要设置一下 appendonly yes ,保存的文件是appendonly.aof文件
AOF
Aof (Append Only File) ,含义就是追加文件。**而这里只是追加每个写操作,**在数据库中有写前日志(Write Ahead Log)也就是在将数据写入到数据库中时,先备份一个日志文件,但是Redis正好相反利用的是写后日志。
第一步:先执行命令写入内存中,第二步:将日志写入到磁盘中。
1.Client作为命令的来源,会有多个源头以及源源不断的请求命令。
2.在这些命令到达Redis Server 以后并不是直接写入AOF文件,会将其这些命令先放入AOF缓存中进行保存。这里的AOF缓冲区实际上是内存中的一片区域,存在的目的是当这些命令达到一定量以后再写入磁盘,避免频繁的磁盘IO操作。
3.AOF缓冲会根据AOF缓冲区同步文件的三种写回策略将命令写入磁盘上的AOF文件。
4.随着写入AOF内容的增加为避免文件膨胀,会根据规则进行命令的合并(又称AOF重写),从而起到AOF文件压缩的目的。
5.当Redis Server 服务器重启的时候会从AOF文件载入数据。
实现原理
为什么要这样操作呢,其实这就需要看下Redis执行命令中包含哪些数据了。比如一个简单的set testkey testvalue命令
*3 代表有三个部分,$3代笔的是set3个字节,$7代表的是7个字节(testkey)
那么在执行命令之前其实没有办法直到Redis执行命令是否正确,如果写前日志的话,那么很可能保存的执行命令就是错误的,导致在数据恢复的时候出现错误,所以写后日志可以先执行命令,然后在备份追加日志文件。另一个也可以有效避免执行命令的阻塞。
但是,AOF其实也存在一定的问题,那就是如果一个执行命令刚好执行完毕,然后没有备份在AOF文件中,服务宕机,数据没有办法进行恢复,以及如果操作命令比较多的时候,其实顺序的执行(在同一个线程中),执行命令和日志追加。那么就会对系统的性能造成阻塞。
回写策略
在AOF中有个配置可以选择,appendfsync。
- Always ,同步写回,操作完命令之后,立马将日志写到磁盘。
- Everysec,每秒写回,操作完命令后先将命令写入到内存缓冲区中,然后1S间隔期 ,将内存缓冲区的数据写入到磁盘中。
- NO,操作系统控制的写回,每个写命令操作完毕后,现将日志写到AOF文件的内存缓冲区中,然后操作系统决定何时写入到磁盘。
从上述可以看到,同步写回可以避免数据丢失,但是性能不好。每秒写回,虽然可以损失一定时间内的数据,但是性能居中。操作系统控制写入,性能最好,但是丢失数据的风险最大。所以这个时候就是trade-off。结合自己的业务场景来考虑。在高性能和高可靠性之间进行选择,如果要求高性能,并且运行数据丢失可以选择后两者,如果必须是高可靠性,那么就需要选择第一个。
重写机制
AOF在重写的时候针对的是写操作命令的记录日志,当我们读取key1 v1的时候,就会写入set key1 v1, 但是其实当我们对同一个key进行多次的操作后,其实是以最新的数据状态进行写入文件的。比如set key v2、set key v3,是按照v3版本进行写入。这样其实就可以避免写入多次数据,有效从写入端减少AOF文件的大小,在数据恢复的时候,也可以更加快速的执行。
比如图中,多次操作后是按照DCN数据进行重写的。AOF重写减少日志大小
虽然AOF重写可以减少日志文件的大小,但是当AOF文件足够大时,将整个数据库的数据写到磁盘中,其实也是一个非常耗时的过程,也就是会不会出现阻塞问题
AOF重写阻塞问题
AOF重写日志的时候,其实会fork出一个子线程执行重写任务。这样可以从根本上解决阻塞问题。但是具体是如何做?
1.先fork出一个bgrewriteaof子进程,然后将主线程的内存数据拷贝一份,写入到子进程的重写日志中
2.主线程可以处理新来的请求,然后写入到AOF缓冲区,以供数据备份,然后也会写入到新的AOF缓冲区,然后子进程会将新的数据写到AOF文件中,实现数据的备份。
小结
本篇主要介绍了Redis持久化机制中的一种,AOF,主要是通过追加日志的形式记录写操作命令,然后对应的流程就是先写入到Redis的时候,然后写入到内存缓冲区中,然后按照不同的策略进行写入磁盘,而日志是写后日志,不同于数据库的写前日志。以及对应的三个不同回写策略,为避免出现AOF文件过大,采用重写机制。但是重写机制虽然可以避免AOF文件过大,但是在读取AOF文件的过程时,仍然是一个很慢的过程。所以也就引入了另一种持久化机制,快照机制,RDB,下一篇文章,介绍一下RDB机制。