“特立独行是对的,融入圈子也是对的,重点是要想清楚自己向往怎样的生活,为此愿意付出怎样的代价。
”
我们通常将 Redis 作为缓存使用,提高读取响应性能,一旦 Redis 宕机,内存中的数据全部丢失,假如现在直接访问数据库大量流量打到 MySQL 可能会带来更加严重的问题。
另外慢慢的从数据库读取放到 Redis 性能必然比不过从 Redis 获取快,也会导致响应变慢。
Redis 为了实现无畏宕机快速恢复,设计了两大杀手锏,分别是 AOF(Append Only FIle)日志和 RDB 快照。
学习一个技术,通常只接触了零散的技术点,没有在脑海里建立一个完整的知识框架和架构体系,没有系统观。这样会很吃力,而且会出现一看好像自己会,过后就忘记,一脸懵逼。
跟着「黎哥」一起吃透 Redis,深层次的掌握 Redis 核心原理以及实战技巧。搭建一套完整的知识框架,学会全局观去整理整个知识体系。
本文硬核,建议收藏点赞,静下心来阅读,我相信都会有很多收获。
本篇将围绕如下几点展开:
涉及的知识点如图所示:
全景图可以围绕两个维度展开,分别是:
应用维度:缓存使用、集群运用、数据结构的巧妙使用
系统维度:可以归类为三高
Redis 系列篇章围绕如下思维导图展开,这次从 《Redis 日志篇:无畏宕机与快速恢复的杀手锏》一起探索 Redis 的高性能、持久化机制的秘密。
吃透Redis
拥有全景图,掌握系统观。
系统观其实是至关重要的,从某种程度上说,在解决问题时,拥有了系统观,就意味着你能有依据、有章法地定位和解决问题。
“65 哥:Redis 因为某些原因宕机了,会导致所有的流量会打到后端 MySQL,我立马重启 Redis,可是它的数据存在内存里面,重启后如何还是没有任何数据,如何防止重启数据丢失呢?
”
65 哥别急,「黎杜编程」带你一步步深入理解到底 Redis 宕机后如何快速恢复的。
Redis 数据存储在内存中,是否可以考虑将内存中的数据写到磁盘上呢?当 Redis 重启的时候就把保存在磁盘上的数据快速恢复到内存中,这样就能实现重启后正常提供服务了。
“65 哥:我想到一个方案,每次执行「写」操作操作内存的同时写入到磁盘
”
这个方案有一个致命问题:每次写指令不仅写内存还是写入磁盘,磁盘的性能相对内存太慢,会导致 Redis 性能大大降低。
“65 哥:那如何规避这个同时写入的问题呢?
”
我们通常将 Redis 当作缓存使用,所以即使 Redis 没有保存全部数据,还可以通过数据库获取,所以 Redis 不会保存所有的数据, Redis 的数据持久化使用了「RDB 数据快照」的方式来实现宕机快速恢复。
“65 哥:那什么是 RDB 内存快照呢?
”
在 Redis 执行「写」指令过程中,内存数据会一直变化。所谓的内存快照,指的就是 Redis 内存中的数据在某一刻的状态数据。
好比时间定格在某一刻,当我们拍照的,通过照片就能把某一刻的瞬间画面完全记录下来。
Redis 跟这个类似,就是把某一刻的数据以文件的形式拍下来,写到磁盘上。这个快照文件叫做 RDB 文件,RDB 就是 Redis DataBase 的缩写。
Redis 通过定时执行 RDB 内存快照,这样就不必每次执行「写」指令都写磁盘,只需要在执行内存快照的时候写磁盘。既保证了唯快不破,还实现了持久化,宕机快速恢复。
RDB内存快照
在做数据恢复时,直接将 RDB 文件读入内存完成恢复。
“65 哥:对哪些数据做快照呢?或者多久做一次快照呢?这个会影响快照的执行效率。
”
65 哥不错呀,开始考虑数据效率问题了。在《Redis 核心篇:唯快不破的秘密》中我们知道他的单线程模型决定了我们要尽可能的避免会阻塞主线程的操作,避免 RDB 文件生成阻塞主线程。
Redis 提供了两个指令用于生成 RDB 文件:
fork
产生一个子进程用于写入 RDB 文件,快照持久化完全交给子进程来处理,父进程继续处理客户端请求,生成 RDB 文件的默认配置。“65 哥:那在对内存数据做「快照」的时候,内存数据还能修改么?也就是写指令能否正常处理?
”
首先我们要明确一点,避免阻塞和 RDB 文件生成期间能处理写操作不是一回事。虽然主线程没有阻塞,到那时为了保证快照的数据的一致性,只能处理读操作,不能修改正在执行快照的数据。
很明显,为了生成 RDB 而暂停写操作,Redis 是不答应的。
“65 哥:那 Redis 如何实现一边处理写请求,同时生成 RDB 文件呢?
”
Redis 使用操作系统的多进程写时复制技术 COW(Copy On Write) 来实现快照持久化,这个机制很有意思,也很少人知道。多进程 COW 也是鉴定程序员知识广度的一个重要指标。
Redis 在持久化时会调用 glibc 的函数fork
产生一个子进程,快照持久化完全交给子进程来处理,父进程继续处理客户端请求。
子进程刚刚产生时,它和父进程共享内存里面的代码段和数据段。这时你可以将父子进程想像成一个连体婴儿,共享身体。
这是 Linux 操作系统的机制,为了节约内存资源,所以尽可能让它们共享起来。在进程分离的一瞬间,内存的增长几乎没有明显变化。
bgsave
子进程可以共享主线程的所有内存数据,读取主线程的数据并写入到 RDB 文件。
在执行 SAVE
命令或者BGSAVE
命令创建一个新的 RDB 文件时,程序会对数据库中的键进行检查,已过期的键不会被保存到新创建的 RDB 文件中。
当主线程执行写指令修改数据的时候,这个数据就会复制一份副本, bgsave
子进程读取这个副本数据写到 RDB 文件,所以主线程就可以直接修改原来的数据。
写时复制技术保证快照期间数据客修改
这既保证了快照的完整性,也允许主线程同时对数据进行修改,避免了对正常业务的影响。
Redis 会使用 bgsave 对当前内存中的所有数据做快照,这个操作是子进程在后台完成的,这就允许主线程同时可以修改数据。
“65 哥:那可以每秒都执行 RDB 文件么,这样即使发生宕机最多丢失 1 秒的数据。
”
过于频繁的执行全量数据快照,有两个严重性能开销:
优缺点
快照的恢复速度快,但是生成 RDB 文件频率不好把握,频率过低宕机丢失的数据就会比较多;太快,又会消耗额外开销。
RDB 采用二进制 + 数据压缩的方式写磁盘,文件体积小,数据恢复速度快。
Redis 除了 RDB 全量快照以外,还设计了 AOF 写后日志,接下来我们一起来聊下什么是 AOF 日志。
AOF 日志存储的是 Redis 服务器的顺序指令序列,AOF 日志只记录对内存进行修改的指令记录。
假设 AOF 日志记录了自 Redis 实例创建以来所有的修改性指令序列,那么就可以通过对一个空的 Redis 实例顺序执行所有的指令,也就是「重放」,来恢复 Redis 当前实例的内存数据结构的状态。
写前日志(Write Ahead Log, WAL): 在实际写数据之前,将修改的数据写到日志文件中,故障恢复得以保证。
比如 MySQL Innodb 存储引擎 中的 redo log(重做日志)便是记录修改的数据日志,在实际修改数据前先记录修改日志在执行修改数据。
写后日志: 先执行「写」指令请求,将数据写入内存,再记录日志。
AOF写后指令
当 Redis 接受到 「set key MageByte」命令将数据写到内存后,Redis 会按照如下格式写入 AOF 文件。
AOF 日志格式
“65 哥:为什么 Redis 使用写后日志这种方式呢?
”
写后日志避免了额外的检查开销,不需要对执行的命令进行语法检查。如果使用写前日志的话,就需要先检查语法是否有误,否则日志记录了错误的命令,在使用日志恢复的时候就会出错。
另外,写后才记录日志,不会阻塞当前的「写」指令执行。
“65 哥:那有了 AOF 就万无一失了么?
”
傻孩子,可没这么简单。假如 Redis 刚执行完指令,还没记录日志宕机了,就有可能丢失这个命令相关的数据。
还有,AOF 避免了当前命令的阻塞,但是可能会给下一个命令带来阻塞的风险。AOF 日志是主线程执行,将日志写入磁盘过程中,如果磁盘压力大就会导致写磁盘很慢,导致后续的「写」指令阻塞。
发现了没,这两个问题与磁盘写回有关,如果能合理的控制「写」指令执行完后 AOF 日志写回磁盘的时机,问题就迎刃而解。
为了提高文件的写入效率,当用户调用 write
函数,将一些数据写入到文件的时候,操作系统通常会将写入数据暂时保存在一个内存缓冲区里面,等到缓冲区的空间被填满、或者超过了指定的时限之后,才真正地将缓冲区中的数据写入到磁盘里面。
这种做法虽然提高了效率,但也为写入数据带来了安全问题,因为如果计算机发生停机,那么保存在内存缓冲区里面的写入数据将会丢失。
为此,系统提供了fsync
和fdatasync
两个同步函数,它们可以强制让操作系统立即将缓冲区中的数据写入到硬盘里面,从而确保写入数据的安全性。
Redis 提供的 AOF 配置项appendfsync
写回策略直接决定 AOF 持久化功能的效率和安全性。
aof_buf
缓冲区中的内容刷写到 AOF 文件。没有两全其美的策略,我们需要在性能和可靠性上做一个取舍。
always
同步写回可以做到数据不丢失,但是每个「写」指令都需要写入磁盘,性能最差。
everysec
每秒写回,避免了同步写回的性能开销,发生宕机可能有一秒位写入磁盘的数据丢失,在性能和可靠性之间做了折中。
no
操作系统控制,执行写指令后就写入 AOF 文件缓冲就可以执行后续的「写」指令,性能最好,但是有可能丢失很多的数据。
“65 哥:那我该如何选择策略呢?
”
我们可以根据系统对高性能和高可靠性的要求,来选择写回策略。总结一下:想要获得高性能,就选择 No 策略;如果想要得到高可靠性保证,就选择 Always 策略;如果允许数据有一点丢失,又希望性能别受太大影响的话,那么就选择 Everysec 策略。
优点:执行成功才记录日志,避免了指令语法检查开销。同时,不会阻塞当前「写」指令。
缺点:由于 AOF 记录的是一个个指令内容,具体格式请看上面的日志格式。故障恢复的时候需要执行每一个指令,如果日志文件太大,整个恢复过程就会非常缓慢。
另外文件系统对文件大小也有限制,不能保存过大文件,文件变大,追加效率也会变低。
“65 哥:AOF 日志文件过大着怎么办?
”
AOF 写前日志,记录的是每个「写」指令操作。不会像 RDB 全量快照导致性能损耗,但是执行速度没有 RDB 快,同时日志文件过大也会造成性能问题,对于唯快不破的 Redis 这个真男人来说,绝对不能忍受日志过大导致的问题。
所以,Redis 设计了一个杀手锏「AOF 重写机制」,Redis 提供了 bgrewriteaof
指令用于对 AOF 日志进行瘦身。
其原理就是开辟一个子进程对内存进行遍历转换成一系列 Redis 的操作指令,序列化到一个新的 AOF 日志文件中。序列化完毕后再将操作期间发生的增量 AOF 日志追加到这个新的 AOF 日志文件中,追加完毕后就立即替代旧的 AOF 日志文件了,瘦身工作就完成了。
“65 哥:为啥 AOF 重写机制能缩小日志文件呢?
”
重写机制有「多变一」功能,将旧日志中的多条指令,在重写后就变成了一条指令。
如下所示:
AOF重写机制(纠错:重写前记录了 3 条指令)
“65 哥:重写后 AOF 日志变小,最后把整个数据库最新数据的操作日志刷写到磁盘了。重写会不会阻塞主线程呢?
”
「码哥」上文说了,AOF 日志是主线程写回的,AOF 重写的过程实际上后台子进程 bgrewriteaof 完成,防止阻塞主线程。
重写过程
和 AOF 日志由主线程写回不同,重写过程是由后台子进程 bgrewriteaof 来完成的,这也是为了避免阻塞主线程,导致数据库性能下降。
总的来说,一共出现 两个日志,一次拷内存数据拷贝,分别是旧的 AOF 日志和新的 AOF 重写日志和 Redis 数据拷贝。
Redis 会将重写过程中的接收到的「写」指令操作同时记录到旧的 AOF 缓冲区和 AOF 重写缓冲区,这样重写日志也保存最新的操作。等到拷贝数据的所有操作记录重写完成后,重写缓冲区记录的最新操作也会写到新的 AOF 文件中。
每次 AOF 重写时,Redis 会先执行一个内存拷贝,用于遍历数据生成重写记录;使用两个日志保证在重写过程中,新写入的数据不会丢失,并且保持数据一致性。
AOF 重写过程
“65 哥:AOF 重写也有一个重写日志,为什么它不共享使用 AOF 本身的日志呢?
”
这个问题问得好,有以下两个原因:
重启 Redis 时,我们很少使用 rdb 来恢复内存状态,因为会丢失大量数据。我们通常使用 AOF 日志重放,但是重放 AOF 日志性能相对 rdb 来说要慢很多,这样在 Redis 实例很大的情况下,启动需要花费很长的时间。
Redis 4.0 为了解决这个问题,带来了一个新的持久化选项——混合持久化。将 rdb 文件的内容和增量的 AOF 日志文件存在一起。这里的 AOF 日志不再是全量的日志,而是自持久化开始到持久化结束的这段时间发生的增量 AOF 日志,通常这部分 AOF 日志很小。
于是在 Redis 重启的时候,可以先加载 rdb 的内容,然后再重放增量 AOF 日志就可以完全替代之前的 AOF 全量文件重放,重启效率因此大幅得到提升。
所以 RDB 内存快照以稍微慢一点的频率执行,在两次 RDB 快照期间使用 AOF 日志记录期间发生的所有「写」操作。
这样快照就不用频繁的执行,同时由于 AOF 只需要记录两次快照之间发生的「写」指令,不需要记录所有的操作,避免出现文件过大的情况。
Redis 设计了 bgsave 和写时复制,尽可能避免执行快照期间对读写指令的影响,频繁快照会给磁盘带来压力以及 fork 阻塞主线程。
Redis 设计了两大杀手锏实现了宕机快速恢复,数据不丢失。
避免日志过大,提供了 AOF 重写机制,根据数据库的数据最新状态,生成数据的写操作作为新日志,并且通过后台完成不阻塞主线程。
综合 AOF 和 RDB 在 Redis 4.0 提供了新的持久化策略,混合日志模型。在 Redis 重启的时候,可以先加载 rdb 的内容,然后再重放增量 AOF 日志就可以完全替代之前的 AOF 全量文件重放,重启效率因此大幅得到提升。
最后,关于 AOF 和 RDB 的选择问题,「码 哥 字 节」有三点建议:
本文由哈喽比特于3年以前收录,如有侵权请联系我们。
文章来源:https://mp.weixin.qq.com/s/-91t4jx743OQgul1IDRa7w
京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。
日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。
据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。
今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。
日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。
近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。
据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。
9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...
9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。
据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。
特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。
据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。
近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。
据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。
9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。
《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。
近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。
社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”
2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。
罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。