理解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持久化有哪些策略?各自的实现原理是怎 ...
随机推荐
- 记录手动签名APK的过程
记录手动签名APK的过程 前两天更新了华为平台上的APK,被驳回,原因是新APK签名和老的APK不一致,老用户安装会失败,用命令行安装会报如下的错误: harlanc@harlancdeMacBook ...
- Python 命令行之旅:使用 docopt 实现 git 命令
作者:HelloGitHub-Prodesire HelloGitHub 的<讲解开源项目>系列,项目地址:https://github.com/HelloGitHub-Team/Arti ...
- Leetcode(3)无重复字符的最长子串
Leetcode(3)无重复字符的最长子串 [题目表述]: 给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度. 第一种方法:暴力 执行用时:996 ms: 内存消耗:12.9MB 效果: ...
- java中多线程 - 如何创建多线程
线程 什么是线程: 线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点儿在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源 表面上 ...
- Java源码 Integer.bitCount实现过程
public static int bitCount(int i) { // HD, Figure 5-2 i = i - ((i >>> 1) & 0x55555555); ...
- Shell进阶精品课程
课程链接 Shell精品进阶教程:理解Shell的方方面面 课程目标 系统性的掌握shell相关知识,进阶shell脚本能力,对shell各方面了然于心 适用人群 具备shell基础但想深入.系统性掌 ...
- Ubuntu编译安装nginx以及配置自动启动
本文主要介绍ubuntu如何编译安装nginx以及遇到的问题 和 配置系统自动启动服务 查看操作系统版本 cat /etc/issue Ubuntu 18.04.3 LTS \n \l 更改镜 ...
- Spring之Zuul初步使用(十)
一.zuul是什么 zuul 是netflix开源的一个API Gateway 服务器, 本质上是一个web servlet应用. Zuul 在云平台上提供动态路由,监控,弹性,安全等边缘服务的框架. ...
- python:__name__的使用
1.python中__name__是什么意思? 很多python的初学者可能都会遇到一个问题:__name__是什么意思? 在刚开始学习python的时候,我们总会看到这样一句代码: if __nam ...
- RocketMQ4.2 最佳实践之集群搭建
学习了RocketMQ的基本概念后,我们来看看RocketMQ最简单的使用场景.RocketMQ的服务器最简单的结构,必须包含一个NameServer和一个Broker.Producer把某个主题的消 ...