理解Redis持久化
本文首发于:https://mp.weixin.qq.com/s/WVUGWuNrGoyY_7aDf7NNmA
微信公众号:后端技术指南针
0.前言
通俗讲持久化就是将内存中的数据写入非易失介质中,比如机械磁盘和SSD。
在服务器发生宕机时,作为内存数据库Redis里的所有数据将会丢失,
因此Redis提供了持久化两大利器:RDB和AOF。
RDB:Redis Dump Binary #全量二进制导出 AOF: Append-Only File #增量文件追加
- RDB 将数据库快照以二进制的方式保存到磁盘中。
- AOF 以协议文本方式,将所有对数据库进行过写入的命令和参数记录到 AOF 文件,从而记录数据库状态。
1.RDB的配置
- 查看RDB配置
[redis@abc]$ cat /abc/redis/conf/redis.conf save save save dbfilename "dump.rdb" dir "/data/dbs/redis/rdbstro"
上图为Redis配置文件里默认的RDB设置:
前三行都是对触发RDB的一个条件, 如第一行表示每900秒钟有一条数据被修改则触发RDB,依次类推;只要一条满足就会进行RDB持久化;
第四行dbfilename指定了把内存里的数据库写入本地文件的名称,该文件是进行压缩后的二进制文件;
第五行dir指定了RDB二进制文件存放目录 ;
- 修改RDB配置
在命令行里进行配置,服务器重启才会生效:
[redis@abc]$ bin/redis-cli > CONFIG GET save ) "save" ) "900 1 300 10 60 10000" > CONFIG SET save "21600 1000" OK
2.RDB的SAVE和BGSAVE
RDB文件是很适合数据的容灾备份与恢复,通过RDB文件恢复数据库耗时较短,可以快速恢复数据。
RDB持久化只会周期性的保存数据,在未触发下一次存储时服务宕机,就会丢失增量数据。
当数据量较大的情况下,fork子进程这个操作很消耗cpu,可能会发生长达秒级别的阻塞情况。
SAVE是阻塞式持久化,执行命令时Redis主进程把内存数据写入到RDB文件中直到创建完毕,期间Redis不能处理任何命令。
BGSAVE属于非阻塞式持久化,创建一个子进程把内存中数据写入RDB文件里,同时主进程处理命令请求。
如图展示了bgsave的简单流程:
3.BGSAVE实现细节
RDB方式的持久化是通过快照实现的,符合条件时Redis会自动将内存数据进行快照并存储在硬盘上,以BGSAVE为例,一次完整数据快照的过程:
- Redis使用fork函数创建子进程;
- 父进程继续接收并处理命令请求,子进程将内存数据写入临时文件;
- 子进程写入所有数据后会用临时文件替换旧RDB文件;
执行fork的时OS会使用写时拷贝策略,对子进程进行快照过程优化。
Redis在进行快照过程中不会修改RDB文件,只有快照结束后才会将旧的文件替换成新的,也就是任何时候RDB文件都是完整的。
我们可以通过定时备份RDB文件来实现Redis数据库备份,RDB文件是经过压缩的,占用的空间会小于内存中的数据大小。
除了自动快照还可以手动发送SAVE或BGSAVE命令让Redis执行快照。
通过RDB方式实现持久化,由于RDB保存频率的限制,如果数据很重要则考虑使用AOF方式进行持久化。
4.AOF的配置
在使用AOF持久化方式时,Redis会将每一个收到的写命令都通过Write函数追加到文件中类似于MySQL的binlog。
换言之AOF是通过保存对redis服务端的写命令来记录数据库状态的。AOF文件有自己的存储协议格式:
[redis@abc]$ more appendonly.aof * # 2个参数 $ # 第一个参数长度为 SELECT # 第一个参数 $ # 第二参数长度为 # 第二参数 * # 3个参数 $ # 第一个参数长度为 SET # 第一个参数 $ # 第二参数长度为 name # 第二个参数 $ # 第三个参数长度为 Jhon # 第二参数长度为
AOF配置:
[redis@abc]$ more ~/redis/conf/redis.conf dir "/data/dbs/redis/abcd" #AOF文件存放目录 appendonly yes #开启AOF持久化,默认关闭 appendfilename "appendonly.aof" #AOF文件名称(默认) appendfsync no #AOF持久化策略 auto-aof-rewrite-percentage #触发AOF文件重写的条件(默认) auto-aof-rewrite-min-size 64mb #触发AOF文件重写的条件(默认)
当开启AOF后,服务端每执行一次写操作就会把该条命令追加到一个单独的AOF缓冲区的末尾,然后把AOF缓冲区的内容写入AOF文件里,
由于磁盘缓冲区的存在写入AOF文件之后,并不代表数据已经落盘了,
而何时进行文件同步则是根据配置的appendfsync来进行配置。
appendfsync有三个选项:always、everysec和no:
- always:服务器在每执行一个事件就把AOF缓冲区的内容强制性的写入硬盘上的AOF文件里,保证了数据持久化的完整性,效率是最慢的但最安全的;
- everysec:服务端每隔一秒才会进行一次文件同步把内存缓冲区里的AOF缓存数据真正写入AOF文件里,兼顾了效率和完整性,极端情况服务器宕机只会丢失一秒内对Redis数据库的写操作;
- no:表示默认系统的缓存区写入磁盘的机制,不做程序强制,数据安全性和完整性差一些。
5.AOF重写
- AOF重写的必要性
AOF比RDB文件更大,并且在存储命令的过程中增长更快,为了压缩AOF的持久化文件,Redis提供了重写机制以此来实现控制AOF文件的增长。
AOF重写实现的理论基础是这样的:
- 执行set hello world 50次
- 最后执行一次 set hello china
- 最终对于AOF文件而言前面50次都是无意义的,AOF重写就是将key只保存最后的状态。
- 重写期间的数据一致性问题
子进程在进行 AOF 重写期间, 主进程还需要继续处理命令, 而新的命令可能对现有的数据进行修改, 会出现数据库的数据和重写后的 AOF 文件中的数据不一致。
因此Redis 增加了一个 AOF 重写缓存, 这个缓存在 fork 出子进程之后开始启用, Redis 主进程在接到新的写命令之后, 除了会将这个写命令的协议内容追加到现有的 AOF 文件之外, 还会追加到这个缓存中。
- AOF文件覆盖
当子进程完成 AOF 重写之后向父进程发送一个完成信号, 父进程在接到完成信号之后会调用信号处理函数,完成以下工作:
- 将 AOF 重写缓存中的内容全部写入到新 AOF 文件中
- 对新的 AOF 文件进行改名,覆盖原有的 AOF 文件
- AOF重写的阻塞性
整个 AOF 后台重写过程中只有最后写入缓存和改名操作会造成主进程阻塞, 在其他时候AOF 后台重写都不会对主进程造成阻塞, 将 AOF 重写对性能造成的影响降到了最低。
- AOF重写的触发条件
AOF 重写可以由用户通过调用 BGREWRITEAOF 手动触发。服务器在 AOF 功能开启的情况下,会维持以下三个变量:
- 当前 AOF 文件大小
- 最后一次 重写之后, AOF 文件大小的变量
- AOF文件大小增长百分比
每次当 serverCron 函数执行时, 它都会检查以下条件是否全部满足, 如果是的话, 就会触发自动的 AOF 重写:
- 没有 BGSAVE 命令在进行 防止于RDB的冲突
- 没有 BGREWRITEAOF 在进行 防止和手动AOF冲突
- 当前 AOF 文件大小至少大于设定值 基本要求 太小没意义
- 当前 AOF 文件大小和最后一次 AOF 重写后的大小之间的比率大于等于指定的增长百分比
6.Redis的数据恢复
- Redis 恢复优先级
- 如果只配置 AOF ,重启时加载 AOF 文件恢复数据;
- 如果同时配置了 RDB 和 AOF ,启动只加载 AOF 文件恢复数据;
- 如果只配置 RDB,启动将加载 dump 文件恢复数据。
- AOF恢复方式
拷贝 AOF 文件到 Redis 的数据目录,启动 redis-server AOF 的数据恢复过程:Redis 虚拟一个客户端,读取AOF文件恢复 Redis 命令和参数,然后执行命令从而恢复数据。这些过程主要在loadAppendOnlyFile() 中实现。
- RDB恢复方式
拷贝 RDB 文件到 Redis 的数据目录,启动 redis-server即可,因为RDB文件和重启前保存的是真实数据而不是命令状态和参数。
7.新型的混合型持久化
RDB和AOF都有各自的缺点:
- RDB是每隔一段时间持久化一次, 故障时就会丢失宕机时刻与上一次持久化之间的数据,无法保证数据完整性
- AOF存储的是指令序列, 恢复重放时要花费很长时间并且文件更大
Redis 4.0 提供了更好的混合持久化选项: 创建出一个同时包含 RDB 数据和 AOF 数据的 AOF 文件, 其中 RDB 数据位于 AOF 文件的开头,
它们储存了服务器开始执行重写操作时的数据库状态,至于那些在重写操作执行之后执行的 Redis 命令,
则会继续以 AOF 格式追加到 AOF 文件的末尾, 也即是 RDB 数据之后。
8.持久化实战
在实际使用中需要根据Redis作为主存还是缓存、数据完整性和缺失性的要求、CPU和内存情况等诸多因素来确定适合自己的持久化方案,
一般来说稳妥的做法包括:
- 最安全的做法是RDB与AOF同时使用,即使AOF损坏无法修复,还可以用RDB来恢复数据,当然在持久化时对性能也会有影响。
- Redis当简单缓存,没有缓存也不会造成缓存雪崩只使用RDB即可。
- 不推荐单独使用AOF,因为AOF对于数据的恢复载入比RDB慢,所以使用AOF的时候,最好还是有RDB作为备份。
- 采用新版本Redis 4.0的持久化新方案。
理解Redis持久化的更多相关文章
- 一篇文章彻底理解Redis持久化:RDB和AOF
为什么需要持久化? Redis对数据的操作都是基于内存的,当遇到了进程退出.服务器宕机等意外情况,如果没有持久化机制,那么Redis中的数据将会丢失无法恢复.有了持久化机制,Redis在下次重启时可以 ...
- 5分钟彻底理解Redis持久化
Redis持久化 RDB快照 在默认情况下,Redis将内存数据库快照保存到dump.rdb的二进制文件中. 可以对Redis进行设置,让它在"N秒内数据集至少有N个改动", 这一 ...
- 10分钟彻底理解Redis持久化和主从复制
在这篇文章,我们一起了解 Redis 使用中非常重要的两个机制:Reids 持久化和主从复制. 什么是 Redis 持久化? Redis 作为一个键值对内存数据库(NoSQL),数据都存储在内存当中, ...
- 读完这篇,让你真正理解Redis持久化
什么叫持久化? 用一句话可以将持久化概括为:将数据(如内存中的对象)保存到可永久保存的存储设备中. 持久化的主要应用是将内存中的对象存储在数据库中,或者存储在磁盘文件中. XML 数据文件中等等. 也 ...
- 深入理解redis持久化
持久化方式: 快照(RDB)方式,默认方式,文件以二进制方式保存到RDB文件. 文件追加(AOF)方式,文件以协议文本的方式write到AOF文件. 作用,重启后的数据恢复.当两种方式都启用时,red ...
- 源码级别理解 Redis 持久化机制
文章首发于公众号"蘑菇睡不着",欢迎来访~ 前言 大家都知道 Redis 是一个内存数据库,数据都存储在内存中,这也是 Redis 非常快的原因之一.虽然速度提上来了,但是如果数据 ...
- 【redis持久化】redis持久化理解
1.以下内容仅为个人理解和总结,仅供参考,万万不可全盘真信,内容会进行实时改进和修正 2.redis持久化: 参考链接1.https://redis.io/topics/persistence -- ...
- 深入理解Redis的持久化机制和原理
Redis是一种面向“key-value”类型数据的分布式NoSQL数据库系统,具有高性能.持久存储.适应高并发应用场景等优势.它虽然起步较晚,但发展却十分迅速. 近日,Redis的作者在博客中写到, ...
- 【大厂面试06期】谈一谈你对Redis持久化的理解?
Redis持久化是面试中经常会问到的问题,这里主要通过对以下几个问题进行分析,帮助大家了解Redis持久化的实现原理. 1.Redis持久化是什么? 2.Redis持久化有哪些策略?各自的实现原理是怎 ...
随机推荐
- 百万年薪python之路 -- 字典(dict)
1.字典(dict)-- dict关键字 字典(dict)是python中唯⼀的⼀个映射类型.他是以{ }括起来的键值对组成. 字典中逗号分隔叫作一个元素 字典是无序的 key必须是不可变 ...
- JUC - ReentrantLock 的基本用法 以及 lock()、tryLock()、lockInterruptibly()的区别
ReentrantLock 与 synchronized对比 最近有在阅读Java并发编程实战这本书,又看到了ReentrantLock和synchronized的对比,发现自己以前对于Renntra ...
- [线段树系列] LCT打延迟标记的正确姿势
这一篇博客将教你什么? 如何用LCT打延迟标记,LCT和线段树延迟标记间的关系,为什么延迟标记要这样打. ——正片开始—— 学习这一篇博客前,确保你会以下知识: Link-Cut-Tree,普通线段树 ...
- Xbim.GLTF源码解析(四):轻量化处理
原创作者:flowell,转载请标明出处:https://www.cnblogs.com/flowell/p/10839433.html 在IFC标准中,由IfcRepresentationMap支持 ...
- 写出float x 与“零值”比较的if语句——一道面试题分析
写出float x 与“零值”比较的if语句 请写出 float x 与“零值”比较的 if 语句: const float EPSINON = 0.00001; if ((x >= - E ...
- UE4蓝图与C++交互——射击游戏中多武器系统的实现
回顾 学习UE4已有近2周的时间,跟着数天学院"UE4游戏开发"课程的学习,已经完成了UE4蓝图方面比较基础性的学习.通过UE4蓝图的开发,我实现了类似CS的单人版射击游戏,效 ...
- 解决MacOs 下的 matplotlib 中文字体乱码
在使用 matplotlib 时候,如果表中有中文字体,那么可能会出现无法显示的情况,原因是因为缺少中文字体,可以使用以下步骤解决. 查看 matplotlib 的位置 matplotlib.matp ...
- NOIP模拟测试25
这次考试后面心态爆炸了...发现刚了2h的T2是假的之后就扔掉了,草率地打了个骗分 T1只会搜索和m=0 最先做的T3,主要是发现部分分很多,当时第一眼看上去有87分(眼瞎了). 后来想了想,感觉一条 ...
- 使用webpack+babel构建ES6语法运行环境
1.前言 由于ES6语法在各个浏览器上支持的情况各不相同,有的浏览器对ES6语法支持度较高,而有的浏览器支持较低,所以为了能够兼容大多数浏览器,我们在使用ES6语法时需要使用babel编译器将代码中的 ...
- 简单搭建DNS服务器——bind
1安装bind yum install -y bind bind-utils bind-chroot 2 修改配置文件 # grep '^[^#]' /etc/named.conf options { ...