坏了,Redis服崩了,内存中的数据该如何恢复?
mhr18 2024-10-24 11:15 27 浏览 0 评论
介绍
Redis中的数据存在内存中,如果突然宕机,那么内存中的数据将全部丢失。如果数据能从后端数据库恢复还好,如果数据只存在Redis中,那数据就全丢失了。并且如果请求量很多,MySQL服务器的压力会很大。
所以最好的方式是对数据进行持久化,并能当宕机的时候能快速恢复
在Redis中有如下两种持久化方式,rdb快照和aof日志
RDB
rdb就是对当前数据库的状态做一个快照,将某个阶段的数据通过二进制文件保存下来。你可以类比照相。内存中的数据越多,生成快照的时候就越长,同时将快照写入磁盘耗费的时间也越长。
这时我们不经要问,生成快照会阻塞主线程吗? 如果会阻塞主线程,则会影响正常请求的处理
在Redis中有两个命令可以用于生成RDB文件,一个是save,另一个是bgsave
- save:在主线程中执行,会导致阻塞
- bgsave:主线程fork出一个子进程负责创建rdb文件,不会阻塞主线程
我们当然毫不犹豫的选择bgsave,毕竟不会阻塞主线程
那当我们使用bgsave时生成镜像的时候数据还能被修改吗?
如果数据允许被修改,会有很多问题。例如,bgsave子进程刚持久化完一个key,结果主线程就把这个key给删了,会造成数据不一致。
如果数据不允许被修改,那么所有写操作只能等到rdb文件生成完才能执行,影响性能。
这时我们就不得不提到COW了,redis是使用多进程COW机制来实现快照持久化的
Copy-On-Write,COW
Redis在进行持久化的时候,会fork出一个子进程,快照持久化交给子进程来完成。子进程刚刚产生的时候,它和父进程共享里面的数据段和代码段。所以在进程分离的一瞬间,内存的增长机会没有变化。
子进程做持久化,不会修改内存中的数据,但是主线程不一样,它会持久接收客户端的修改请求,然后修改内存中的数据。
这时就会使用操作系统的COW机制来进行数据段页面的分离。数据段由很多操作系统的页面组成,当父进程对其中一个页面的数据进行修改时,会将被共享的页面复制一份分离出来,然后对这个复制的页面进行修改。这时子进程相应的页面是没有变化的,还是进程产生时的数据。
随着父进程修改操作的进行,越来越多共享的页面被分离出来,页面就会持续增长,但是不超过原有内存的2倍。
子进程中的数据一直没有变化,它就可以安心的做持久化了。
如果每隔1分钟生成一个快照,宕机后还是会丢失快照生成后所执行的操作(最多为1分钟之内的操作)。我们把生成快照的时间缩短,又会影响Redis性能,毕竟fork子进程会阻塞主线程,频繁读写磁盘,也会给磁盘带来很大压力。
这是就不得不提到另一种持久化的方式,aof日志
AOF
当我们每次执行一条命令的时候,把对应的操作记到aof日志中,当redis宕机的时候我们只要重放日志就能恢复数据。而且Redis是以文本的形式保存aof日志的
例如当我们执行如下一条命令
set key value
1
aof文件中就会追加如下的内容
*3
$3
set
$3
key
$5
value
1234567
*3表示当前命令有3个部分,每部分都是由“$+数字开头”,数字表示命令,键或者值由几个字节组成
需要注意的是,redis中记录的是写后日志,即先执行命令,再写日志。
那要是命令执行成功,还没有来得及写日志?那么服务宕机后这条命令不是丢失了?
因为aof日志是在主线程中写入的,如果每次写日志都刷到磁盘,岂不是很影响性能?
好在redis给我们提供了三种写aof日志的方式
always:同步写回,写命令执行完就同步到磁盘
everysec:每秒写回,每个写命令执行完,只是先把日志写到aof文件的内存缓冲区,每隔1秒将缓冲区的内容写入磁盘
no:操作系统控制写回,每个写命令执行完,只是先把日志写到aof文件的内存缓冲区,由操作系统决定何时将缓冲区内容写回到磁盘
当aof的刷盘机制为always,redis每处理一次写命令,都会把写命令刷到磁盘中才返回,整个过程是在Redis主线程中进行的,势必会拖慢redis的性能
当aof的刷盘机制为everysec,redis写完内存后就返回,刷盘操作是放到后台线程中去执行的,后台线程每隔1秒把内存中的数据刷到磁盘中
当aof的刷盘机制为no,宕机后可能会造成部分数据丢失,一般不采用。
一般情况下,aof刷盘机制配置为everysec即可
aof日志是通过保存被执行的写命令来记录数据库状态的,随着时间的流逝,aof日志会越来越大,使用aof文件来还原数据所需要的时间也越来越长。有没有什么优化方案呢?此时aof日志重写登场了。
AOF日志重写
假如说客户端依次执行了如下5条命令
127.0.0.1:6379> rpush list 1
(integer) 1 // [1]
127.0.0.1:6379> rpush list 2
(integer) 2 // [1, 2]
127.0.0.1:6379> rpush list 3
(integer) 3 // [1, 2, 3]
127.0.0.1:6379> lpop list
"1" // [2, 3]
127.0.0.1:6379> rpush list 1
(integer) 3 // [2, 3, 1]
12345678910
单独记list这个key的状态就得有5条日志。要是能把这5条命令合并成 rpush list 2 3 1这个命令就好了。其实这就是aof日志重写要干的事情,那么如何实现呢?
虽然Redis将生成新的aof文件的功能命名为"aof重写",但是aof重写并不需要对现有aof文件进行任何读取,分析操作。而是直接读取读取内存中的最新值,然后保存对应的命令。
例如上面的例子,redis直接读取list的值,并生成一条rpush list 2 3 1命令放到aof日志中。
可以看到aof重写是一个非常耗时的操作,那么它会阻塞主线程吗?
不会,因为作为一种优化手段,Redis肯定不希望它被阻塞。所以每次重写的时候主线程fork出一个bgrewriteaof子进程。bgrewriteaof子进程使用Copy-On-Write技术来读取内存中的数据,写新的aof日志
那在重写aof日志的过程中,主线程执行的操作该怎么写到新的aof日志中?
其实在aof日志重写的过程中,主线程会把操作同步到aof缓冲区和aof重写缓冲区。当子线程完成aof重写,并且将aof重写缓冲区的内容,写入新的aof日志中时,就会用新的aof日志代替旧的aof日志
Redis生成rdb文件和aof日志重写,都是通过主线程fork子进程的方式,让子进程来执行的
Redis4.0混合持久化
当使用RDB做持久化时,宕机后会造成一部分数据的丢失,此时可以缩短生成RDB快照的时间间隔,但是如果频繁的生成RDB快照,有会有如下两方面的问题
- 频繁的将全量数据写到磁盘,会给磁盘造成很大的压力
- 主线程fork子进程来生成rdb快照,子进程生成rdb快照不会阻塞主线程,但是主线程通过fork创建子进程的过程会阻塞主线程,主线程的内存越大,阻塞时间越长。
当使用AOF做持久化的时候,数据完整性较高,但是宕机后恢复时间比较长。
那有没有什么方法?即能做到快速恢复,又能保证数据完整性较高?
你别说,还真有。Redis4.0提出了一种混合持久化的方式。
混合持久化同样也是通过bgrewriteaof完成的(即aof重写的进程),不同的是当开启混合持久化时,fork出的子进程先将共享的内存副本全量的以RDB方式写入aof文件,然后在将重写缓冲区的增量命令以AOF方式写入到文件,写入完成后通知主进程更新统计信息,并将新的含有RDB格式和AOF格式的AOF文件替换旧的的AOF文件。简单的说:新的AOF文件前半段是RDB格式的全量数据后半段是AOF格式的增量数据,如下图:
在Redis重启的时候,可以先加载rdb文件的内容,然后重放aof日志即可。
区别
区别 | rdb | aof |
持久化方式 | 生成某一时刻快照文件 | 实时记录写命令到日志 |
数据完整性 | 不完整,取决于备份周期 | 完整性相对较高,取决于刷盘机制 |
文件大小 | 二进制文件,相对较小 | 保存原始命令,文件较大 |
宕机恢复时间 | 快 | 慢 |
使用场景 | 宕机需要快速恢复,允许一定数量的数据丢失 | 对数据可靠性要求较高 |
相关推荐
- 【预警通报】关于WebLogic存在远程代码执行高危漏洞的预警通报
-
近日,Oracle官方发布了2021年1月关键补丁更新公告CPU(CriticalPatchUpdate),共修复了包括CVE-2021-2109(WeblogicServer远程代码执行漏洞)...
- 医院信息系统突发应急演练记录(医院信息化应急演练)
-
信息系统突发事件应急预案演练记录演练内容信息系统突发事件应急预案演练参与人员信息科参与科室:全院各部门日期xxxx-xx-xx时间20:00至24:00地点信息科记录:xxx1、...
- 一文掌握怎么利用Shell+Python实现完美版的多数据源备份程序
-
简介:在当今数字化时代,无论是企业还是个人,数据的安全性和业务的连续性都是至关重要的。数据一旦丢失,可能会造成无法估量的损失。因此,如何有效地对分布在不同位置的数据进行备份,尤其是异地备份,成为了一个...
- docker搭建系统环境(docker搭建centos)
-
Docker安装(CentOS7)1.卸载旧版Docker#检查已安装版本yumlistinstalled|grepdocker#卸载旧版本yumremove-ydocker.x...
- 基础篇:数据库 SQL 入门教程(sql数据库入门书籍推荐)
-
SQL介绍什么是SQLSQL指结构化查询语言,是用于访问和处理数据库的标准的计算机语言。它使我们有能力访问数据库,可与多种数据库程序协同工作,如MSAccess、DB2、Informix、M...
- Java21杀手级新特性!3行代码性能翻倍
-
导语某券商系统用这招,交易延迟从12ms降到0.8ms!本文揭秘Oracle官方未公开的Record模式匹配+虚拟线程深度优化+向量API神操作,代码量直降70%!一、Record模式匹配(代码量↓8...
- 一文读懂JDK21的虚拟线程(java虚拟线程)
-
概述JDK21已于2023年9月19日发布,作为Oracle标准Java实现的一个LTS版本发布,发布了15想新特性,其中虚拟线程呼声较高。虚拟线程是JDK21中引入的一项重要特性,它是一种轻量级的...
- 效率!MacOS下超级好用的Linux虚拟工具:Lima
-
对于MacOS用户来说,搭建Linux虚拟环境一直是件让人头疼的事。无论是VirtualBox还是商业的VMware,都显得过于笨重且配置复杂。今天,我们要介绍一个轻巧方便的纯命令行Linux虚拟工具...
- 所谓SaaS(所谓三维目标一般都应包括)
-
2010年前后,一个科技媒体的主编写一些关于云计算的概念性问题,就可以作为头版头条了。那时候的云计算,更多的还停留在一些概念性的问题上。而基于云计算而生的SaaS更是“养在深闺人未识”,一度成为被IT...
- ORA-00600 「25027」 「x」报错(报错0xc0000001)
-
问题现象:在用到LOB大对象的业务中,进行数据的插入,失败了,在报警文件中报错:ORA-00600:内部错误代码,参数:[25027],[10],[0],[],[],[],[],[...
- 安卓7源码编译(安卓源码编译环境lunch失败,uname命令找不到)
-
前面已经下载好源码了,接下来是下载手机对应的二进制驱动执行编译源码命令下载厂商驱动https://developers.google.com/android/drivers?hl=zh-cn搜索NGI...
- 编译安卓源码(编译安卓源码 电脑配置)
-
前面已经下载好源码了,接下来是下载手机对应的二进制驱动执行编译源码命令下载厂商驱动https://developers.google.com/android/drivers?hl=zh-cn搜索NGI...
- 360 Vulcan Team首战告捷 以17.5万美金强势领跑2019“天府杯“
-
2019年11月16日,由360集团、百度、腾讯、阿里巴巴、清华大学与中科院等多家企业和研究机构在成都联合主办了2019“天府杯”国际网络安全大赛暨2019天府国际网络安全高峰论坛。而开幕当日最激荡人...
- Syslog 日志分析与异常检测技巧(syslog发送日志配置)
-
系统日志包含有助于分析网络设备整体运行状况的重要信息。然而,理解并从中提取有效数据往往颇具挑战。本文将详解从基础命令行工具到专业日志管理软件的全流程分析技巧,助你高效挖掘Syslog日志价值。Gr...
- 从Oracle演进看数据库技术的发展(从oracle演进看数据库技术的发展的过程)
-
数据库技术发展本质上是应用需求驱动与基础架构演进的双向奔赴,如何分析其技术发展的脉络和方向?考虑到oracle数据库仍然是这个领域的王者,以其为例,管中窥豹,对其从Oracle8i到23ai版本的核...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- oracle位图索引 (74)
- oracle基目录 (50)
- oracle批量插入数据 (65)
- oracle事务隔离级别 (53)
- oracle主从同步 (55)
- oracle 乐观锁 (51)
- redis 命令 (78)
- php redis (88)
- redis 存储 (66)
- redis 锁 (69)
- 启动 redis (66)
- redis 时间 (56)
- redis 删除 (67)
- redis内存 (57)
- redis并发 (52)
- redis 主从 (69)
- redis 订阅 (51)
- redis 登录 (54)
- redis 面试 (58)
- 阿里 redis (59)
- redis 搭建 (53)
- redis的缓存 (55)
- lua redis (58)
- redis 连接池 (61)
- redis 限流 (51)