Redis系列:RDB内存快照提供持久化能力
1 介绍
从上一篇的 《深刻理解高性能Redis的本质》 中可以知道, 我们经常在数据库层上加一层缓存(如Redis),来保证数据的访问效率。
这样性能确实也有了大幅度的提升,因为从内存中取数远比从磁盘中快的多,但是本身Redis也是一层服务,也存在宕机、故障的可能性。
一旦服务挂起,可能生产的后果包括如下几方面:
1. Redis的数据是存在内存中的,所以一旦挂起,内存中的数据会全部丢失。
2. I/O从内存层级迁移到磁盘层级,性能极速下降。
3. 原本访问缓存的请求会透过缓存层直接投向数据库,给数据库带来极大的压力,甚至导致雪崩。
所以,缓存层崩溃产生的后果是灾难的。为了避免宕机和宕机后的数据丢失, 为了保证数据的快速恢复,Redis提供了两个持久化数据的能力,RDB Snapshot 和 AOF(Append Only FIle)日志。本章我们先来看看RDB快照的使用。
2 什么是RDB内存快照
大规模高并发的分布式场景,经常会遇到问题就是Redis挂起,导致访问失败,而所有的请求透过缓存层投向数据库,给数据库造成极大的压力,甚至雪崩。
而Redis的数据是存储在高速缓存中,即使我们重启并且恢复使用,缓存池依旧是空的,因为内存被释放了。
重新建立缓存的过程,对数据库也是一个暴击的过程,很可能会导致整个系统调用链的雪崩。参考我的这篇《架构与思维:一次缓存雪崩的灾难复盘》
所以更为稳妥的办法是持久化到磁盘中,这样哪怕重启数据也不会消失。但是如果每次数据的变化(增、删、改)都要写内存并同时写磁盘,这样成本太高,内存+磁盘的持续数据同步,会让 Redis 性能大大降低。而且还要保证原子性操作,避免内存和磁盘的数据不一致。
2.1 使用内存快照
为了避免实时写入高频操作磁盘带来的负面效应。Redis提供了内存快照策略。
工作原理是,Redis在指定的时间间隔内,将内存中的数据集快照定格下来,写入磁盘,并存储在副本文件中。当Redis重启时,这些快照文件会被自动读取并恢复到内存中。打游戏的同学可以想象存盘,下一次恢复游戏,可以从存盘的地方读取游戏直接开始。
如上图,将指定时间的Redis缓存数据进行快照。当发生故障的时候,直接从最接近的时间点进行数据恢复(即21:10的故障按照21点的RDB快照进行恢复),直接将 RDB 文件读入内存完成恢复。
2.2 生成RDB策略
在Redis的RDB持久化方案中,提供了两种模式来生成RDS文件,分别是 SAVE 和 BGSAVE。虽然都是用于创建内存快照并保存到磁盘的命令,但两者在执行方式和影响上有明显的区别。
SAVE命令会阻塞当前Redis服务器进程,直到RDB文件创建完毕。
在执行SAVE命令期间,Redis不能处理其他命令,阻塞主进程,这会导致服务器无法响应其他请求,直到RDB过程完成为止。因此,当数据量较大时,使用SAVE命令可能会对Redis的性能产生较大影响。
BGSAVE命令则会在后台异步进行快照操作,同时Redis还可以继续处理客户端的请求。
BGSAVE命令通过fork一个子进程来完成持久化任务,这样主进程就不会被阻塞,从而保证了Redis的高可用性。但是,由于需要fork一个子进程,BGSAVE命令可能会消耗更多的内存资源。
2.2.1 SAVE模式
save模式是主进程执行,非常不建议使用主进程执行的方式,在笔者的 《深刻理解高性能Redis的本质》 一文中,
我们介绍了它的主操作都是在单线程模型上完成的。所以 RDB 文件生成会影响主线程的网络I/O和键值对读写,导致客户端正常操作被阻塞,所以应该尽量避免。
2.2.2 BGSAVE模式
bgsave是后台异步执行,通过调用glibc函数创建一个子进程专门用于写入RDB文件,从而避免了主线程的阻塞。当执行BGSAVE命令时,Redis会继续处理其他客户端请求(比如Get、Set等),而子进程会在后台完成RDB文件的生成。这是Redis RDB文件生成的默认配置,也是推荐的方式。
上图执行流程如下:
- 执行bgsave命令,Redis主进程判断当前是否存在正在执行的RDB/AOF子进程,若果存在则bgsave命令直接返回。
- 主进程执行fork操作创建子进程,fork操作过程中父进程会阻塞(创建子进程),通过
info stats
命令查看latest_fork_usec
选项,可以获取最近一个fork操作的耗时,单位为微秒 - 父进程fork完成后,bgsave命令返回
Background saving started
信息,之后的操作都是异步的了,不再阻塞主进程,Client的Get、Set等操作依然可以执行。 - fork子进程的做法是通过调用glibc函数进行创建的,这步骤跟第2点对齐,都是会有短暂的阻塞。
- 子进程创建RDB文件,在主进程内存中生成临时快照文件,完成后对原有文件进行原子替换。执行
lastsave
命令可以获取最后一次生成RDB的时间,对应rdb_last_save_time
选项。 - 子进程发送信号给主进程表示完成,主进程接受到信息并更新统计记录。
以上整个过程保证了快照的完整性,也允许主进程同时对数据进行修改,避免了对正常业务的影响。
2.2.3 避免过频的全量Snapshot
虽然说Redis 使用 bgsave 函数 fork 子进程在后台完成内存中的数据做快照,并不阻塞父进程继续处理客户端的操作。
但过频执行全量数据快照,依然会导致严重的性能开销,主要如下:
- 频繁生成 RDB 文件写入磁盘,磁盘空间占用大,IO压力大,也会降低效率。
- fork 出来的 bgsave 子进程因为共享主线程的资源,一定程度上会影响主线程的运行性能。
2.3 总结
快照的恢复速度快,但是生成 RDB 文件的频率需要把握一个度,频率过低快照间隔数据较大,丢失的数据就会比较多;频率太快,又会消耗额外开销,降低Redis性能。
RDB内存快照优缺点如下:
优点:
- RDB以一种二进制格式+数据压缩的方式写磁盘,文件轻量。
- 数据恢复速度快,用于灾难恢复的场景,加载 RDB 恢复数据远快于 AOF 方式。
缺点:
- 无法做到实时持久化,每次都要创建子进程, 频繁操作成本过高
- 保存后的二进制文件, 存在老版本不兼容新版本 rdb 文件的问题
- 数据恢复不完全,快照时间点和故障时间点之间必然有时间差、数据差
Redis系列:RDB内存快照提供持久化能力的更多相关文章
- Redis系列之-—内存淘汰策略(笔记)
一.Redis ---获取设置的Redis能使用的最大内存大小 []> config get maxmemory ) "maxmemory" ) " --获取当前内 ...
- Redis的两种持久化方式-快照持久化(RDB)和AOF持久化
Redis为了内部数据的安全考虑,会把本身的数据以文件形式保存到硬盘中一份,在服务器重启之后会自动把硬盘的数据恢复到内存(redis)的里边,数据保存到硬盘的过程就称为“持久化”效果. redis有两 ...
- Redis系列2:数据持久化提高可用性
1 介绍 从上一篇的 <深刻理解高性能Redis的本质> 中可以知道, 我们经常在数据库层上加一层缓存(如Redis),来保证数据的访问效率. 这样性能确实也有了大幅度的提升,但是本身Re ...
- linux之 redis 的rdb 转 aof 及主从复
redis持久化RDB基于快照的持久化通过save命令,强制持久化 在redis.conf中dbfilename dbmp.rdbsave 900 1save 300 10save 60 10 ...
- Redis基础篇(四)持久化:内存快照(RDB)
AOF好处是每次执行只需要记录操作命令,记录量不大.但在故障恢复时,需要逐一执行AOF的操作命令,如果日志很大,恢复就很慢. 今天学习另一种持久化方式:内存快照.内存快照,是Redis某一时刻的状态, ...
- Redis持久化——内存快照(RDB)
最新:Redis持久化--如何选择合适的持久化方式 最新:Redis持久化--AOF日志 最新:Redis持久化--内存快照(RDB) 一文回顾Redis五大对象(数据类型) Redis对象--有序集 ...
- Redis系列(三):Redis的持久化机制(RDB、AOF)
本篇博客是Redis系列的第3篇,主要讲解下Redis的2种持久化机制:RDB和AOF. 本系列的前2篇可以点击以下链接查看: Redis系列(一):Redis简介及环境安装. Redis系列(二): ...
- redis 系列16 持久化 RDB
一.概述 Redis是内存数据库,一旦服务器进程退出,服务器中的数据库内存数据状态也会消失.为了解决这个问题,Redis提供了RDB 持久化功能,这个功能可以将redis在内存中的数据库状态保存到磁盘 ...
- redis系列:RDB持久化与AOF持久化
前言 什么是持久化? 持久化(Persistence),即把数据(如内存中的对象)保存到可永久保存的存储设备中(如磁盘).持久化的主要应用是将内存中的对象存储在数据库中,或者存储在磁盘文件中.XML数 ...
- redis 实战操作RDB和AOF快照持久化
前言:redis是我们常用的缓存方式,今天就来介绍下两种持久化的方式吧,先科普概念,再实战操作 一.RDB Redis将某一时刻的快照(备份的数据库数据)保存成一种称为RDB格式的文件中,这种格式是经 ...
随机推荐
- webservice--WSDL文件生成本地的代理类
我们在对应第三方接口时常用:项目上右键---->服务引用---->WCF Web Service,如下图的页面----->填好url后---->转到,就可以发现服务,生成代理类 ...
- JS ----- JS实用小功能
1.复制页面上文字功能 function copyIdCode() { var idcode = document.getElementById("personIdcodeCopy" ...
- PHP中文件锁
PHP中文件锁 文件锁的用途: 若一个人在写入一个文件,另外一个人同时也打个了这个文件进行写入文件. 这情况下,如果遇到一定的碰撞概率的话,不知道到底谁的操作为准. 因此,这个时候我们引入锁机制. 若 ...
- BoolToStr、TBooleanHelper、Boolean 转 字符串
方法1:直接使用 BoolToStr procedure TForm3.btn1Click(Sender: TObject); var a, b: Boolean; begin a := True; ...
- .NET Core开发实战(第17课:为选项数据添加验证:避免错误配置的应用接收用户流量)--学习笔记
17 | 为选项数据添加验证:避免错误配置的应用接收用户流量 三种验证方法 1.直接注册验证函数 2.实现 IValidateOptions 3.使用 Microsoft.Extensions.Opt ...
- 顺着这份Java面试地图,国内一二线互联网公司随便进...
原创:陶朱公Boy(微信公众号ID:taozhugongboy),欢迎分享,转载请保留出处. 前言 临近春节,这几天手头没什么事情,花了点时间,将自己近两年收集的面试真题,进行了一番深度归纳总结,整理 ...
- Linux dmesg命令使用方法详解
一.命令简介 dmesg(display message)命令用于显示开机信息.kernel 会将开机信息存储在 ring buffer 中.您若是开机时来不及查看信息,可利用 dmesg 来查看. ...
- 玩转 CMS2
玩转 CMS2 上篇研究了样式.请求.evn.mock,感觉对效率的提升没有太明显作用. 比如某个工作需要2天,现在1天可以干完,这就是很大的提升. 提高效率的方法有代码复用.模块化.低代码工具. 目 ...
- 【framework】WMS启动流程
1 前言 WMS 是 WindowManagerService 的简称. (1)WMS 主要职责 窗口管理:负责启动.添加.删除窗口,管理窗口大小.层级,核心成员有:WindowContainer ...
- 全排列II
全排列II 给定一个可包含重复数字的序列,返回所有不重复的全排列. 示例 输入: [1,1,2] 输出: [ [1,1,2], [1,2,1], [2,1,1] ] 题解 /** * @param { ...