redis持久化机制

393 阅读6分钟

前言

由于redis是把数据存储在内存中,所以能快速读取数据,但也会产生一些新的问题。当redis所在的服务器宕机会导致redis数据库的数据会丢失。为了能够重用redis的数据,我们需要把内存中的数据存储到磁盘中,即持久化。redis提供了两种持久化的方法,一种是RDB快照,一种是只追加文件AOF

RDB


是什么

RDB 是指定时间间隔内将内存数据集快照写入磁盘,恢复时将快照文件直接读取到内存中。

实现方式

RDB有两种实现方式SAVE和BGSAVE.

  • SAVE是阻塞式的RDB持久化,当执行这个命令时redis的主进程把内存的数据快照写入到RDB文件中,直到该过程完成前redis不会执行任何其他命令
  • BGSAVE是非阻塞式RDB持久化,redis会创建一个子进程来把内存的数据快照写入到RDB文件中,同时主进程还能执行其他的命令。(注:子进程基本上是复制父进程的,相当于两个redis进程在系统上运行,这里会造成内存使用率大幅增加)

配置

# 时间策略
save 900 1
save 300 10
save 60 10000

# 文件名称
dbfilename dump.rdb

# 文件保存路径
dir /home/work/app/redis/data/

# 如果持久化出错,主进程是否停止写入
stop-writes-on-bgsave-error yes

# 是否压缩
rdbcompression yes

# 导入时是否检查
rdbchecksum yes

配置说明

  • save 900 1 表示900s内如果有1条是写入命令,就触发产生一次快照,可以理解为就进行一次备份
  • stop-writes-on-bgsave-error yes 这个配置也是非常重要的一项配置,这是当备份进程出错时,主进程就停止接受新的写入操作,是为了保护持久化的数据一致性问题。如果自己的业务有完善的监控系统,可以禁止此项配置, 否则请开启
  • 当然如果你想要禁用RDB配置,也是非常容易的,只需要在save的最后一行写上:save ""

存在问题

  • 最后一次持久化的数据可能会丢失。
  • 消耗内存过大(推荐使用AOF)

AOF


是什么

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

实现原理

AOF持久化分为三步,命令追加、文件写入和文件同步。

  1. 当redis开启AOF后,服务端每执行一次写操作(如set、sadd、rpush)就会把该条命令追加到一个单独的AOF缓存区末尾。
  2. 把AOF缓存区中的命令写到AOF文件(注:看上去第二步就已经完成AOF持久化了那第三步是干什么的呢?这就需要从系统的文件写入机制说起:一般我们现在所使用的操作系统,为了提高文件的写入效率,都会有一个写入策略,即当你往硬盘写入数据时,操作系统不是实时的将数据写入硬盘,而是先把数据暂时的保存在一个内存缓冲区里,等到这个内存缓冲区的空间被填满或者是超过了设定的时限后才会真正的把缓冲区内的数据写入硬盘中。)
  3. 当redis进行到第二步文件写入的时候,从用户的角度来看是已经把AOF缓存区的数据写入到AOF文件,但对于系统而言只不过是将AOF缓冲区的内容放到另外一个缓冲区而已,之后redis还需要进行文件同步把该内存缓冲区里的数据真正写入硬盘上(何时进行文件同步则是根据配置的appendfsync来进行)

配置

# 是否开启aof
appendonly yes

# 文件名称
appendfilename "appendonly.aof"

# 同步方式
appendfsync everysec

# aof重写期间是否同步
no-appendfsync-on-rewrite no

# 重写触发配置
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

# 加载aof时如果有错如何处理
aof-load-truncated yes

# 文件重写策略
aof-rewrite-incremental-fsync yes

配置说明:
appendfsync 三种模式:

  • always: 服务器会在每执行一个事件就把AOF缓冲区的内容强制性的写入硬盘上的AOF文件里,可以看成你每执行一个redis写入命令就往AOF文件里记录这条命令,这保证了数据持久化的完整性,但效率是最慢的,却也是最安全的
  • everysec: 服务端每执行一次写操作(如set、sadd、rpush)也会把该条命令追加到一个单独的AOF缓冲区的末尾,并将AOF缓冲区写入AOF文件,然后每隔一秒才会进行一次文件同步把内存缓冲区里的AOF缓存数据真正写入AOF文件里,这个模式兼顾了效率的同时也保证了数据的完整性,即使在服务器宕机也只会丢失一秒内对redis数据库做的修改
  • no: redis数据库里的数据就算丢失你也可以接受,它也会把每条写命令追加到AOF缓冲区的末尾,然后写入文件,但什么时候进行文件同步真正把数据写入AOF文件里则由系统自身决定,即当内存缓冲区的空间被填满或者是超过了设定的时限后系统自动同步。这种模式下效率是最快的,但对数据来说也是最不安全的,如果redis里的数据都是从后台数据库如mysql中取出来的,属于随时可以找回或者不重要的数据,那么可以考虑设置成这种模式

存在问题

  • AOF文件过大,对redis数据库的每一次写操作都会让AOF文件里增加一条数据,久而久之这个文件会形成一个庞然大物 解决方案:AOF重写的机制(Redis持久化之----AOF重写机制

参考文章