宕机了,Redis数据丢了怎么办?
持续原创输出,点击上方蓝字关注我

目录
前言 什么是AOF? 三种写回策略 日志文件太大怎么办? AOF重写会阻塞主线程吗? AOF的缺点 总结
什么是RDB? 给哪些数据做快照? 快照时能够修改数据吗? 多久做一次快照? 增量快照 AOF和RDB混合使用 总结
总结
前言
Redis
作为内存型的数据库,虽然很快,依然有着很大的隐患,一旦「服务器宕机」重启,内存中数据还会存在吗?
很容易想到的一个方案是从后台数据恢复这些数据,如果数据量很小,这倒是一个可行的方案。但是如果数据量过大,频繁的从后台数据库访问数据,压力很大;另外一方面恢复数据的时间极慢。
对于Redis
来说,实现数据的持久化和快速恢复是至关重要。
今天这篇文章就来介绍一下Redis
持久化的两种机制AOF
日志、RDB
快照。
什么是 AOF 日志?
AOF
(Append Only File
)日志称之为「写后日志」,即是命令先执行完成,把数据写入内存,然后才会记录日志。
AOF
日志(文本形式)会将收到每一条的命令且执行成功的命令以一定的格式写入到文本中(追加的方式)。
「写后日志有什么好处呢?」 如下:
对于写前日志无论命令是否执行成功都会被记录,但是 Redis
的写后日志则只有命令执行成功才会被写入日志,避免了日志中存在错误命令;同时由于是命令执行成功之后才会写入日志,因此不会阻塞当前命令的执行。
但是AOF
日志也有「潜在的风险」,分析如下:
由于是写后日志,如果在命令执行成功之后,在日志未写入磁盘之前服务器突然宕机,那重启恢复数据的时候,这部分的数据肯定在日志文件中不存在了,那么将会丢失。(无法通过后台数据库恢复的情况下) 虽然不会阻塞当前命令的执行,由于记录日志也是在主线程中( Redis
是单线程),如果日志写入磁盘的时候突然阻塞了,肯定会影响下一个命令的执行。
为了解决上面的风险,AOF
日志提供了三种回写策略。
三种写回策略
AOF
机制提供了三种回写策略,这些都在appendfsync
配置,如下:
Always
(同步写回):命令执行完成,立马同步的将日志写入磁盘Everysec
(每秒写回):命令执行完成后,先将日志写入 AOF 文件的内存缓冲区,每隔一秒把缓冲区中内容写入磁盘。No
(操作系统控制的写回):每个写命令执行完,只是先把日志写到AOF
文件的内存缓冲区,由操作系统决定何时将缓冲区内容写回磁盘。
其实这三中写回策略都无法解决主线程的阻塞和数据丢失的问题,分析如下:
同步写回
:基本不丢失数据,但是每步操作都会有一个慢速的落盘操作,不可避免的影响主线程性能。每秒写回
:采用一秒写一次到 AOF 日志文件中,但是一旦宕机还是会丢失一秒的数据。操作系统控制的写回
:在写完缓冲区之后则会写入磁盘,但是数据始终在缓冲区的时间内一旦宕机,数据还是会丢失。
以上三种策略优缺点总结如下表:
策略 | 优点 | 缺点 |
---|---|---|
Always | 可靠性高,数据基本不丢失 | 每个写命令都要落盘,性能影响较大 |
Everysec | 性能适中 | 宕机时丢失一秒数据 |
No | 性能好 | 宕机时丢失数据较多 |
日志文件太大怎么办?
随着数据量的增大,AOF日志文件难免会很大,这样将会导致写入和恢复数据都将变得非常慢。此时AOF提供了一种「重写机制」解决这一问题。
❝
重写机制理解起来很简单,即是
Redis
会创建一个新的AOF
日志文件,将每个键值对最终的值用一条命令写入日志文件中。❞
比如读取了键值对key1:value1
,重写机制会在新的AOF日志文件中记录如下一条命令:
set key1 value1
其实即是记录多次修改的最终的值记录在新的AOF日志文件中,这样当恢复数据时可直接执行该命令。
「为什么重写机制能够缩小文件呢?」 当一个键值被多次修改后,AOF
日志文件中将会记录多次修改键值的命令,重写机制是根据这个键值最新状态为它生成「写入」命令,这样旧文件中的「多条」命令在重写后的新日志中变成了「一条」命令。
作者画了一张重写流程图,仅供参考,如下:

AOF重写会阻塞主线程吗?
AOF重写虽然能够缩减日志文件的大小,达到减少日志记录和数据恢复的时间,但是在数据量非常的大情况下把整个数据库重写后的日志写入磁盘是一个非常耗时的过程,难道不会阻塞主线程吗?
「答案是:不会阻塞主线程」; 因为AOF重写过程是由后台子进程bgrewriteaof
来完成的,这也是为了避免阻塞主线程,导致数据库性能下降。
其实重写的过程分为两个阶段:「一个拷贝,两处日志」。
「一个拷贝」:指每次执行重写时,主线程都fork
一个子线程bgrewriteaof
,主线程会把内存数据拷贝一份到子线程,此时子线程中包含了数据库的最新数据。然后子线程就能在不影响主线程的情况下进行AOF重写了。
「两处日志」是什么?如下:
第一处日志
:子线程重写并未阻塞主线程,此时主线程仍然会处理请求,此时的AOF日志仍然正在记录着,这样即使宕机了,数据也是齐全的。第一处日志即是值主线程正在使用的日志。第二处日志
:指新的AOF重写日志;重写过程中的操作也会被写到重写日志缓冲区,这样重写日志也不会丢失最新的操作。等到拷贝数据的所有操作记录重写完成后,重写日志记录的这些最新操作也会写入新的 AOF 文件,以保证数据库最新状态的记录。此时,我们就可以用新的 AOF 文件替代旧文件了。
❝
「总结」:
Redis
在进行AOF
重写时,会fork
一个子线程(不会阻塞主线程)并进行内存拷贝用于重写,然后使用两个日志保证重写过程中,新写入的数据不会丢失。❞
AOF的缺点
虽说进行了日志重写后,AOF日志文件会缩减很多,但是在数据恢复过程中仍然是一条命令一条命令(由于单线程,只能顺序执行)的执行恢复数据,这个恢复的过程非常缓慢。
总结
AOF这种通过逐一记录操作命令的日志方式,提供了三种写回策略保证数据的可靠性,分别是Always
、Everysec
和No
,这三种策略在可靠性上是从高到低,而在性能上则是从低到高。
为了避免日志文件过大,Redis提供了重写的机制,每次重写都fork一个子线程,拷贝内存数据进行重写,将多条命令缩减成一条生成键值对的命令,最终重写的日志作为新的日志。
什么是RDB?
RDB
(Redis DataBase)是另外一种持久化方式:内存快照。
❝
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
时又做了一次快照,如果在t
这个时间段内服务器突然宕机了,则快照中只保存了T1
时刻的快照,在t
时间段内的数据修改未被记录(丢失)。如下图:

从上图明显可以看出,「RDB
并不是一个完美的日志记录方案」,只有让t
时间逐渐缩小,才能保证丢失的数据缩小。
「那么问题来了,时间能够缩短1秒
吗?」 即是每秒执行一次快照。
❝
全量快照是记录某一个时刻的「全部」内存数据,每秒执行一次的对Redis性能影响巨大,于是「增量快照」就出来了。
❞
增量快照
「增量快照是指做了一次全量快照之后,后续的快照只对修改的数据进行快照记录」,这样可以避免每次都全量快照的开销。
增量快照的前提是Redis能够记住修改的数据,这个功能其实开销也是巨大的,需要保存完整的键值对,这对内存的消耗是巨大的。
❝
为了解决这个问题,Redis使用了
AOF
和RDB
混合使用的方式。❞
AOF和RDB混合使用
这个概念是在Redis4.0
提出的,简单的说就是「内存快照以一定的频率执行,比如1小时一次,在两次快照之间,使用AOF日志记录这期间的所有命令操作。」
❝
混合使用的方式使得内存快照不必频繁的执行,并且AOF记录的也不是全部的操作命令,而是两次快照之间的操作命令,不会出现AOF日志文件过大的情况了,避免了AOF重写的开销了。
❞
这个方案既能够用到的RDB的快速恢复的好处,又能享受都只记录操作命令的简单优势,强烈建议使用。
总结
RDB
内存快照记录的是某一个时刻的内存数据,因此能够快速恢复;AOF
和RDB
混合使用能够使得宕机后数据快速恢复,又能够避免AOF
日志文件过大。
总结
本文介绍了两种数据恢复和持久化的方案,分别是AOF
和RDB
。
AOF
介绍了什么?如下:
AOF
是写后日志,通过记录操作命令持久化数据。由于 AOF
是在命令执行之后记录日志,如果在写入磁盘之前服务器宕机,则会丢失数据;如果写入磁盘的时候突然阻塞,则会阻塞主线程;为了解决以上问题,AOF机制提供了三种写回的策略,每种策略都有不同的优缺点。AOF
日志文件过大怎么办?AOF
通过fork
一个子线程重写一个新的日志文件(共享主线程的内存,记录最新数据的写入命令),同时子线程重写,避免阻塞主线程。
RDB
介绍了什么?如下:
RDB
是内存快照,记录某一个时刻的内存数据,而不是操作命令。Redis
提供了两个命令,分别是save
、bgsave
来执行全量快照,这两个命令的区别则是save
是在主线程执行,势必会阻塞主线程,bgsave
是在fork
一个子线程,共享内存。RDB通过操作系统的「写时复制技术」,能够保证在执行快照的同时主线程能够修改快照。 由于两次快照之间是存在间隔的,一旦服务器宕机,则会丢失两次间隔时刻的数据, Redis4.0
开始使用AOF
日志记录两次快照之间执行的命令(AOF
和RDB
混合使用)。

宕机了,Redis数据丢了怎么办?的更多相关文章
- 修复ogg source端意外宕机造成的数据不同步
修复ogg source端意外宕机造成的数据不同步 分类: Oracle2016-04-28 11:50:40原文地址:修复ogg source端意外宕机造成的数据不同步 作者:十字螺丝钉 ogg s ...
- Redis宕机的问题
在主从模式下宕机要分为区分来看: slave从redis宕机 在Redis中从库重新启动后会自动加入到主从架构中,自动完成同步数据: 如果从数据库实现了持久化,只要重新假如到主从架构中会实现增 ...
- Redis 日志篇:无畏宕机快速恢复的杀手锏
特立独行是对的,融入圈子也是对的,重点是要想清楚自己向往怎样的生活,为此愿意付出怎样的代价. 我们通常将 Redis 作为缓存使用,提高读取响应性能,一旦 Redis 宕机,内存中的数据全部丢失,假如 ...
- Redis数据持久化(RDB、AOF)
1. 简介 Redis作为内存型数据库,数据都保存在内存中,如果重启或意外宕机后,数据会全部丢失.因此,Redis提供了完善的持久化机制,将内存中的数据持久化到磁盘上,避免了完整性和安全性的问题, ...
- clickhouse高可用-节点宕机数据一致性方案-热扩容
1. 集群节点及服务分配 说明: 1.1. 在每个节点上启动两个clickhouse服务(后面会详细介绍如何操作这一步),一个数据分片,一个数据备份,为了确保宕机数据一致性,数据分片和数据备份不能同一 ...
- 由Redis的hGetAll函数所引发的一次服务宕机事件
昨晚通宵生产压测,终于算是将生产服务宕机的原因定位到了,心累.这篇博客,算作一个复盘和记录吧... 先来看看Redis的缓存淘汰算法思维导图: 说明:当实际占用的内存超过Redis配置的maxmemo ...
- Redis的KEYS命令引起宕机事件
摘要: 使用 Redis 的开发者必看,吸取教训啊! 原文:Redis 的 KEYS 命令引起 RDS 数据库雪崩,RDS 发生两次宕机,造成几百万的资金损失 作者:陈浩翔 Fundebug经授权转载 ...
- redis集群节点宕机
redis集群是有很多个redis一起工作,那么就需要这个集群不是那么容易挂掉,所以呢,理论上就应该给集群中的每个节点至少一个备用的redis服务.这个备用的redis称为从节点(slave). 1. ...
- redis宕机如何解决?如果是项目上线的宕机呢?
我们先来了解一下 bridge网络模式 他会创建一个docker0桥,看完这个我们就会知道redis哨兵机制的端口了. 之后继续研究redis宕机的解决办法! 宕机: 服务器停止服务 如果只有一台r ...
随机推荐
- Helium文档5-WebUI自动化-press模拟键盘按键输入技巧
前言 press方法是用来模拟键盘按键输入,可以组合使用,来模拟键盘输入,解决一些难定位的元素 入参介绍 以下是press源码中的函数介绍 def press(key): :入参 :param ke ...
- C# 面试前的准备_基础知识点的回顾_02
1.数据库的范式 这算入门问题了吧,但凡是个数据库类的,都得问吧, 但我们在回答的时候开始背书啦 第一范式(1NF)无重复的列 第二范式(2NF)属性完全依赖于主键 [ 消除部分子函数依赖 ] 第三范 ...
- docker容器学习资料
现在说起docker容器,你应该不会太陌生了吧?如果你是真的不懂或者是太久没有用到已经忘记的差不多了,那么你需要这一波的干货了,这波的干货刚刚好可以满足你的需要! 话不多说,直接上干货
- 用 Span 对 C# 进程中三大内存区域进行统一访问 ,太厉害了!
一:背景 1. 讲故事 前段时间写了几篇 C# 漫文,评论留言中有很多朋友多次提到 Span,周末抽空看了下,确实是一个非常
- redis client原理分析
代码库地址:https://github.com/garyburd/redigo 1:连接池 2:发送命令 3:解析结果 1:连接池 连接池结构体如下: type Pool struct { // D ...
- python打印水仙花数的个人总结
面试过程中,提到python,面试最多的就是让你现场写代码实现水仙花.冒泡.九九乘法表,这些面试方法旨在校验面试者的python基础和思维逻辑. 先从水仙花说起,水仙花是指一个n位正整数(n>= ...
- Spark性能调优的方法
原则一:避免创建重复的RDD 通常来说,我们在开发一个Spark作业时,首先是基于某个数据源(比如Hive表或HDFS文件)创建一个初始的RDD:接着对这个RDD执行某个算子操作,然后得到下一个RDD ...
- [Luogu P2341] [HAOI2006]受欢迎的牛 (缩点+bitset)
题面 传送门:https://www.luogu.org/problemnew/show/P2341 Solution 前排提示,本蒟蒻做法既奇葩又麻烦 我们先可以把题目转换一下. 可以把一头牛喜欢另 ...
- 2018-12-8 论文翻译+hdoj+git+python
今天干的事不多,明天得把实验写了. 论文翻译了摘要.0.5h hdoj 五道水题.注意while(cin>>char&&char != '\n')没用.可用ch = cin ...
- js 图片放大镜功能
原理:放置两张相同的图片,一张作为主图片(图片1),另一张作为用来裁剪并放大的图片(图片2) 鼠标移动时,计算鼠标在图片1的位置(距离图片1左上角的x,y距离),以此决定在图片2开始 ...