Redis RDB技术底层原理详解


Posted in Redis onSeptember 04, 2021

每日一句

低头是一种能力,它不是自卑,也不是怯弱,它是清醒中的嬗变。有时,稍微低一下头,或者我们的人生路会更精彩。

前提概要

Redis是一个的键-值(K-V)对的内存数据库服务,通常包含了任意个非空数据库。而每个非空的键值数据库中又可以存放任意个K-V,基本的结构如下图所示:

Redis RDB技术底层原理详解

  • Redis的强劲性能很大程度上是由于其将所有数据都存储在了内存中,为了使Redis在重启之后仍能保证数据不丢失,需要将数据从内存中以某种形式同步到硬盘中,这一过程就是持久化。
  • 我们知道redis中缓存的数据都存放在内存中,一旦服务故障,会导致内存中数据丢失,所以需要一种数据持久化的方案,将redis内存中的数据,写入磁盘,当redis重启后,能从磁盘中恢复数据。

Redis服务器的结构

  • 这里有一个问题,因为Redis是一个内存数据库,如果它直接将数据存储到内存中,但是如果不考虑将存储在内存中的数据持久化到硬盘里面,一旦服务器进程退出,那么数据库中的数据也会消失。
  • 数据库的持久化机制主要有两种,一种是RDB机制,另外一种是AOF机制,AOF机制已经在前面的文章中介绍过了,
  • 如果有兴趣可以去看看,而本文主要讲述RDB机制。

RDB持久化方式

RDB持久化是指在指定的时间间隔内将redis内存中的数据集快照写入磁盘,实现原理是redis服务在指定的时间间隔内先fork一个子进程,由子进程将数据集写入临时文件,写入成功后,再替换之前的文件,用二进制压缩存储,生成dump.rdb文件存放在磁盘中。

Redis RDB技术底层原理详解

RDB机制

  • Redis提供了RDB持久化能力,这个功能可以将Redis在内存中的数据库状态保持在磁盘里面,避免数据意外丢失。
  • RDB持久化机制可以手动执行,也可以根据服务器配置选定定期执行操作,该功能可以将某一个时间点的数据快照进行保存到一个RDB文件中。

RDB优势

  • 一旦采用该方式,那么你的整个Redis数据库将只包含一个文件,这对于文件备份而言是非常完美的。比如,你可能打算每个小时归档一次最近24小时的数据,同时还要每天归档一次最近30天的数据。通过这样的备份策略,一旦系统出现灾难性故障,我们可以非常容易的进行恢复。
  • 对于灾难恢复而言,RDB是非常不错的选择。因为我们可以非常轻松的将一个单独的文件压缩后再转移到其它存储介质上。
  • 性能最大化。对于Redis的服务进程而言,在开始持久化时,它唯一需要做的只是fork出子进程,之后再由子进程完成这些持久化的工作,这样就可以极大的避免服务进程执行IO操作了。
  • 相比于AOF机制,如果数据集很大,RDB的启动效率会更高。

RDB劣势

如果你想保证数据的高可用性,即最大限度的避免数据丢失,那么RDB将不是一个很好的选择。因为系统一旦在定时持久化之前出现宕机现象,此前没有来得及写入磁盘的数据都将丢失。

由于RDB是通过fork子进程来协助完成数据持久化工作的,因此,如果当数据集较大时,可能会导致整个服务器停止服务几百毫秒,甚至是1秒钟。

RDB配置规则

在redis的6379.conf配置文件中:

备份配置参数

save <seconds> <changes>

save <指定时间间隔> <执行指定次数更新操作>,满足条件就将内存中的数据同步到硬盘中。官方出厂配置默认是 900秒内有1个更改,300秒内有10个更改以及60秒内有10000个更改,则将内存中的数据快照写入磁盘。

save 900 1      #在900秒(15分钟)之后,如果至少有一个key发生变化,则dump内存快照
save 300 10     #在300秒(15分钟)之后,如果至少有10个key发生变化,则dump内存快照
save 60 10000   #在60秒(1分钟)之后,如果至少有10000个key发生变化,则dump内存快照

文件配置参数

默认的rdb文件路径是当前目录,文件名是dump.rdb,可以在配置文件中修改路径和文件名,分别是dir和dbfilename.

# 存放快照的目录
dir ./ # rdb文件存储路径
dbfilename dump.rdb # rdb文件名

压缩配置参数

在进行镜像备份时,是否进行压缩。

rdbcompression yes  #Redis默认是开启压缩的。
# yes:压缩,但是需要一些cpu的消耗。
# no:不压缩,需要更多的磁盘空间。

如果没有触发自动快照,需要对Redis执行手动快照操作,save和bgsave命令来手动快照,两个命令是:

  • SAVE:由主进程进行快照,会阻塞其他请求。
  • BGSAVE:通过fork子进程进行快照,不会阻塞其他请求。

注意:由于Redis使用fork来复制一份当前进程,那么子进程就会占有和主进程一样的内存资源,比如说主进程8G内存,那么在备份的时候,必须保证有16G的内存,要不然会启用虚拟内存,性能非常的差。

快照的过程如下:

  • Redis使用fork函数复制一份当前进程(父进程)的副本(子进程);
  • 父进程继续接收并处理客户端发来的命令,而子进程开始将内存中的数据写入硬盘中的临时文件;
  • 当子进程写入完所有数据后会用该临时文件替换旧的RDB文件,至此一次快照操作完成。(注意:会存在写一部命令压缩缓存区,记录写入rdb文件时候的操作)

在执行fork的时候操作系统会使用写时复制(copy-on-write)策略,即fork函数发生的一刻父子进程共享同一内存数据,当父进程要更改其中某片数据时(如执行一个写命令),操作系统会将该片数据复制一份以保证子进程的数据不受影响,所以新的RDB文件存储的是执行fork时那一刻的内存快照数据。

通过上述过程可以发现Redis在进行快照的过程中不会修改RDB文件,只有快照结束后才会将旧的文件替换成新的,也就是说任何时候RDB文件都是完整的。这使得可以通过定时备份RDB文件来实现Redis数据库备份。

快照的过程压缩分析:

RDB文件是经过压缩(上文介绍了:可以配置rdbcompression参数以禁用压缩节省CPU占用)的二进制格式,所以占用的空间会小于内存中的数据大小,更加利于传输。

快照的读取加载过程:

  • Redis启动后会读取RDB快照文件,将数据从硬盘载入到内存。根据数据量大小与结构和服务器性能不同,这个时间也不同。通常将一个记录一千万个字符串类型键、大小为1GB的快照文件载入到内存中需要花费20~30秒钟。
  • 通过RDB方式实现持久化,一旦Redis异常退出,就会丢失最后一次快照以后更改的所有数据。这就需要开发者根据具体的应用场合,通过组合设置自动快照条件的方式来将可能发生的数据损失控制在能够接受的范围。如果数据很重要以至于无法承受任何损失,则可以考虑使用AOF方式进行持久化。

RDB 的优缺点

优点:

  1. 适合大规模的数据恢复。
  2. 如果业务对数据完整性和一致性要求不高,RDB是很好的选择。

缺点:

  • 数据的完整性和一致性不高,因为RDB可能在最后一次备份时宕机了。
  • 备份时占用内存,因为Redis 在备份时会独立创建一个子进程,将数据写入到一个临时文件(此时内存中的数据是原来的两倍),最后再将临时文件替换之前的备份文件。
  • 由于RDB是通过fork子进程来协助完成数据持久化工作的,因此,如果当数据集较大时,可能会导致整个服务器停止服务几百毫秒,甚至是1秒钟。(回写和覆盖的时候用的是主进程)。

RDB与AOF二者选择的标准(虽然还没有讲AOF,提前普及)

  • 如果系统是愿意牺牲一些性能,换取更高的缓存一致性(aof)
  • 或者是愿意写操作频繁的时候,不启用备份来换取更高的性能,待手动运行save的时候,再做备份(rdb)。

Redis允许同时开启AOF和RDB,既保证了数据安全又使得进行备份等操作十分容易。此时重新启动Redis后Redis会使用AOF文件来恢复数据,因为AOF方式的持久化可能丢失的数据更少。

总结

  • Redis 默认开启RDB持久化方式,在指定的时间间隔内,执行指定次数的写操作,则将内存中的数据写入到磁盘中。
  • RDB 持久化适合大规模的数据恢复但它的数据一致性和完整性较差。
  • Redis 需要手动开启AOF持久化方式,默认是每秒将写操作日志追加到AOF文件中。

所以Redis的持久化和数据的恢复要选择在夜深人静的时候执行是比较合理的。

到此这篇关于Redis RDB技术底层原理详解的文章就介绍到这了,更多相关Redis RDB底层原理内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Redis 相关文章推荐
redis通过6379端口无法连接服务器(redis-server.exe闪退)
May 08 Redis
Redis基于Bitmap实现用户签到功能
Jun 20 Redis
厉害!这是Redis可视化工具最全的横向评测
Jul 15 Redis
Redis 常见使用场景
Aug 30 Redis
为什么RedisCluster设计成16384个槽
Sep 25 Redis
Redis三种集群模式详解
Oct 05 Redis
Redis+Lua脚本实现计数器接口防刷功能(升级版)
Feb 12 Redis
Redis 中使用 list,streams,pub/sub 几种方式实现消息队列的问题
Mar 16 Redis
redis数据结构之压缩列表
Mar 21 Redis
Redis分布式锁的7种实现
Apr 01 Redis
sentinel支持的redis高可用集群配置详解
Apr 01 Redis
Redis实现订单过期删除的方法步骤
Jun 05 Redis
使用redis实现延迟通知功能(Redis过期键通知)
Redis集群新增、删除节点以及动态增加内存的方法
Sep 04 #Redis
Redis字典实现、Hash键冲突及渐进式rehash详解
Sep 04 #Redis
基于Redis的List实现特价商品列表功能
Aug 30 #Redis
Redis 常见使用场景
Aug 30 #Redis
Redis入门教程详解
Redis如何实现分布式锁
Aug 23 #Redis
You might like
基于Zend的Captcha机制的应用
2013/05/02 PHP
Thinkphp5.0 框架实现控制器向视图view赋值及视图view取值操作示例
2019/10/12 PHP
php5.3/5.4/5.5/5.6/7常见新增特性汇总整理
2020/02/27 PHP
JQuery 小练习(实例代码)
2009/08/07 Javascript
Ext JS 4实现带week(星期)的日期选择控件(实战一)
2013/08/21 Javascript
JS页面延迟执行一些方法(整理)
2013/11/11 Javascript
三种取消选中单选框radio的方法
2014/09/09 Javascript
js实现三张图(文)片一起切换的banner焦点图
2015/08/25 Javascript
JavaScript时间操作之年月日星期级联操作
2016/01/15 Javascript
浅谈jquery之on()绑定事件和off()解除绑定事件
2016/10/26 Javascript
解决IE7中使用jQuery动态操作name问题
2017/08/28 jQuery
JavaScript实现省市联动过程中bug的解决方法
2017/12/04 Javascript
深入浅析angular和vue还有jquery的区别
2018/08/13 jQuery
javascript实现考勤日历功能
2018/11/29 Javascript
Windows下支持自动更新的Electron应用脚手架的方法
2018/12/24 Javascript
详解webpack编译速度提升之DllPlugin
2019/02/05 Javascript
js比较两个单独的数组或对象是否相等的实例代码
2019/04/28 Javascript
JavaScript中关于base64的一些事
2019/05/06 Javascript
js实现指定时间倒计时效果
2019/08/26 Javascript
layui实现鼠标移动到单元格上显示数据的方法
2019/09/11 Javascript
原生JS无缝滑动轮播图
2019/10/22 Javascript
JS实现的定时器展示简单秒表、页面弹框及跳转操作完整示例
2020/01/26 Javascript
python 查找文件名包含指定字符串的方法
2018/06/05 Python
利用python在excel里面直接使用sql函数的方法
2019/02/08 Python
Python实现K折交叉验证法的方法步骤
2019/07/11 Python
Python zip函数打包元素实例解析
2019/12/11 Python
Win10用vscode打开anaconda环境中的python出错问题的解决
2020/05/25 Python
python 实现两个npy档案合并
2020/07/01 Python
HTML5 Canvas 实现K线图的示例代码
2019/12/23 HTML / CSS
移动端HTML5 input常见问题(小结)
2020/09/28 HTML / CSS
ivx平台开发之不用代码实现一个九宫格抽奖功能
2021/01/27 HTML / CSS
美国演唱会和体育门票购买网站:Ticketnetwork
2018/10/19 全球购物
安全保证书格式
2015/02/28 职场文书
员工辞退通知书
2015/04/17 职场文书
500字作文之难忘的同学
2019/12/20 职场文书
Win11 PC上的Outlook搜索错误怎么办?
2022/07/15 数码科技