Redis的持久化机制你学会了吗
大家都知道Redis经常被使用在缓存的场景中,那有没有想过这么一个问题,一旦服务器宕机,内存中的数据全部丢失,我们该如何进行恢复呢?如果直接从后端数据库恢复,不仅会给数据库带来巨大的压力,还会使上层应用响应变慢。所以redis的持久化机制是很重要的。接下来我们一起来探讨一下Redis的持久化机制。目前Redis持久化主要有两大机制,即AOF(Append Only File)日志和RDB快照。接下来我们就来分别学习一下。
AOF日志
AOF日志,即写后日志,它的含义是Redis先执行命令,把数据写入内存,然后再写入日志。Redis为什么要先执行命令后写入日志呢?首先我们来看一下AOF日志里记录了什么内容。AOF记录的是Redis收到的每一条命令,这些日志以文本的形式保存。假如我们执行了set hello world命令,AOF的内容如下:

其中“*3”代表当前命令有3部分,每部分是由”$+数字”开头,后面紧跟着具体命令、键和值。这里的数字代表后面的命令、键和值一共有多少个字节。例如 “$3 set”表示这部分有3个字节,也就是“set”命令。
Redis为了避免额外的检查开销,再往AOF里写入日志的时候,并不会对这些命令进行语法检查。所以如果先写日志再执行命令,日志中就可能会记录一些错误的命令,Redis使用日志恢复的时候就会出错。而写后日志这种方式,就是先去执行命令,如果命令执行出错,则不写入日志,只有执行成功的命令才会写入日志中。所以Redis使用写后日志这一方式的一大好处是,可以避免出现记录错误命令的情况。AOF还有一大好处,它是在命令执行后才记录日志,所以不会阻塞当前的写操作。
不过,AOF也有潜在的两个风险,首先如果刚执行完一个命令,还没来的及写日志就宕机了,那么这个命令和相应的数据就有丢失的风险。其次,AOF虽然避免了对当前命令的阻塞,但可能会给下一个操作带来阻塞风险。这是因为,AOF日志也是在主线程中执行的,如何在把日志文件写入磁盘很慢时,就会阻塞后续操作。针对这个问题,AOF给我们提供了三种写回策略,也就是AOF的配置项appendfsync的三个可选值。
- Always,同步写回:每个写命令执行完,立马同步地将日志写回磁盘;
- Everysec,每秒写回:每个写命令执行完,只是先把日志写到AOF文件的内存缓冲区,每隔一秒把缓冲区中的内容写入磁盘;
- No,操作系统控制的写回:每个写命令执行完,只是先把日志写到AOF文件的内存缓冲区,由操作系统决定何时将缓冲区内容写回磁盘。
这三种写回策略都无法做到两全其美,都有自己的优缺点,我们只能根据我们的业务场景,是需要高性能还是高可靠性来选择不同的写回策略。

最后,AOF还有一个问题,就是AOF以文件的形式记录在磁盘里。随着Redis接受的写命令越来越多,那么AOF日志文件也会越来越大,所以需要采取一定的手段来控制AOF日志文件的大小。这个时候,AOF重写机制就派上用场了。AOF重写机制是指在重写时,Redis会根据数据库的现状创建一个新的AOF文件,也就是说,读取数据库中的所有键值对,然后对每一个键值对用一条命令记录它的写入。为什么重写机制可以把日志文件变小呢?实际上,重写机制具有“多变一”功能。所谓的“多变一”,也就是说,旧日志文件中的多条命令,在重写后的新日志中变成了一条命令。例如我们对某个key进行了6次写入操作,那么旧的日志文件中就会有6条记录,而重写后的日志文件中就只有一条命令,所以AOF重写会减小文件的大小。那么AOF重写会阻塞主线程吗?毕竟把整个Redis的数据库的最新数据的操作日志都写回磁盘,仍然是一个非常耗时的过程。和AOF日志由主线程写回不同,重写过程是由后台子进程bgrewriteaof来完成的,这也是为了避免阻塞主线程,导致Redis的性能下降。每次执行重写时,主线程 fork 出后台的 bgrewriteaof 子进程。此时,fork 会把主线程的内存拷贝(采用操作系统的写时复制技术,不会真正的拷贝,写时复制技术下面会分析)一份给 bgrewriteaof 子进程,这里面就包含了数据库的最新数据。然后,bgrewriteaof 子进程就可以在不影响主线程的情况下,逐一把拷贝的数据写成操作,记入重写日志。因为主线程未阻塞,仍然可以处理新来的操作。为了避免数据丢失,在AOF重写过程中,新进入的写命令会写入到两份日志中。第一处日志就正在使用的 AOF 日志,Redis 会把这个操作写到它的缓冲区。这样一来,即使宕机了,这个 AOF 日志的操作仍然是齐全的,可以用于恢复。第二处日志,就是指新的 AOF 重写日志。这个操作也会被写到重写日志的缓冲区。这样,重写日志也不会丢失最新的操作。等到拷贝数据的所有操作记录重写完成后,重写日志记录的这些最新操作也会写入新的 AOF 文件,以保证数据库最新状态的记录。此时,我们就可以用新的 AOF 文件替代旧文件了。

RDB快照文件
由于AOF记录的是操作命令,而不是实际的数据。所以,用AOF方法进行故障恢复的时候,需要逐一把操作日志都执行一遍。如果操作日志很多,那Redis恢复的就很慢,影响到正常使用。那有没有即保证可靠性,还能在宕机时实现快速的恢复办法呢?那就是内存快照。对于Redis来说,它把某一时刻的状态以文件的形式写到磁盘上。这样一来,即使宕机,快照文件也不会丢失,数据的可靠性得到了保证。这个快照文件就叫RDB(Redis DataBase)文件。和AOF相比,RDB记录的是某一时刻的数据,并不是操作,所以,在做数据恢复时,直接把RDB文件加载到内存里,很快的完成恢复。
Redis提供了两个命令来生成RDB文件,分别是save和bgsave。
- save:在主线程中执行,会导致阻塞。
- bgsave:创建一个子进程,专门用于写入RDB文件,避免主线程的阻塞。这也是redis生成RDB文件的默认配置。
所以,我们可以采用bgsave来执行全量快照,既保证了可靠性,又避免了Redis的性能影响。接下了,我们来思考这么一个问题,就是Redis在做全量快照时,Redis中的数据可以被修改吗?Redis还支持写操作吗?为了快照而暂停写操作,Redis肯定是不能接受的。所以Redis借助了操作系统提供的写时复制技术(Copy-On-Write,COW)。简单来说,bgsave子进程是由主线程fork生成的,可以共享主线程的所有内存数据。bgsave运行之后,开始读取主线程中的内存数据,并把他们写入RDB文件。此时,如果主线程对这些数据进行读操作,则主线程和bgsave子进程相互不影响。但是,如果主线程执行写操作或者修改操作,也就是修改内存中的一块数据,那么这块数据会复制一份,生成副本。然后主线程在副本上进行修改。同时,bgsave子进程继续把原来的数据写入RDB文件。这样既保证了快照的完整性,也避免了对正常业务的影响。

接下来我们来看下一个问题,就是多久做一次快照,如果快照隔的时间太久,丢的数据就越多,间隔时间太短,丢失的数据越少,但是频繁的执行全量快照会给磁盘带来很大的压力。由于fork创建子进程bgsave这个过程是需要阻塞主线程的,主线程的内存越大,fork时间越长。所以频繁的fork出bgsave子进程,也就会频繁阻塞主线程。那有什么好的办法既能利用RDB的快速恢复,又能以较小的开销做到尽量少丢数据呢。Redis4.0提出了一个混合使用AOF日志和RDB的方法。简单来说,内存快照以一定的频率执行,两次快照之间使用AOF记录操作命令。
最后总结一下,关于AOF和RDB的选择问题,给大家提供3点建议。
- 数据不能丢失时,内存快照和 AOF 的混合使用是一个很好的选择。
- 如果允许分钟级别的数据丢失,可以只使用 RDB。
- 如果只用 AOF,优先使用 everysec 的配置选项,因为它在可靠性和性能之间取了一个平衡。
更多硬核知识,请关注公众号”老韩随笔"。

Redis的持久化机制你学会了吗的更多相关文章
- Redis数据持久化机制AOF原理分析一---转
http://blog.csdn.net/acceptedxukai/article/details/18136903 http://blog.csdn.net/acceptedxukai/artic ...
- 10分钟彻底理解Redis的持久化机制:RDB和AOF
作者:张君鸿 juejin.im/post/5d09a9ff51882577eb133aa9 什么是Redis持久化? Redis作为一个键值对内存数据库(NoSQL),数据都存储在内存当中,在处理客 ...
- Redis进阶:Redis的持久化机制
Redis进阶:Redis的持久化机制 Redis的持久化机制目前包括RBD和AOF两种方式. RDB持久化 RDB持久化方式是在指定的时间间隔对数据进行快照存储.过期的键值不会被存储到快照中.如果恢 ...
- Redis的持久化机制与内存管理机制
1.概述 Redis的持久化机制有两种:RDB 和 AOF ,这两种机制有什么区别?正式环境应该采用哪种机制? 我们的服务器内存资源是有限的,如果内存被Redis的缓存占满了怎么办?这就要看Redis ...
- Redis的持久化机制:RDB和AOF
什么是Redis持久化? Redis作为一个键值对内存数据库(NoSQL),数据都存储在内存当中,在处理客户端请求时,所有操作都在内存当中进行,如下所示: 这样做有什么问题呢? 其实,只要稍微有点计算 ...
- Redis学习-持久化机制
Redis持久化的意义 在于故障恢复 比如你部署了一个redis,作为cache缓存,当然也可以保存一些较为重要的数据 如果没有持久化的话,redis遇到灾难性故障的时候(断电.宕机),就会丢失所有的 ...
- Redis的持久化机制
持久化机制 RDB:快照模式AOF :日志模式 多数据库– 一个redis服务器内部默认有16个数据,编号О0-15– 默认操作是编号为0的数据库– 可以在命令行用select选择数据库127.0.0 ...
- Redis的持久化机制是什么?各自的优缺点?
Redis 提供两种持久化机制 RDB 和 AOF 机制: 1.RDBRedis DataBase)持久化方式:是指用数据集快照的方式半持久化模式) 记录 redis 数据库的所有键值对,在某个时间点 ...
- 深入理解Redis的持久化机制和原理
Redis是一种面向“key-value”类型数据的分布式NoSQL数据库系统,具有高性能.持久存储.适应高并发应用场景等优势.它虽然起步较晚,但发展却十分迅速. 近日,Redis的作者在博客中写到, ...
随机推荐
- MySQL 基础、安装、配置
1. MySQL 基础 1.1 什么是数据库? 1.2 数据库的类型 1.3 关系型数据库的优点 1.4 MySQL 简介 1.5 MySQL 数据类型 1.6 Mysql 存储引擎 1.7 MySQ ...
- 深度学习Anchor Boxes原理与实战技术
深度学习Anchor Boxes原理与实战技术 目标检测算法通常对输入图像中的大量区域进行采样,判断这些区域是否包含感兴趣的目标,并调整这些区域的边缘,以便更准确地预测目标的地面真实边界框.不同的模型 ...
- ng : 无法加载文件 C:\Users\szz\AppData\Roaming\npm\ng.ps1,因为在此系统上禁止运行脚本的解决方案
当安装好Angular CLI后想要查看该版本时在终端键入: ng version 后出现下图的错误提示 解决方案: 在win10 系统中有一个搜索框 输入 Windos PowerShell (一定 ...
- 四、SSL虚拟证书
沿用练习三,配置基于加密网站的虚拟主机,实现以下目标: 域名为www.c.com 该站点通过https访问 通过私钥.证书对该站点所有数据加密 4.2 方案 源码安装Nginx时必须使用--with- ...
- Telnet查看端口是否通
1. 查看端口是否通畅 telnet IP 端口号 如:telnet 10.150.159.71 5516 2.查看本机是否开启某个端口:netstat -an |findstr "端口 ...
- 撸了几天的sofa-tracer之后,我悟了!
什么是分布式链路跟踪 简而言之,在分布式系统下,用于跟踪链路而衍生出的一项技术. 应用场景如下: 应用A,B,C,D,E 以一个层级关系依赖, 当用户向 应用A 发起请求,但是返回了个异常,为了排查这 ...
- 合肥某小公司面试题:Spring基础
<对线面试官>系列目前已经连载25篇啦!有深度风趣的系列! [对线面试官]Java注解 [对线面试官]Java泛型 [对线面试官] Java NIO [对线面试官]Java反射 & ...
- .NET网页后台调用前台js方法时相同Key,调用不成功
ClientScript.RegisterStartupScript(GetType(), "key", "<script>Save()</script ...
- c++实现希尔密码
实验名称: 希尔密码的实现(c++版;本文只以26个大写英文字符作为加密后的密文的可选项) 实验原理: 引用知识: 记 Zm={0,1,2,...,m-1} 定义1:设A为定义在集合Zm 上的n阶方阵 ...
- Java基础篇(JVM)——字节码详解
这是Java基础篇(JVM)的第一篇文章,本来想先说说Java类加载机制的,后来想想,JVM的作用是加载编译器编译好的字节码,并解释成机器码,那么首先应该了解字节码,然后再谈加载字节码的类加载机制似乎 ...