当前位置: 首页 > 科技观察

宕机导致Redis数据丢失怎么办?

时间:2023-03-15 22:22:33 科技观察

目录前言什么是AOF?三种回写策略日志文件过大怎么办?AOF改写会阻塞主线程吗?AOF缺点总结什么是RDB?应该对哪些数据进行快照?快照时可以修改数据吗?多久拍摄一次快照?增量快照AOF和RDB的混合使用总结总结前言Redis是一个内存数据库。虽然速度很快,但还是有着很大的隐患。一旦“serverdown”重启,内存中的数据还会存在吗?一种很容易想到的解决方案是从后台数据中恢复数据。如果数据量不大,这是一个可行的方案。但是,如果数据量太大,频繁的从后台数据库访问数据,压力会很大;另一方面,恢复数据的时间极其缓慢。对于Redis来说,实现数据的持久化和快速恢复是至关重要的。今天的文章将介绍Redis持久化的两种机制,AOF日志和RDB快照。什么是AOF日志?AOF(AppendOnlyFile)日志称为“after-writelog”,即先执行命令,将数据写入内存,再记录日志。AOF日志(文本形式)会将每条接收到并执行成功的命令以一定的格式(追加方式)写入文本中。“写后日志有什么好处?”如下:对于pre-writelog,不管命令是否执行成功都会记录,而Redis的post-writelog只有命令执行成功才会写入日志,避免错误的命令日志;同时,直到命令执行成功后才会写入日志,所以不会阻塞当前命令的执行。但是,AOF日志也存在“潜在风险”。分析如下:1、由于是post-writelog,如果在命令执行成功后,log写入磁盘前,服务器突然crash,重启恢复数据时,这部分数据必须不再存在于日志文件中,因此它将丢失。(无法通过后台数据库恢复)2.虽然不会阻塞当前命令的执行,但是由于日志记录也是在主线程中(Redis是单线程的),如果写日志的时候突然阻塞到磁盘,肯定会影响下一条命令的执行。为了解决以上风险,AOF日志提供了三种回写策略。三种回写策略AOF机制提供了三种回写策略,在appendfsync中配置,如下:Always(同步回写):命令执行后,立即将日志同步写入磁盘命令执行时,日志先写入AOF文件的内存缓冲区,缓冲区的内容每秒写入磁盘。否(由操作系统控制的回写):每次执行写命令后,首先将日志写入AOF文件的内存缓冲区,由操作系统决定何时将缓冲区的内容写回磁盘。事实上,这三种回写策略都不能解决主线程阻塞和数据丢失的问题。分析如下:同步回写:基本不会丢失数据,但是每次操作都会有慢速的写操作,不可避免的会影响Main线程的性能。Writebackeverysecond:每秒写一次AOF日志文件,但是一旦发生崩溃,一秒钟的数据还是会丢失。操作系统控制的writeback:buffer写完后,会写到磁盘,但是buffer期间一旦数据宕机,数据还是会丢失。以上三种策略的优缺点总结如下表:日志文件过大怎么办?随着数据量的增加,AOF日志文件必然会很大,这会导致写入和恢复数据都变得很慢。这时AOF提供了一种“重写机制”来解决这个问题。?重写机制非常简单易懂,就是Redis会新建一个AOF日志文件,通过一条命令将每个键值对的最终值写入到日志文件中。例如读取键值对key1:value1后,重写机制会在新的AOF日志文件中记录如下命令:setkey1value1其实是记录多次修改的最终值,并记录在新的AOF日志文件中,这样恢复数据时可以直接执行该命令。“为什么重写机制可以减小文件的大小?”当一个key值被多次修改时,AOF日志文件会记录多次修改key值的命令。重写机制生成“write”命令,使得旧文件中的“多个”命令在重写后成为新日志中的“一个”命令。作者画了一个重写流程图,仅供参考,如下:重写机制过程AOF重写会不会阻塞主线程?AOF重写虽然可以减小日志文件的大小,减少日志记录和数据恢复的时间,但是在数据量非常大的情况下,将整个数据库的重写日志写入磁盘是一个非常耗时的过程.不会阻塞主线程吗?“答案是:主线程不会被阻塞”;因为AOF改写过程是由后台子进程bgrewriteaof完成的,也是为了避免阻塞主线程,导致数据库性能下降。实际上,改写过程分为两个阶段:“一份,两份日志”。“一份”:表示每次重写时,主线程fork出一个子线程bgrewriteaof,主线程会复制一份内存数据给子线程。此时子线程中包含了数据库的最新数据。那么子线程就可以在不影响主线程的情况下进行AOF改写了。什么是“二本”?如下:第一条日志:子线程重写不阻塞主线程。这个时候主线程还是会处理请求,此时AOF日志还在记录,这样即使机器死机了,数据也是完整的。第一个日志是主线程正在使用的日志。第二条日志:指的是新的AOF重写日志;rewrite过程中的操作也会写入rewritelogbuffer,这样rewritelog就不会丢失最新的操作。所有复制数据的操作记录改写完成后,这些最新的改写日志记录的操作也会写入一个新的AOF文件,保证数据库最新的状态记录。此时,我们可以用新的AOF文件替换旧文件。?《小结》:Redis在进行AOF改写时,会fork一个子线程(不阻塞主线程)并做一份内存副本进行改写,然后使用两次日志来保证改写过程中新写入的数据不会迷路了。AOF的缺点虽然日志重写后,AOF日志文件会减少很多,但是在数据恢复的过程中,仍然是一个命令一个命令(由于是单线程,只能顺序执行)恢复数据.这个恢复过程非常缓慢。总结AOF是一种将操作命令一条一条记录下来的日志方式,它提供了三种回写策略来保证数据的可靠性,分别是Always、Everysec和No。这三种策略的可靠性从高到低,而在Performance上则是从从低到高。为了防止日志文件过大,Redis提供了重写机制。每次重写,fork一个子线程,复制内存数据进行重写,将多条命令缩减为一条命令,生成key-value对。最后,重写日志作为新日志。什么是RDB?RDB(RedisDataBase)是另一种持久化方式:内存快照。?RDB记录的是“某一时刻”的内存数据,不是操作命令。这种方法类似于拍照,只是保留某一时刻的影像。内存快照就是将某一时刻的状态以文件的形式写入磁盘。这样即使出现宕机,数据也不会丢失。此快照文件称为RDB文件。?因为记录了某个时刻的内存数据,所以数据恢复非常快,不需要像AOF日志一样,一条一条的执行记录的命令。应该对哪些数据进行快照?为了保证数据的可靠性,Redis执行的“全量快照”是将内存中的数据全部写入磁盘。随着数据量的增加,一次性将所有数据写入磁盘必然会造成线程阻塞,这与Redis的性能有关。为了解决线程阻塞的问题,Redis提供了两条命令,如下:save:在主线程中执行,会导致主线程阻塞。bgsave:fork一个子进程,专门用来写RDB文件,避免主线程阻塞。这是Redis的默认配置。这样可以使用bgsave命令进行全量快照,既可以保证数据的可靠性,又可以避免主线程的阻塞。快照时可以修改数据吗?当子线程正在执行完整快照时,主线程仍在接受请求。读取数据肯定没有问题,但是修改了数据,快照的完整性怎么保证呢?《举个栗子》:我在T时刻做全量快照,假设数据量为8G,写入磁盘的过程至少需要20S。在这20S的时间里,一旦内存中的数据被修改,快照的完整性就被破坏了。但是如果在快照的过程中数据不能被修改,将会对Redis的性能产生巨大的影响。Redis是如何解决这个问题的??Redis利用操作系统提供的Copy-On-Write(COW)技术,在执行快照的同时正常处理写操作。其实很简单。bgsave命令会fork出一个子线程,子线程共享所有内存,子线程会读取主线程内存中的数据,写入到RDB文件中。写时复制确保可以修改数据。如上图所示,键值对A的读取不会影响子线程,但是如果主线程一旦某个线程修改了内存中的一条数据(比如一个键值对D),这段数据会被复制,然后bgsave子线程会把它写入到RDB文件中。您多久拍摄一次快照?快照只是记录了某个时刻的数据,一旦长时间隔离,一旦服务器宕机,那段时间的数据就会丢失。比如在T1时间拍一张快照,在T1+t拍一张快照。如果服务器突然宕机,则快照中只保存时间t1的快照,t时间段的数据修改还没有被记录(丢失)。如下图所示:t时刻宕机,快照没有执行。从上图可以明显看出,“RDB并不是一个完美的日志解决方案。”只有逐渐减少t时间,才能减少丢失的数据,“那么问题来了,时间能不能缩短1秒?”也就是每秒做一次快照。?全量快照是记录某一时刻“所有”内存数据。每秒执行一次对Redis的性能影响巨大,于是“增量快照”应运而生。增量快照“增量快照是指全量快照后,后续的快照只记录修改过的数据”,这样可以避免每次全量快照的开销。增量快照的前提是Redis可以记住修改的数据。事实上,这个功能的开销是巨大的。需要保存完整的键值对,内存消耗较大。?Redis为了解决这个问题,采用了AOF和RDB混合使用的方式。AOF和RDB混合使用的概念是在Redis4.0中提出的。简单的说就是“内存快照按照一定的频率执行,比如每小时一次,在两次快照之间,用AOF日志记录这段时间所有的命令操作。”?混合使用的方式使得内存快照不必频繁执行,并且AOF记录的不是所有的操作命令,而是两个快照之间的操作命令,不会导致AOF日志文件过大,避免AOF重写的开销,这种方案不仅可以利用RDB快速恢复的好处,但也享有只记录操作命令的简单优势,强烈推荐使用。总结RDB内存快照记录的是某一时刻的内存数据,因此可以快速恢复;AOF和RDB的混合使用可以使宕机后数据恢复快,可以避免AOF日志文件过大总结本文介绍数据恢复和持久化方案有两种,分别是AOF和RDB,AO是做什么的F介绍?如下:1、AOF是post-writelog,通过记录操作命令来持久化数据。2、由于AOF是在命令执行后记录的Log,如果在写入磁盘之前服务器崩溃了,数据就会丢失;如果写入磁盘时突然阻塞,主线程就会阻塞;为了解决以上问题,AOF机制提供了三种回写策略,每种策略各有优缺点。3、AOF日志文件过大怎么办?AOF通过fork一个子线程重写一个新的日志文件(共享主线程的内存,记录最新数据的写入命令),同时子线程Rewrite避免阻塞主线程。RDB引入了什么?如下:RDB是内存快照,记录的是某个时刻的内存数据,而不是操作命令。Redis提供了save和bgsave两条命令来执行全量快照,这两条命令的区别在于save是在主线程上执行的,必然会阻塞主线程,而bgsave是fork一个子线程来共享内存。RDB利用操作系统的“copy-on-write技术”保证主线程在执行快照的同时可以修改快照。由于两次快照之间存在间隔,一旦服务器宕机,两次间隔之间时间点的数据就会丢失。Redis4.0开始使用AOF日志来记录两次快照之间执行的命令(AOF和RDB混用)。