聊聊Redis的持久化

redis:我的数据不仅可以放在内存中,照样可以持久化到硬盘中。所以我也是一种数据库。

我们都知道,redis就是靠快而出名,而它的快则是因为数据全部在内存中操作。

但是如果数据仅仅只放在内存中的话,还是有问题的,比如服务宕机、机器重启等都会造成内存数据丢失,因此,必须使用某种方法将redis数据持久化到硬盘中。

redis采用了两种持久化方式:「RDB和AOF」

RDB

「RDB是一种快照技术,快照是一次全量备份」,它是将内存数据全部以二进制形式保存下来,且内容非常紧凑。

我们都知道,redis的快还有一个原因是它是单线程(至于redis单线程为啥比多线程快,网上有很多解释,这里不再赘述),这个线程既负责所有客户端套接字的并发读写,也负责数据在内存中的逻辑读写。如果再加入RDB持久化,这个线程肯定是吃不消的,因为持久化是将数据写入到硬盘中,这就牵扯到IO操作,IO操作的耗时和内存操作的耗时根本不是一个量级的。因此这个单线程肯定不能用来负责RDB持久化。

那要怎样进行RDB持久化呢?再起一个线程来负责?那redis就不是单线程了。为了解决这个问题,redis采用多进程来实现持久化。

「redis在持久化的时候会fork出一个子进程」,后续的持久化操作都会交给这个子进程来处理,而父进程则继续处理客户端的请求。这样既保证了快速处理客户端请求,又能进行数据持久化。

AOF

「AOF是一种指令日志,里面记录着内存数据修改的所有指令」。每一次修改数据的指令都会增量的写入到AOF日志中,这就导致了此日志随着时间会变得特别庞大。

想象一下,如果AOF日志中记录了redis中所有的修改指令,那拿着这个指令在一个空的redis实例中顺序执行,就会重现原redis,同样起到持久化的作用。

但是,「AOF日志文件很大」,如果执行整个AOF日志,将会非常耗时,导致redis卡顿,这样肯定是不行的。这时候我们就需要对AOF进行“瘦身”。

AOF日志怎么瘦身呢?redis同样使用一个新的进程来处理,这个进程对内存数据进行遍历,然后转换成一系列redis的操作指令,序列化到一个新的AOF中,然后将AOF瘦身操作期间产生的增量AOF日志再写入到新AOF日志中,最后将新AOF日志替换原AOF日志,这样瘦身工作就完成了。

这种做法为啥能起到瘦身的作用呢?比如redis曾经有这样的操作:先增加了一条数据,然后又删除了这条数据。在原AOF日志中记录着两条指令,一条新增、一条删除。而转换成新的AOF日志中,对内存数据遍历时,没有发现这条数据,因此对应的是一条指令都没有。这样就起到了瘦身的作用。

两者优缺点

最终的选择

当我们redis挂了重启时,一般不会选择RDB来加载持久化数据,因为会有部分数据丢失。但是选择AOF日志的话,它会比RDB慢很多,启动redis实例会花费很长时间。为了解决这个问题,redis4.0提供了一个新的持久化选项--「混合持久化」,这种方式是将RDB持久化开始到结束这段时间内会丢失的数据交给AOF日志来记录,这样大部分数据都交给RDB来恢复,而小部分数据交给AOF日志,从而「保证了数据恢复速度,而且数据也基本不会丢失」,两全其美。


扫一扫,关注我

彻底搞懂这烦人的编码与乱码!

2020-09-10

Java面试系列-线程相关(一)

2020-09-03

Java到底是引用传递还是值传递

2020-08-07

数据是怎么一步一步到服务器的

2020-06-18

redis分布式锁

2020-06-05


本文分享自微信公众号 - pipi蛋(pipidan_fuyun)。
如有侵权,请联系 [email protected] 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章