一文带你深入了解 Redis 的持久化方式及其原理
Redis 提供了两种持久化方式,一种是基于快照形式的 RDB,另一种是基于日志形式的 AOF,每种方式都有自己的优缺点,本文将介绍 Redis 这两种持久化方式,希望阅读本文后你对 Redis 的这两种方式有更加全面、清晰的认识。
RDB 快照方式持久化
先从 RDB 快照方式聊起,RDB 是 Redis 默认开启的持久化方式,并不需要我们单独开启,先来看看跟 RDB 相关的配置信息:
################################ SNAPSHOTTING ################################
#
# Save the DB on disk:
#
# save <seconds> <changes>
#
# Will save the DB if both the given number of seconds and the given
# number of write operations against the DB occurred.
#
# In the example below the behaviour will be to save:
# after 900 sec (15 min) if at least 1 key changed
# after 300 sec (5 min) if at least 10 keys changed
# after 60 sec if at least 10000 keys changed
# save ""
# 自动生成快照的触发机制 中间的是时间,单位秒,后面的是变更数据 60 秒变更 10000 条数据则自动生成快照
save 900 1
save 300 10
save 60 10000
# 生成快照失败时,主线程是否停止写入
stop-writes-on-bgsave-error yes
# 是否采用压缩算法存储
rdbcompression yes
# 数据恢复时是否检测 RDB文件有效性
rdbchecksum yes
# The filename where to dump the DB
# RDB 快照生成的文件名称
dbfilename dump.rdb
# 快照生成的路径 AOF 也是存放在这个路径下面
dir .
关于 RDB 相关配置信息不多,需要我们调整的就更少了,我们只需要根据自己的业务量修改生成快照的机制和文件存放路径即可。
RDB 有两种持久化方式:手动触发 和 自动触发,手动触发使用以下两个命令:
save:会阻塞当前 Redis 服务器响应其他命令,直到 RDB 快照生成完成为止,对于内存 比较大的实例会造成长时间阻塞,所以线上环境不建议使用
bgsave:Redis 主进程会 fork 一个子进程,RDB 快照生成有子进程来负责,完成之后,子进程自动结束,bgsave 只会在 fork 子进程的时候短暂的阻塞,这个过程是非常短的,所以推荐使用该命令来手动触发
除了执行命令手动触发之外,Redis 内部还存在自动触发 RDB 的持久化机制,在以下几种情况下 Redis 会自动触发 RDB 持久化:
在配置中配置了 save 相关配置信息,如我们上面配置文件中的
save 60 10000,也可以把它归类为“save m n”格式的配置,表示 m 秒内数据集存在 n 次修改时,会自动触发 bgsave。在主从情况下,如果从节点执行全量复制操作,主节点自动执行 bgsave 生成 RDB 文件并发送给从节点
执行 debug reload 命令重新加载 Redis 时,也会自动触发 save 操作
默认情况下执行 shutdown 命令时,如果没有开启 AOF 持久化功能则自动执行 bgsave
上面就是 RDB 持久化的方式,可以看出 save 命令使用的比较少,大多数情况下使用的都是 bgsave 命令,所以这个 bgsave 命令还是有一些东西,那接下来我们就一起看看 bgsave 背后的原理,先从流程图开始入手:
bgsave 命令大概有以下几个步骤:
- 1、执行 bgsave 命令,Redis 主进程判断当前是否存在正在执行的 RDB/AOF 子进程,如果存在, bgsave 命令直接返回不在往下执行。
- 2、父进程执行 fork 操作创建子进程,fork 操作过程中父进程会阻塞,fork 完成后父进程将不在阻塞可以接受其他命令。
- 3、子进程创建新的 RDB 文件,基于父进程当前内存数据生成临时快照文件,完成后用新的 RDB 文件替换原有的 RDB 文件,并且给父进程发送 RDB 快照生成完毕通知
上面就是 bgsave 命令背后的一些内容,RDB 的内容就差不多了,我们一起来总结 RDB 持久化的优缺点,RDB 方式的优点:
- RDB 快照是某一时刻 Redis 节点内存数据,非常适合做备份,上传到远程服务器或者文件系统中,用于容灾备份
- 数据恢复时 RDB 要远远快于 AOF
有优点同样存在缺点,RDB 的缺点有:
- RDB 持久化方式数据没办法做到实时持久化/秒级持久化。我们已经知道了 bgsave 命令每次运行都要执行 fork 操作创建子进程,属于重量级操作,频繁执行成本过高。
- RDB 文件使用特定二进制格式保存,Redis 版本演进过程中有多个格式 的 RDB 版本,存在老版本 Redis 服务无法兼容新版 RDB 格式的问题
如果我们对数据要求比较高,每一秒的数据都不能丢,RDB 持久化方式肯定是不能够满足要求的,那 Redis 有没有办法满足呢,答案是有的,那就是接下来的 AOF 持久化方式
AOF 持久化方式
Redis 默认并没有开启 AOF 持久化方式,需要我们自行开启,在 redis.conf 配置文件中将 appendonly no 调整为 appendonly yes,这样就开启了 AOF 持久化,与 RDB 不同的是 AOF 是以记录操作命令的形式来持久化数据的,我们可以查看以下 AOF 的持久化文件 appendonly.aof
*2
$6
SELECT
$1
0
*3
$3
set
$6
mykey1
$6
你好
*3
$3
set
$4
key2
$5
hello
*1
$8
大概就是长这样的,具体的你可以查看你 Redis 服务器上的 appendonly.aof 配置文件,这也意味着我们可以在 appendonly.aof 文件中国修改值,等 Redis 重启时将会加载修改之后的值。看似一些简单的操作命令,其实从命令到 appendonly.aof 这个过程中非常有学问的,下面时 AOF 持久化流程图:
在 AOF 持久化过程中有两个非常重要的操作:一个是将操作命令追加到 AOF_BUF 缓存区,另一个是 AOF_buf 缓存区数据同步到 AOF 文件,接下来我们详细聊一聊这两个操作:
1、为什么要将命令写入到 aof_buf 缓存区而不是直接写入到 aof 文件?
我们知道 Redis 是单线程响应,如果每次写入 AOF 命令都直接追加到磁盘上的 AOF 文件中,这样频繁的 IO 开销,Redis 的性能就完成取决于你的机器硬件了,为了提升 Redis 的响应效率就添加了一层 aof_buf 缓存层, 利用的是操作系统的 cache 技术,这样就提升了 Redis 的性能,虽然这样性能是解决了,但是同时也引入了一个问题,aof_buf 缓存区数据如何同步到 AOF 文件呢?由谁同步呢?这就是我们接下来要聊的一个操作:fsync 操作
2、aof_buf 缓存区数据如何同步到 aof 文件中?
aof_buf 缓存区数据写入到 aof 文件是有 linux 系统去完成的,由于 Linux 系统调度机制周期比较长,如果系统故障宕机了,意味着一个周期内的数据将全部丢失,这不是我们想要的,所以 Linux 提供了一个 fsync 命令,fsync 是针对单个文件操作(比如这里的 AOF 文件),做强制硬盘同步,fsync 将阻塞直到写入硬盘完成后返回,保证了数据持久化,正是由于有这个命令,所以 redis 提供了配置项让我们自行决定何时进行磁盘同步,redis 在 redis.conf 中提供了appendfsync 配置项,有如下三个选项:
# appendfsync always
appendfsync everysec
# appendfsync no
- always:每次有写入命令都进行缓存区与磁盘数据同步,这样保证不会有数据丢失,但是这样会导致 redis 的吞吐量大大下降,下降到每秒只能支持几百的 TPS ,这违背了 redis 的设计,所以不推荐使用这种方式
- everysec:这是 redis 默认的同步机制,虽然每秒同步一次数据,看上去时间也很快的,但是它对 redis 的吞吐量没有任何影响,每秒同步一次的话意味着最坏的情况下我们只会丢失 1 秒的数据, 推荐使用这种同步机制,兼顾性能和数据安全
- no:不做任何处理,缓存区与 aof 文件同步交给系统去调度,操作系统同步调度的周期不固定,最长会有 30 秒的间隔,这样出故障了就会丢失比较多的数据。
这就是三种磁盘同步策略,但是你有没有注意到一个问题,AOF 文件都是追加的,随着服务器的运行 AOF 文件会越来越大,体积过大的 AOF 文件对 redis 服务器甚至是主机都会有影响,而且在 Redis 重启时加载过大的 AOF 文件需要过多的时间,这些都是不友好的,那 Redis 是如何解决这个问题的呢?Redis 引入了重写机制来解决 AOF 文件过大的问题。
3、Redis 是如何进行 AOF 文件重写的?
Redis AOF 文件重写是把 Redis 进程内的数据转化为写命令同步到新 AOF 文件的过程,重写之后的 AOF 文件会比旧的 AOF 文件占更小的体积,这是由以下几个原因导致的:
- 进程内已经超时的数据不再写入文件
- 旧的 AOF 文件含有无效命令,如 del key1、hdel key2、srem keys、set a111、set a222等。重写使用进程内数据直接生成,这样新的AOF文件只保 留最终数据的写入命令
- 多条写命令可以合并为一个,如:lpush list a、lpush list b、lpush list c可以转化为:lpush list a b c。为了防止单条命令过大造成客户端缓冲区溢 出,对于 list、set、hash、zset 等类型操作,以 64 个元素为界拆分为多条。
重写之后的 AOF 文件体积更小了,不但能够节约磁盘空间,更重要的是在 Redis 数据恢复时,更小体积的 AOF 文件加载时间更短。AOF 文件重写跟 RDB 持久化一样分为手动触发和自动触发,手动触发直接调用 bgrewriteaof 命令就好了,我们后面会详细聊一聊这个命令,自动触发就需要我们在 redis.conf 中修改以下几个配置
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
- auto-aof-rewrite-percentage:代表当前 AOF文件空间 (aof_current_size)和上一次重写后 AOF 文件空间(aof_base_size)的比值,默认是 100%,也就是一样大的时候
- auto-aof-rewrite-min-size:表示运行 AOF 重写时 AOF 文件最小体积,默认为 64MB,也就是说 AOF 文件最小为 64MB 才有可能触发重写
满足了这两个条件,Redis 就会自动触发 AOF 文件重写,AOF 文件重写的细节跟 RDB 持久化生成快照有点类似,下面是 AOF 文件重写流程图:
AOF 文件重写也是交给子进程来完成,跟 RDB 生成快照很像,AOF 文件重写在重写期间建立了一个 aof_rewrite_buf 缓存区来保存重写期间主进程响应的命令,等新的 AOF 文件重写完成后,将这部分文件同步到新的 AOF 文件中,最后用新的 AOF 文件替换掉旧的 AOF 文件。需要注意的是在重写期间,旧的 AOF 文件依然会进行磁盘同步,这样做的目的是防止重写失败导致数据丢失,
Redis 持久化数据恢复
我们知道 Redis 是基于内存的,所有的数据都存放在内存中,由于机器宕机或者其他因素重启了就会导致我们的数据全部丢失,这也就是要做持久化的原因,当服务器重启时,Redis 会从持久化文件中加载数据,这样我们的数据就恢复到了重启前的数据,在数据恢复这一块Redis 是如何实现的?我们先来看看数据恢复的流程图:
Redis 的数据恢复流程比较简单,优先恢复的是 AOF 文件,如果 AOF 文件不存在时则尝试加载 RDB 文件,为什么 RDB 的恢复速度比 AOF 文件快,但是还是会优先加载 AOF 文件呢?我个人认为是 AOF 文件数据更全面并且 AOF 兼容性比 RDB 强,需要注意的是当存在 RDB/AOF 时,如果数据加载不成功,Redis 服务启动会失败。
最后
目前互联网上很多大佬都有 Redis 系列教程,如有雷同,请多多包涵了。原创不易,码字不易,还希望大家多多支持。若文中有所错误之处,还望提出,谢谢。
欢迎扫码关注微信公众号:「平头哥的技术博文」,和平头哥一起学习,一起进步。
一文带你深入了解 Redis 的持久化方式及其原理的更多相关文章
- Redis数据持久化机制AOF原理分析一---转
http://blog.csdn.net/acceptedxukai/article/details/18136903 http://blog.csdn.net/acceptedxukai/artic ...
- redis的持久化方式RDB和AOF的区别
1.前言 最近在项目中使用到Redis做缓存,方便多个业务进程之间共享数据.由于Redis的数据都存放在内存中,如果没有配置持久化,redis重启后数据就全丢失了,于是需要开启redis的持久化功能, ...
- redis的持久化方式
redis有两种持久化方式,第一种是基于快照的持久化方式,第二种是基于文件追加的持久化方式 一.基于快照的持久化 1.修改redis.conf配置文件,开启基于快照的持久化方式 2.修改持久化文件存放 ...
- 深入理解Redis的持久化机制和原理
Redis是一种面向“key-value”类型数据的分布式NoSQL数据库系统,具有高性能.持久存储.适应高并发应用场景等优势.它虽然起步较晚,但发展却十分迅速. 近日,Redis的作者在博客中写到, ...
- redis 的持久化方式
redis 持久化的两种方式 RDB:RDB 持久化机制,是对 redis 中的数据执行周期性的持久化. AOF:AOF 机制对每条写入命令作为日志,以 append-only 的模式写入一个日志文件 ...
- 分布式缓存Redis的持久化方式RDB和AOF
一.前言 Redis支持两种方式的持久化,RDB和AOF.RDB会根据指定的规则“定时”将内存中的数据存储到硬盘上,AOF会在每次执行命令后将命令本身记录下来.两种持久化方式可以单独使用其中一种,但更 ...
- Redis之持久化方式详解
背景:Redis之所以能够在技术革新发展迅速的时代超越Memcache等其他Nosql数据库,最主要的一点是Redis提供数据持久化,能够根据持久化策略将缓存数据灵活的写到磁盘上,更好地满足了当下海量 ...
- 一文带你深入了解 redis 复制技术及主从架构
主从架构可以说是互联网必备的架构了,第一是为了保证服务的高可用,第二是为了实现读写分离,你可能熟悉我们常用的 MySQL 数据库的主从架构,对于我们 redis 来说也不意外,redis 数据库也有各 ...
- [转载] redis 的两种持久化方式及原理
转载自http://www.m690.com/archives/371 Redis是一种高级key-value数据库.它跟memcached类似,不过数据可以持久化,而且支持的数据类型很丰富.有字符串 ...
随机推荐
- Jenkins基本使用
Jenkins安装 安装基本上属于傻瓜式安装了 选择安装路径不要包含中文 点击install 找到默认密码 选择插件安装 点击无,然后再选择安装 创建一个管理员 Jenkins配置任务 新建工程 输入 ...
- 维护基于ASP.NET的网站的学习-SqlCommand类介绍及存储过程
笔者目前在维护学校科技处的一个网站,目前学期初,教师申报项目操作多,出现了一些问题.前几天维护了一个验证码图片不显示的bug,今天想记录下这个解决了一整天的bug-老师项目结题需要手动修改数据库老师项 ...
- PHP array_shift
1.函数的作用:删除数组的头个元素并返回 2.函数的参数: @params array &$array 3.需要注意的例子: <?php /** * http://php.net/ma ...
- [LUOGU1437] 敲砖块
题目描述 在一个凹槽中放置了 n 层砖块.最上面的一层有n 块砖,从上到下每层依次减少一块砖.每块砖 都有一个分值,敲掉这块砖就能得到相应的分值,如下图所示. 14 15 4 3 23 33 33 7 ...
- sudo权限造成的故障
公司服务器故障: [chengsir@yinwucheng ~]$ sudo mkdir /opt/nginx sudo: /usr/bin/sudo must be owned by uid 0 a ...
- C语言I博客作业05
内容 答案 这个作业属于哪个课程 C语言程序设计II 这个作业要求在哪里 C语言I作业05 我在这个课程的目标是 更熟练的运用编译函数问题 这个作业在哪个具体方面帮助我实现目标 PTA实验作业 参考文 ...
- 百万年薪python之路 -- 并发编程之 多线程 三
1. 阻塞,非阻塞,同步,异步 进程运行的三个状态: 运行,就绪,阻塞. 从执行的角度: 阻塞: 进程运行时,遇到IO了,进程挂起,CPU被切走. 非阻塞: 进程没有遇到IO 当进程遇到IO, ...
- Linux 修改网卡名
1. 修改网卡配置文件 vim /etc/sysconfig/network-scripts/ifcfg-ens32 (“ens32”为当前网卡名) 将NAME.DEVICE项修改为eth0 2. ...
- python wraps的作用
1.__name__用来显示函数的名称,__doc__用来显示文档字符串也就是("""文档字符串""")这里面的内容 2.首先我们来看不加@ ...
- 务必收藏备用:.net core中通过Json或直接获取图形验证码(数字验证码、字母验证码、混合验证码),有源代码全实战demo(开源代码.net core3.0)
很多人写的博客大家看了会一知半解,不知道怎么用,应该引用什么类库或者代码不全,这样很多小白很是头疼,尤其是尝新技术更是如此.我们这边不止告诉你步骤,而且还提供开源demo.随着时间的推移,我们的dem ...