众所周知,Redis常常用来作为缓存、内存数据库、消息队列......这都由于Redis是将数据存储在内存上的,因此访问速度就会比MySQL这样的数据库快。
但数据储存在内存上就会有一个非常致命的缺点:掉电就没了。
试想一下,当我们将很多数据储存在Redis中,还没来得及使用,突然停电了,再打开主机启动服务之后,啥都没了,这得多难受。为了应对这种情况,Redis在背后就搞了一系列的机制来进行数据持久化,保证Redis服务器的高可用~
简介
Redis实现持久化的时候主要是按照两个策略来做的:RDB,AOF
RDB:Redis DataBase -> 定期备份
AOF:Append Only File -> 实时备份
当我们插入一个数据的时候,首先会在内存中存储一份,然后再在硬盘上存一份,虽然一份数据存了两份,但提高了可用性。当我们查询数据的时候,会先从内存中去查,当服务器进行重启的时候,则会从硬盘上将原有的数据读取到内存中~
RDB
RDB指的是对Redis内存中的数据定期的写入硬盘,进行备份保存,生成一个快照文件。具体触发保存的方式有两种:手动触发、自动触发.
手动触发
1)手动触发,程序员通过执行命令才触发保存
save:执行save的时候,redis服务器会全力去执行备份操作,当数据量多的时候,执行时间就会延长,就会阻塞其他客户端的操作,导致出现bug(与keys * 操作一样,也是个比较危险的操作)
bgsave:与save相对,不会影响其他客户端的操作,通过”多进程“的方式来实现备份.
父进程通过fork指令(写时拷贝),创建了一个长得一模一样的子进程(内存地址、PCB都相同,为了减小开销),当父进程中有变量被修改,子进程才会去重新创建,防止冲突。
执行流程如下:
首先Redis服务器收到了bgsave命令,会先去判断当前是否存在正在执行备份操作(RDB/AOF)的子进程,如果存在,则返回。如果不存在则继续。
父进程调用fork,创建子进程(写时拷贝的方式,不会太影响效率),然后父进程就可以继续去接受客户端的其他命令了。子进程将内存中的数据写入到新生成的RDB文件中,然后再将旧的RDB文件进行替换。
自动触发
2)自动触发,可以在配置文件中进行设置,每隔多长时间/每产生多少次修改进行一次触发
redis配置文件在linux中存放的路径:/etc/redis
我们不用刻意去记这个路径,可以用过指令来查找:
-> whereis redis
配置文件中默认的进行自动触发的配置如下:
解释:
save <seconds> <changes> 表示 每多少秒 且 这一秒修改了几次,就进行一次持久化操作.
save 900 1 表示 每900秒(15min) 且 进行了一次修改key的操作进行一次保存.
RDB文件
RDB是一个保存了压缩形式二进制的文件。当Redis服务器进行重启的时候,就会去加载这个文件,由于是二进制文件,加载的速度相较于AOF文件是更快的。
RDB文件存储位置:/var/lib/redis
文件内容:
由于是压缩形式的二进制文件,我们很难观察出里面的内容。
如果我们对这个文件进行修改呢?
1.如果是在已有的数据中进行修改,会在redis重启的时候,启动失败,提示文件错误
2.如果是在这个文件的末尾进行添加,此时redis可以启动。
综上,把错误的RDB文件去交给Redis,得到的结果是不可预期的。我们可以使用Redis提供的工具来检查一下这个二进制文件:
redis-check-rdb xxxx.rdb
如果rbd文件错误,就会显示如下信息:
RDB文件的优缺点:
1.RDB是一个压缩的二进制文件,数据加载的速度远快于AOF文件加载速度。
2.RDB文件做的是一个定期备份的事情,里面的数据表示的是某一时间点中Redis的数据,适合用于全量备份。
3.RDB的初心本就是定期备份,并且需要创建进程进行备份,无法做到实时性,可能存在数据丢失。
4.RDB是二进制文件,可能在某些Redis版本中RDB的文件格式会出现不一致,兼容性不能保证。
AOF
AOF是以独立日志的方式记录每次写命令,主要用于解决Redis数据持久化的实时性。
AOF默认是关闭状态,需要通过修改配置文件来开启。
cd /etc/redis
vim redis.conf
将no改为yes,就可以开启了。修改完了之后,要想生效,需要重启服务器。
service-redis-server restart
AOF的文件也是跟RDB在同一个地方的,即/var/lib/redis。
AOF是一个文本文件,会将每次操作进行记录。
AOF执行流程
Redis本身是一个单线程模型,如果对于每个命令都去访问一次IO设备,那么效率会大大下降。因此就在内存中搞了一个缓冲区,先将命令写入缓冲区,然后再将缓冲区的数据一下子写入到文件中。此处的rewrite操作是为了给文件“瘦身”(例如:一 增一删,相当于没有),当redis服务器重启的时候,就会去读AOF文件中的数据(当开启AOF的时候,Redis重启读数据就会以AOF为准).
AOF机制为了提高效率,会将数据先写到缓存中,如果此时断电了,缓冲区在内存中,未写入硬盘,此时也就没有了~ 虽然AOF是实时备份,但为了效率也不得不进行取舍。
不过Redis也在内部提供了一些数据同步策略。当然也在 /ect/redis/redis.conf 文件中
策略:
配置值 | 说明 |
no | 不主动进行同步,让OS来控制,最快最不可靠 |
always | 每次写入都进行同步,最慢最可靠 |
everysec | 每秒进行一次同步,中庸之道~ |
AOF重写机制
通过观察上述AOF文件中的内容,我们会发现,里面记录了每次指令的操作,如:select、set、del.....
但AOF是用来进行持久化数据,以便下次Redis服务器进行重启的时候恢复数据。
当出现如下指令的时候:
set k1 100 #add
get k1 #select
del k1 #delete
虽然AOF文件中记录了上述指令,但记录了个寂寞~当下次重启的时候啥也不会恢复,并且记录了这么多指令,会大大提高文件的大小。因此就需要用来重写机制,来将一些操作进行合并,只需关注最终结果即可~~
出发重写机制也有两种方式:手动触发、自动触发
手动触发
通过调用bgrewriteaof指令,进行重写。
AOF重写流程:
1.首先父进程收到bgrewriteaof命令,调用fork,创建子进程。
2.子进程根据当前内存中的key,写入到新的AOF文件。
3.父进程继续接受客户端的指令,会将指令写入到缓冲区和重写指令缓冲区
4.当子进程数据已经写完的时候,告诉父进程,然后父进程会将重写指令缓冲区的数据写入到新的AOF文件,最后将新的AOF文件替换旧的AOF文件。
在RDB中,对于fork以后得数据,就不会去管理了,在AOF中会先写入到缓冲区中~
父进程继续将数据写入到旧的AOF文件是否有意义?最后会被新的AOF文件替换。
如果遇到掉电的情况,子进程由于没有保存,新的AOF文件数据全都丢了,如果父进程不去写旧的AOF文件的话,重启的时候恢复的数据会有问题,无法保证数据完整性~
自动触发
通过设置auto-aof-rewrite-percentage 和 auto-aof-rewrite-min-size 这两个属性来进行配置。
auto-aof-rewrite-percentage:表示当前AOF占用大小相较于上次重写是增加的比例。
auto-aof-rewrite-min-size:表示触发重写时AOF的最小文件大小。
混合持久化
AOF本来是按照文本的方式记录数据的,但后续服务器加载文本文件成本比较高,redis就引入了“混合持久化”。
先按照AOF的方式,记录每一个操作,然后在重写的时候,将内存中的key用rdb文件-压缩二进制的方式进行记录,然后保存在AOF文件中。
因此我们有时候也会在AOF见到类似RDB文件中的数据。