百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术教程 > 正文

坏了,Redis服崩了,内存中的数据该如何恢复?

mhr18 2024-10-24 11:15 21 浏览 0 评论

介绍

Redis中的数据存在内存中,如果突然宕机,那么内存中的数据将全部丢失。如果数据能从后端数据库恢复还好,如果数据只存在Redis中,那数据就全丢失了。并且如果请求量很多,MySQL服务器的压力会很大。

所以最好的方式是对数据进行持久化,并能当宕机的时候能快速恢复

在Redis中有如下两种持久化方式,rdb快照和aof日志

RDB

rdb就是对当前数据库的状态做一个快照,将某个阶段的数据通过二进制文件保存下来。你可以类比照相。内存中的数据越多,生成快照的时候就越长,同时将快照写入磁盘耗费的时间也越长。

这时我们不经要问,生成快照会阻塞主线程吗? 如果会阻塞主线程,则会影响正常请求的处理

在Redis中有两个命令可以用于生成RDB文件,一个是save,另一个是bgsave

  1. save:在主线程中执行,会导致阻塞
  2. 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快照,有会有如下两方面的问题

  1. 频繁的将全量数据写到磁盘,会给磁盘造成很大的压力
  2. 主线程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

持久化方式

生成某一时刻快照文件

实时记录写命令到日志

数据完整性

不完整,取决于备份周期

完整性相对较高,取决于刷盘机制

文件大小

二进制文件,相对较小

保存原始命令,文件较大

宕机恢复时间

使用场景

宕机需要快速恢复,允许一定数量的数据丢失

对数据可靠性要求较高

相关推荐

Redis合集-使用benchmark性能测试

采用开源Redis的redis-benchmark工具进行压测,它是Redis官方的性能测试工具,可以有效地测试Redis服务的性能。本次测试使用Redis官方最新的代码进行编译,详情请参见Redis...

Java简历总被已读不回?面试挂到怀疑人生?这几点你可能真没做好

最近看了几十份简历,发现大部分人不是技术差,而是不会“卖自己”——一、简历死穴:你写的不是经验,是岗位说明书!反面教材:ד使用SpringBoot开发项目”ד负责用户模块功能实现”救命写法:...

redission YYDS(redission官网)

每天分享一个架构知识Redission是一个基于Redis的分布式Java锁框架,它提供了各种锁实现,包括可重入锁、公平锁、读写锁等。使用Redission可以方便地实现分布式锁。red...

从数据库行锁到分布式事务:电商库存防超卖的九重劫难与破局之道

2023年6月18日我们维护的电商平台在零点刚过3秒就遭遇了严重事故。监控大屏显示某爆款手机SKU_IPHONE13_PRO_MAX在库存仅剩500台时,订单系统却产生了1200笔有效订单。事故复盘发...

SpringBoot系列——实战11:接口幂等性的形而上思...

欢迎关注、点赞、收藏。幂等性不仅是一种技术需求,更是数字文明对确定性追求的体现。在充满不确定性的网络世界中,它为我们建立起可依赖的存在秩序,这或许正是技术哲学最深刻的价值所在。幂等性的本质困境在支付系...

如何优化系统架构设计缓解流量压力提升并发性能?Java实战分享

如何优化系统架构设计缓解流量压力提升并发性能?Java实战分享在高流量场景下。首先,我需要回忆一下常见的优化策略,比如负载均衡、缓存、数据库优化、微服务拆分这些。不过,可能还需要考虑用户的具体情况,比...

Java面试题: 项目开发中的有哪些成长?该如何回答

在Java面试中,当被问到“项目中的成长点”时,面试官不仅想了解你的技术能力,更希望看到你的问题解决能力、学习迭代意识以及对项目的深度思考。以下是回答的策略和示例,帮助你清晰、有说服力地展示成长点:一...

互联网大厂后端必看!Spring Boot 如何实现高并发抢券逻辑?

你有没有遇到过这样的情况?在电商大促时,系统上线了抢券活动,结果活动刚一开始,服务器就不堪重负,出现超卖、系统崩溃等问题。又或者用户疯狂点击抢券按钮,最后却被告知无券可抢,体验极差。作为互联网大厂的后...

每日一题 |10W QPS高并发限流方案设计(含真实代码)

面试场景还原面试官:“如果系统要承载10WQPS的高并发流量,你会如何设计限流方案?”你:“(稳住,我要从限流算法到分布式架构全盘分析)…”一、为什么需要限流?核心矛盾:系统资源(CPU/内存/数据...

Java面试题:服务雪崩如何解决?90%人栽了

服务雪崩是指微服务架构中,由于某个服务出现故障,导致故障在服务之间不断传递和扩散,最终造成整个系统崩溃的现象。以下是一些解决服务雪崩问题的常见方法:限流限制请求速率:通过限流算法(如令牌桶算法、漏桶算...

面试题官:高并发经验有吗,并发量多少,如何回复?

一、有实际高并发经验(建议结构)直接量化"在XX项目中,系统日活用户约XX万,核心接口峰值QPS达到XX,TPS处理能力为XX/秒。通过压力测试验证过XX并发线程下的稳定性。"技术方案...

瞬时流量高并发“保命指南”:这样做系统稳如泰山,老板跪求加薪

“系统崩了,用户骂了,年终奖飞了!”——这是多少程序员在瞬时大流量下的真实噩梦?双11秒杀、春运抢票、直播带货……每秒百万请求的冲击,你的代码扛得住吗?2025年了,为什么你的系统一遇高并发就“躺平”...

其实很多Java工程师不是能力不够,是没找到展示自己的正确姿势。

其实很多Java工程师不是能力不够,是没找到展示自己的正确姿势。比如上周有个小伙伴找我,五年经验但简历全是'参与系统设计''优化接口性能'这种空话。我就问他:你做的秒杀...

PHP技能评测(php等级考试)

公司出了一些自我评测的PHP题目,现将题目和答案记录于此,以方便记忆。1.魔术函数有哪些,分别在什么时候调用?__construct(),类的构造函数__destruct(),类的析构函数__cal...

你的简历在HR眼里是青铜还是王者?

你的简历在HR眼里是青铜还是王者?兄弟,简历投了100份没反应?面试总在第三轮被刷?别急着怀疑人生,你可能只是踩了这些"隐形求职雷"。帮3630+程序员改简历+面试指导和处理空窗期时间...

取消回复欢迎 发表评论: