Redis系列2:数据持久化提高可用性
nanshan 2024-10-20 07:36 20 浏览 0 评论
1 介绍
从上一篇的 《深刻理解高性能Redis的本质》 中可以知道, 我们经常在数据库层上加一层缓存(如Redis),来保证数据的访问效率。
这样性能确实也有了大幅度的提升,但是本身Redis也是一层服务,也存在宕机、故障的可能性。
一旦服务挂起,可能生产的后果包括如下几方面:
1、Redis的数据是存在内存中的,所以一旦挂起,内存中的数据会全部丢失。
2、I/O从内存层级迁移到磁盘层级,性能极速下降。
3、原本访问缓存的请求会透过缓存层直接投向数据库,给数据库带来极大的压力,甚至导致雪崩。
所以,缓存层崩溃产生的后果是灾难的。为了避免宕机和宕机后的数据丢失, 为了保证数据的快速恢复,Redis提供了两个持久化数据的能力, AOF(Append Only FIle)日志 和 RDB 快照。
2 关于RDB 内存快照
大规模高并发的分布式场景,经常会遇到问题就是Redis挂起,导致访问失败,而所有的请求透过缓存层投向数据库,给数据库造成极大的压力。
而Redis的数据是存储在高速缓存中,即使我们重启并且恢复使用,缓存池依旧是空的,因为内存被释放了。
重新建立缓存的过程,对数据库也是一个暴击的过程,很可能会导致整个系统调用链的雪崩。参考我的这篇《架构与思维:一次缓存雪崩的灾难复盘》
我们知道,Redis 数据都是保存在内存中,能不能将内存中的数据进一步写到磁盘上,Redis 重启的时候就可以把磁盘上的数据快速恢复到内存中。这样,即使Redis宕机重启之后,依然能够正常的提供服务。
但是不能忽略一个问题,Redis和MySQL最大的区别之一就是一个存储在内存,一个持久化在磁盘。但是如果每次数据的变化(新增、修改、删除缓存)都要写内存并同时写磁盘,这样成本太高,内存+磁盘,会让 Redis 性能大大降低。而且还要保证原子性操作,避免内存和磁盘的数据不一致。
2.1 使用内存快照
为了避免实时写入高频操作磁盘带来的负面效应。Redis提供了内存快照策略。
我们知道,Redis 在 执行写(增、删、改)指令过程中,内存中数据会持续的在变化。而内存快照,指的是 Redis 内存中的数据在某一刻的状态。就好比如是拍照一样,你把那一刻的数据都定格下来,持久化到磁盘上。打游戏的同学可以想象存盘。
快照文件我们称之为 RDB 文件,即 Redis DataBase 的缩写。
Redis 通过定时执行 RDB 内存快照,这样就不必每次执行写指令都存盘,只需要在执行内存快照的时候写磁盘。这样既保证Redis的高效读写,还实现了定时持久化,宕机后可快速恢复数据。
如上图,在做数据恢复时,直接将 RDB 文件读入内存完成恢复。
2.2 生成RDB策略
Redis 提供了两种模式来生成 RDB 文件:
- save: 由主线程来执行,同步阻塞,只有等save完成后,才能进行新操作;
- bgsave:执行后,会立刻返回OK,同时调用 glibc 的函数fork产生一个子进程用于写入 RDB 文件,快照持久化完全交给子进程来处理。主进程继续执行他自己的工作,非阻塞。
2.2.1 save模式
save模式是主进程执行,非常不建议使用主进程执行的方式,在 《深刻理解高性能Redis的本质》 中,
我们知道他的主操作都是在单线程模型上完成的。所以尽量避免 RDB 文件生成影响主线程的网络I/O和键值对读写。
2.2.2 bgsave模式
上面提到的另外一种方式,fork一个子进程来写RDB文件。
Redis 使用操作系统的多进程写时复制技术 COW(Copy On Write) 来实现快照持久化,这个很重要,具体可以了解下这篇《Copy On Write机制》,写的不错。
Redis 在持久化时会调用 glibc 的函数fork产生一个子进程,由这个子进程来处理快照持久化的动作,子进程可以共享主进程的所有内存数据,所以它读取到主进程的数据之后写入到 RDB 文件。而父进程继续处理客户端的写操作,不受影响。
在创建 RDB 文件时,程序会对数据库中的键进行检查,仅仅将未过期的键保存到新创建的 RDB 文件中。
当主进程执行写指令修改数据的时候,这个数据就会复制一份副本, bgsave 子进程读取这个副本数据写到 RDB 文件,所以主进程就可以直接修改原来的数据。
这既保证了快照的完整性,也允许主进程同时对数据进行修改,避免了对正常业务的影响。
2.2.3 避免过频全量照片
虽然说Redis 使用 bgsave 函数 fork 子进程在后台完成 内存中的数据做快照,没有影响父进程继续处理客户端的各种操作。
但是需注意一点,过于频繁的执行全量的数据快照,必然会导致严重的性能开销:
- 频繁生成 RDB 文件写入磁盘,磁盘压力过大,效率降低。
- fork 出来的 bgsave 子进程因为共享主线程的数据,一定程度上会阻塞主线程的运行,主线程的内存越大,阻塞时间越长。
2.3 总结
- 快照的恢复速度快,但是生成 RDB 文件的频率需要把握一个度,频率过低快照间隔数据较大,丢失的数据就会比较多;频率太快,又会消耗额外开销,降低Redis性能。
- RDB 建议采用二进制 + 数据压缩的方式写磁盘,文件体积小,数据恢复速度快。
3 AOF 日志
AOF 日志存储了 Redis 服务器的顺序指令序列,AOF 日志只记录对内存进行修改的指令记录。
假设 AOF 日志记录了自 Redis 实例创建以来所有的修改性指令序列,那么就可以通过对一个空的 Redis 实例顺序执行所有的指令。
也就是说,可以通过重放(replay),来建立 Redis 当前实例的内存数据结构。这种模式有没有很熟悉,有没有想到MySQL主从同步时候的relay log。
3.1 日志变更前后对比
AOF记录日志有两种模式,一种是预写式日志,也称写前日志(Write Ahead Log, WAL): 在实际写数据之前,将修改的数据写到日志文件中。
另外一种是写后日志: 先执行写操作,当数据存入内存后,再记录日志。
预写式日志类似 MySQL Innodb 引擎 中的 redo log,修改数据前先记录日志,再修改。
3.2 日志格式
Redis 接收到 set keyName someValue 命令的时候,会先将数据写到内存,Redis 会按照如下格式写入 AOF 文件。
*3:表示当前指令分为三个部分,每个部分都是 $ + 数字开头,后面是3部分的具体内容:指令、键、值。
数字:表示这部分的命令、键、值多占用的字节大小。比如 $3表示这部分包含 3 个字符,也就是 set 的长度。
推荐使用写后日志的模式,避免了额外的检查开销,不需要对执行的命令进行语法检查。如果使用写前日志的话,就需要先检查语法是否有误,否则日志记录了错误的命令,在使用日志恢复的时候就会出错。另外,写后才记录日志,不会阻塞当前的 写 指令执行。
# set keyName someValue
*3
$3
set
$7 #长度为7
keyName
$9 #长度为9
someValue
# 执行 mset key1 1 ,key2 2 ,key33 3
# aof日志如下:
*7 # 本批命令需要往下读7行非 $ 开始的命令
$4 #接着读取4个字节宽度,‘mset’长度为4,记为 $4
mset
$4 #接着读取4个字节宽度,‘key1’长度为4,记为 $4
key1
$1 #接着读取1个字节宽度,‘1’长度为1,记为 $1
1
$4
key2
$1
2
$5 #接着读取的字节宽度,‘$key33’长度为5,记为 $5
key33
$1
3
3.3 可能存在的问题
- 可能存在丢失:比如Redis 刚执行完指令,还没记录日志宕机了,命令数据就丢了。
- AOF 避免了当前命令的阻塞,但是AOF 日志是主线程执行,将日志写入磁盘过程中,如果磁盘压力大就会导致执行变慢,降低后续的操作。
3.4 写回策略
上面的问题,在Redis高频读写的时候是必然存在的,想要解决,在写入的时候做一层缓冲就可以了,避免直塞。这时候Redis提供了一种执行策略叫写回策略。
3.4.1 写回策略说明
为了提高日志文件的写入效率,写回策略会做如下变化:
- 当你调用 write 函数将数据写入到文件时,这时候不是真正的落盘,而是将写入数据暂存在操作系统的内存缓冲区里。
- 待到缓冲区的空间被填满、或者超过了指定的阈值时候,才真正地将缓冲区中的数据写入到磁盘里面。
这种做法显然提高了效率,但也为写入数据带来了安全性问题,如果服务器发生了单机,那么保存在内存缓冲区里面的写入数据就会丢失。
为此,系统提供了fsync和fdatasync两个同步函数,它们可以强制让操作系统立即将缓冲区中的数据写入到硬盘里面,从而确保写入数据的安全性。
Redis 提供的 AOF 配置项 appendfsync 写回策略直接决定 AOF 持久化功能的效率和安全性,以下是 appendfsync 的3个枚举: - always:同步写回,写指令执行完 即将缓冲区内容回写到 AOF 文件。
- everysec:每秒写回,写指令执行完,日志写到 AOF 文件缓冲区,缓冲区每隔一秒再把内容同步到磁盘。
- no: 操作系统控制,写执行执行完毕,把日志写到 AOF 文件内存缓冲区,由操作系统决定何时回写到磁盘。
写磁盘会带来性能上的损耗,所以写回的策略要根据实际情况做一个取舍,比如你是偏向性能还是可靠性。
always 同步写回可以做到数据不丢失,但是每次执行写指令都需要写入磁盘,性能最差。
everysec 每秒写回,避免了同步写回的性能开销,但是如果服务发生宕机,会有大约1s时间周期的数据丢失,这种模式是在性能和可靠性之间做了妥协。
no 操作系统控制,执行写指令后就写入 AOF 文件缓冲,再执行后续的写磁盘指令,性能最好,但有可能丢失更多的数据。
3.4.2 写回策略的选择
我们可以根据服务的实际情况来抉择策略,看是偏向高性能还是高可靠。
- 高性能需求,选择 No 策略
- 高可靠性保证,就选择 Always 策略
- 如果能够接受数据存在少量丢失,又希望性能较好的话,就选择 Everysec 策略
4 混合RDF/AOF 方式模式
现实情况下,无论使用RDB或者AOF都差点意思。使用 rdb 来恢复内存状态,势必会丢失一部分数据。 使用 AOF 日志重放,重放对性能有一定的影响,而且在 Redis 实例很大的情况下,需要花费很长的时间。
Redis 4.0 解决了这个问题,才用了一个新的持久化模式——混合持久化,该 混合模式 默认是关闭状态的。
将 RDB 文件的内容和 rdb快照时间点之后的增量的 AOF 日志文件存在一起。这时候 AOF 日志不需要再是全量的日志,而是最近一次快照时间点之后到当下发生的增量 AOF 日志,通常这部分 AOF 日志很小。
所以执行有如下顺序:
- 查找rdb内容,如果存在先加载 rdb内容再 重放剩余的 aof。
- 没有rdb内容,直接以aof格式重放整个文件。
这样快照就不用频繁的执行,同时由于 AOF 只需要记录最近一次快照之后的数据,不需要记录所有的操作,避免了出现单次重放文件过大的问题。
5 总结
- RDB提供了快照模式,记录某个时间的Redis内存状态。RDB设计了 bgsave 和写时复制,尽可能避免执行快照期间对读写指令的影响,但是频繁快照会给磁盘带来压力以及 fork 阻塞主线程。需把握频率。
- AOF 日志存储了 Redis 服务的顺序指令序列,通过重放(replay)指令来写入日志文件,并通过写回策略来避免高频读写给Redis带来压力。
- RDB快照的照片时间间隔,必然会带来数据缺失,如果允许分钟级别的数据丢失,可以只使用 RDB。
- 如果只用 AOF,写回策略优先使用 everysec 的配置选项,因为它在可靠性和性能之间取了一个平衡。
- 数据不能丢失时,内存快照和 AOF 的混合使用是一个很好的选择。
作者:翁智华
出处:https://www.cnblogs.com/wzh2010/p/15886790.html
相关推荐
- 如何为MySQL服务器和客户机启用SSL?
-
用户想要与MySQL服务器建立一条安全连接时,常常依赖VPN隧道或SSH隧道。不过,获得MySQL连接的另一个办法是,启用MySQL服务器上的SSL封装器(SSLwrapper)。这每一种方法各有其...
- Mysql5.7 出现大量 unauthenticated user
-
线上环境mysql5.7突然出现大量unauthenticateduser,进mysql,showprocesslist;解决办法有:在/etc/hosts中添加客户端ip,如192.16...
- MySQL 在 Windows 系统下的安装(mysql安装教程windows)
-
更多技术文章MySQL在Windows系统下的安装1.下载mysql和Framework链接链接:百度网盘请输入提取码提取码:6w3p双击mysql-installer-communit...
- MySql5.7.21.zip绿色版安装(mysql数据库绿色版安装)
-
1、去网上下载满足系统要求的版本(mysql-5.7.21-winx64.zip)2、直接解压3、mysql的初始化(1)以管理员身份运行cmd,在mysql中的bin目录下shift+右键-在...
- MySQL(8.0)中文全文检索 (亲测有效)
-
在一堆文字中找到含有关键字的应用。当然也可以用以下语句实现:SELECT*FROM<表名>WHERE<字段名>like‘%ABC%’但是它的效率太低,是全盘扫描。...
- 新手教程,Linux系统下MySQL的安装
-
看了两三个教程。终于在哔哩哔哩找到一个简单高效的教程,成功安装,up主名叫bili逍遥bili,感兴趣可以去看看。下面这个是我总结的安装方法环境:CentOS764位1.下载安装包,个人觉得在...
- 麒麟服务器操作系统安装 MySQL 8 实战指南
-
原文连接:「链接」Hello,大家好啊,今天给大家带来一篇麒麟服务器操作系统上安装MySQL8的文章,欢迎大家分享点赞,点个在看和关注吧!MySQL作为主流开源数据库之一,被广泛应用于各种业务...
- 用Python玩转MySQL的全攻略,从环境搭建到项目实战全解析
-
这是一篇关于“MySQL数据库入门实战-Python版”的教程,结合了案例实战分析,帮助初学者快速掌握如何使用Python操作MySQL数据库。一、环境准备1.安装Python访问Pytho...
- 安装MySQL(中标麒麟 安装mysql)
-
安装MySQL注意:一定要用root用户操作如下步骤;先卸载MySQL再安装1.安装包准备(1)查看MySQL是否安装rpm-qa|grepmysql(2)如果安装了MySQL,就先卸载rpm-...
- Mysql最全笔记,快速入门,干货满满,爆肝
-
目录一、MySQL的重要性二、MySQL介绍三、软件的服务架构四、MySQL的安装五、SQL语句六、数据库相关(DDL)七、表相关八、DML相关(表中数据)九、DQL(重点)十、数据完...
- MAC电脑安装MySQL操作步骤(mac安装mysqldb)
-
1、在官网下载MySQL:https://dev.mysql.com/downloads/mysql/根据自己的macOS版本,选择适配的MySQL版本根据自己需求选择相应的安装包,我这里选择macO...
- mysql主从(mysql主从切换)
-
1、本章面试题什么是mysql主从,主从有什么好处什么是读写分离,有什么好处,使用mycat如何实现2、知识点2.1、课程回顾dubboORM->MVC->RPC->SOApro...
- 【linux学习】以MySQL为例,带你了解数据库
-
做运维的小伙伴在日常工作中难免需要接触到数据库,不管是MySQL,mariadb,达梦还是瀚高等其实命令都差不多,下面我就以MySQL为例带大家一起来了解下数据库。有兴趣的小伙伴不妨评论区一起交流下...
- 玩玩WordPress - 环境简介(0)(玩玩网络科技有限公司)
-
简介提到开源博客系统,一般都会直接想到WordPress!WordPress是使用PHP开发的,数据库使用的是MySQL,一般会在Linux上运行,Nginx作为前端。这时候就需要有一套LNMP(Li...
- 服务器常用端口都有哪些?(服务器端使用的端口号范围)
-
下面为大家介绍一下,服务器常用的一些默认端口,以及他们的作用: 21:FTP服务所开放的端口,用于上传、下载文件。 22:SSH端口,用于通过命令行模式远程连接Linux服务器或vps。 23:...
你 发表评论:
欢迎- 一周热门
-
-
极空间如何无损移机,新Z4 Pro又有哪些升级?极空间Z4 Pro深度体验
-
如何在安装前及安装后修改黑群晖的Mac地址和Sn系列号
-
UOS服务器操作系统防火墙设置(uos20关闭防火墙)
-
日本海上自卫队的军衔制度(日本海上自卫队的军衔制度是什么)
-
爱折腾的特斯拉车主必看!手把手教你TESLAMATE的备份和恢复
-
如何修复用户配置文件服务在 WINDOWS 上登录失败的问题
-
10个免费文件中转服务站,分享文件简单方便,你知道几个?
-
手机如何设置与显示准确时间的详细指南
-
【系统配置】信创终端挂载NAS共享全攻略:一步到位!
-
[常用工具] OpenCV_contrib库在windows下编译使用指南
-
- 最近发表
- 标签列表
-
- linux 查询端口号 (58)
- docker映射容器目录到宿主机 (66)
- 杀端口 (60)
- yum更换阿里源 (62)
- internet explorer 增强的安全配置已启用 (65)
- linux自动挂载 (56)
- 禁用selinux (55)
- sysv-rc-conf (69)
- ubuntu防火墙状态查看 (64)
- windows server 2022激活密钥 (56)
- 无法与服务器建立安全连接是什么意思 (74)
- 443/80端口被占用怎么解决 (56)
- ping无法访问目标主机怎么解决 (58)
- fdatasync (59)
- 405 not allowed (56)
- 免备案虚拟主机zxhost (55)
- linux根据pid查看进程 (60)
- dhcp工具 (62)
- mysql 1045 (57)
- 宝塔远程工具 (56)
- ssh服务器拒绝了密码 请再试一次 (56)
- ubuntu卸载docker (56)
- linux查看nginx状态 (63)
- tomcat 乱码 (76)
- 2008r2激活序列号 (65)