1、为什么要做Redis的持久化
首先Redis的作用是将一些常用的数据保存到服务器的内存中,以此来减轻数据库的压力及提高数据查询的速度。这些保存在内存中的数据在服务器突然宕机或者重启的时候会全部丢失。这时候在redis重启之后需要重新再向内存中添加数据,如果数据量过大(几万条、几十万条),需要恢复的时间就特别的长,另外由于Redis的数据丢失,大量的数据查询请求会转移到数据库上,造成短时间内数据库访问量大量提升,访问量很大的时候,可能会造成数据库也挂掉,也就是所谓的缓存雪崩(缓存穿透、缓存击穿、缓存雪崩)。
面对这种情况,就需要用到Redis的持久化,通过持久化机制将在内存中的数据通过文件的方式保存磁盘上面。在出现事故,丢失了内存中的数据时,就可以通过这些持久化的文件来迅速地恢复数据到内存中。
2、持久化方式RDB、AOF介绍
RDB
RDB(Redis DataBase):对Redis中的数据执行周期性的持久化,可以在redis.conf设置设置持久化的执行周期。
配置命令:save 60 1000。每隔60s,如果有超过1000个key发生变更,那么就生成一个新的dump.rdb文件。
该文件的内容为redis在内存中数据的完整快照。可以设置多条save命令,每到一个检查点,就会去检查一下,如果满足条件就会生成一个新的rdb文件。
也可以手动调用save或者bgsave命令,同步或异步执行rdb快照生成。
执行过程:
- Redis父进程判断是否有正在执行的save、bgsave或者bgrewriteaof(aof文件重写命令)子进程。有正在执行的命令则返回。
- 上述命令都没有的情况下,父进程执行fork(调用OS函数复制主进程)操作创建子进程,这个复制过程中父进程是阻塞的,Redis不能执行来自客户端的任何命令。
- 父进程fork后,bgsave命令返回“Background saving started”信息并不再阻塞父进程,并可以响应其他命令。
- 子进程创建RDB文件,根据父进程内存快照生成临时快照文件,完成后对原文件进行原子替换(RDB始终完善),每次生成一个新的快照,都会覆盖之前的老快照。
- 子进程发送信号给父进程表示完成,父进程更新统计信息。
- 父进程fork子进程后,继续工作。
RDB优缺点:
- 优点:
- RDB非常适合做数据的冷备。RDB每隔一段时间会生成一次dump.rdb文件,可以通过脚本备份到服务器另外的地方或者远程的资源服务器上。
- RDB对Redis对外提供的读写服务影响非常小,因为Redis主进程只需要fork一个子进程,让子进程执行IO操作来维持Redis的可持久化。
- 相对于AOF来说,直接基于RDB数据文件来重启和恢复Redis进程,更加快速。
- 缺点:
- 因为RDB需要每隔一段时间才会做一次数据备份,所以用RDB的方式来做持久化会造成数据的丢失。
- 如果父进程本身占用的内存很大(内存中的数据量大),它调用fork的时候会导致客户端提供的服务暂停一段时间,暂停时间视数据量的大小定。
AOF
AOF(append only file):对Redis的所有操作命令进行记录,在redis.conf中可以设置fsnyc的频率。打开AOF持久化机制后,Redis每次接收到一条写命令,就会先写入服务器的缓存(os cache),再调用系统的fsync将缓存中的数据写入日志文件中。
配置命令:
appendonly yes #开启aof
appendfsync always #每次新增一条命令,就立即向日志文件中写入数据。这种方式性能比较差。QPS大幅下降,但能保证每一条操作都被记录下来。不推荐使用。
appendfsync everysec #每过一秒中向日志文件中写入数据,最常用的配置方式。推荐使用。
appendfsync no #Redis仅负责将数据写入os cache,不去调用系统的fsync,这个将数据写入日志文件的过程交给系统自身。这种方式不可控,不推荐使用。
rewrite:
Redis中能存储的数据是有限的,有些数据可能超过了过期时间自动过期,或者被用户自己删除,或者被Redis的缓存清除算法清理掉。所以Redis中的数据是在不断变化的,一部分常用的数据会被保存在Redis中。
但是很多在Redis中被删除的数据可能还保存在AOF文件中。另外由于AOF只有一个,而且每一个操作都会被记录,所以AOF文件会越来越大。这时候就需要调用rewrite操作了。rewrite主要是用来保证aof中的数据与Redis内存中的数据保持一致,保证AOF文件不会越来越大。在redis.conf中,可以配置rewrite策略。
rewrite配置命令:
auto-aof-rewrite-percentage 100 #数据量超过之前的100%
auto-aof-rewrite-min-size 64mb #数据量超过64mb
在AOF文件大小超过之前的100%时查看文件的大小,如果文件大小超过64mb则执行rewrite操作;如果没有超过64mb就不执行rewrite。
rewrite步骤:
- 满足重写条件后,Redis执行重写请求。
- 检查是否有正在进行的save、bgsave或者bgrewriteaof,有的话返回,没有的话父进程fork一个子进程。
- 父进程执行完fork操作,继续响应其他命令。子进程将新的修改命令写入到aof_buf缓冲区,并根据appendfsync策略将缓冲区中的数据写到磁盘文件中。这个时候新的修改命令同时向旧的AOF文件和新的AOF文件中写入。
- 父进程将重写缓冲区内的数据写入新的AOF文件中。
- 重写缓冲区中的数据全部写入AOF后,使用新的AOF文件替换旧的文件。
AOF优缺点:
- 优点:
- AOF由于可以更好的保证数据不丢失,一般是设置为每秒执行一次fsync操作,最多丢失一秒的数据。
- AOF日志文件是以append-only模式写入的,所以没有磁盘寻址的开销,写入性能比较高。
- AOF文件不易破损,就算破损了,使用redis-check-aof --fix命令可以直接修复破损文件。
- AOF执行rewrite操作时,不会影响Redis的读写。因为执行rewrite操作时,会同时向新老文件中同时写入数据,不会向RDB在数据量过大时,读写的短暂暂停。
- 缺点:
- 由于AOF记录了每一步更新操作,所以AOF文件通常要比RDB文件大。
- 开启AOF会降低QPS。
RDB和AOF到底该如何选择:
通常RDB和AOF是同时开启的。
- 如果能接收丢失几分钟的数据,可以只开启RDB。
- 开启AOF会降低QPS,如果可以接受并发量降低,可以只开启AOF
- 用AOF可以保证数据不丢失,用RDB可以作数据的冷备。同时开启RDB和AOF时,会优先使用AOF来恢复数据,因为AOF中的数据更全。