Redis 的大 Key 对持久性有何影响?
目录
- 大 Key 对 AOF 日志的影响
- 大 Key 对 AOF 重写和 RDB 的影响
- 总结
Redis 的持久化方式有两种:AOF 日志
和 RDB 快照
。
所以接下来,针对这两种持久化方式具体分析分析。
大 Key 对 AOF 日志的影响
先说说 AOF 日志三种写回磁盘的策略
Redis 提供了 3 种 AOF 日志写回硬盘的策略,分别是:
- Always,这个单词的意思是「总是」,所以它的意思是
每次写操作命令执行完后,同步将 AOF 日志数据写回硬盘
; - Everysec,这个单词的意思是「每秒」,所以它的意思是
每次写操作命令执行完后,先将命令写入到 AOF 文件的内核缓冲区,然后每隔一秒将缓冲区里的内容写回到硬盘
; - No,意味着不由 Redis 控制写回硬盘的时机,转交给操作系统控制写回的时机,也就是每次写操作命令执行完后,
先将命令写入到 AOF 文件的内核缓冲区,再由操作系统决定何时将缓冲区内容写回硬盘
。
这三种策略只是在控制 fsync()
函数的调用时机。
当应用程序向文件写入数据时,内核通常先将数据复制到内核缓冲区中,然后排入队列,然后由内核决定何时写入硬盘。
如果想要应用程序向文件写入数据后,能立马将数据同步到硬盘,就可以调用 fsync() 函数,这样内核就会将内核缓冲区的数据直接写入到硬盘,等到硬盘写操作完成后,该函数才会返回。
- Always 策略就是每次写入 AOF 文件数据后,就执行 fsync() 函数;
- Everysec 策略就会创建一个异步任务来执行 fsync() 函数;
- No 策略就是永不执行 fsync() 函数;
分别说说这三种策略,在持久化大 Key 的时候,会影响什么?
在使用 Always 策略的时候,主线程在执行完命令后,会把数据写入到 AOF 日志文件,然后会调用fsync()
函数,将内核缓冲区的数据直接写入到硬盘,等到硬盘写操作完成后,该函数才会返回。
当使用 Always 策略的时候,如果写入是一个大 Key,主线程在执行 fsync() 函数的时候,阻塞的时间会比较久,因为当写入的数据量很大的时候,数据同步到硬盘这个过程是很耗时的。
当使用 Everysec 策略的时候,由于是异步执行 fsync() 函数,所以大 Key 持久化的过程(数据同步磁盘)不会影响主线程。
当使用 No 策略的时候,由于永不执行 fsync() 函数,所以大 Key 持久化的过程不会影响主线程。
大 Key 对 AOF 重写和 RDB 的影响
当 AOF 日志写入了很多的大 Key,AOF 日志文件的大小会很大,那么很快就会触发 AOF 重写机制
。
AOF 重写机制和 RDB 快照(bgsave
命令)的过程,都会分别通过fork()
函数创建一个子进程来处理任务。
在创建子进程的过程中,操作系统会把父进程的「页表」复制一份给子进程,这个页表记录着虚拟地址和物理地址映射关系,而不会复制物理内存,也就是说,两者的虚拟空间不同,但其对应的物理空间是同一个。
这样一来,子进程就共享了父进程的物理内存数据了,这样能够节约物理内存资源,页表对应的页表项的属性会标记该物理内存的权限为只读。
随着 Redis 存在越来越多的大 Key,那么 Redis 就会占用很多内存,对应的页表就会越大。
在通过 fork()
函数创建子进程的时候,虽然不会复制父进程的物理内存,但是内核会把父进程的页表复制一份给子进程,如果页表很大,那么这个复制过程是会很耗时的,那么在执行 fork 函数的时候就会发生阻塞现象。
而且,fork 函数是由 Redis 主线程调用的,如果 fork 函数发生阻塞,那么意味着就会阻塞 Redis 主线程。由于 Redis 执行命令是在主线程处理的,所以当 Redis 主线程发生阻塞,就无法处理后续客户端发来的命令。
我们可以执行info
命令获取到 latest_fork_usec
指标,表示 Redis 最近一次 fork 操作耗时。
# 最近一次 fork 操作耗时
latest_fork_usec:315
如果 fork 耗时很大,比如超过1秒,则需要做出优化调整:
- 单个实例的内存占用控制在 10 GB 以下,这样 fork 函数就能很快返回。
- 如果 Redis 只是当作纯缓存使用,不关心 Redis 数据安全性问题,可以考虑关闭 AOF 和 AOF 重写,这样就不会调用 fork 函数了。
- 在主从架构中,要适当调大 repl-backlog-size,避免因为 repl_backlog_buffer 不够大,导致主节点频繁地使用全量同步的方式,全量同步的时候,是会创建 RDB 文件的,也就是会调用 fork 函数。
那什么时候会发生物理内存的复制呢?
当父进程或者子进程在向共享内存发起写操作时,CPU 就会触发缺页中断,这个缺页中断是由于违反权限导致的,然后操作系统会在「缺页异常处理函数」里进行物理内存的复制,并重新设置其内存映射关系,将父子进程的内存读写权限设置为可读写,最后才会对内存进行写操作,这个过程被称为「写时复制(Copy On Write)」。
写时复制顾名思义,在发生写操作的时候,操作系统才会去复制物理内存,这样是为了防止 fork 创建子进程时,由于物理内存数据的复制时间过长而导致父进程长时间阻塞的问题。
如果创建完子进程后,父进程对共享内存中的大 Key 进行了修改,那么内核就会发生写时复制,会把物理内存复制一份,由于大 Key 占用的物理内存是比较大的,那么在复制物理内存这一过程中,也是比较耗时的,于是父进程(主线程)就会发生阻塞。
所以,有两个阶段会导致阻塞父进程:
- 创建子进程的途中,由于要复制父进程的页表等数据结构,阻塞的时间跟页表的大小有关,页表越大,阻塞的时间也越长;
- 创建完子进程后,如果子进程或者父进程修改了共享数据,就会发生写时复制,这期间会拷贝物理内存,如果内存越大,自然阻塞的时间也越长;
这里额外提一下, 如果 Linux 开启了内存大页,会影响 Redis 的性能的。
Linux 内核从 2.6.38 开始支持内存大页机制,该机制支持 2MB 大小的内存页分配,而常规的内存页分配是按 4KB 的粒度来执行的。
如果采用了内存大页,那么即使客户端请求只修改 100B 的数据,在发生写时复制后,Redis 也需要拷贝 2MB 的大页。相反,如果是常规内存页机制,只用拷贝 4KB。
两者相比,你可以看到,每次写命令引起的复制内存页单位放大了 512 倍,会拖慢写操作的执行时间,最终导致 Redis 性能变慢。
那该怎么办呢?很简单,关闭内存大页(默认是关闭的)。
禁用方法如下:
echo never > /sys/kernel/mm/transparent_hugepage/enabled
总结
当 AOF 写回策略配置了 Always 策略,如果写入是一个大 Key,主线程在执行 fsync()
函数的时候,阻塞的时间会比较久,因为当写入的数据量很大的时候,数据同步到硬盘这个过程是很耗时的。
AOF 重写机制和 RDB 快照(bgsave 命令)的过程,都会分别通过 fork()
函数创建一个子进程来处理任务。会有两个阶段会导致阻塞父进程(主线程):
- 创建子进程的途中,由于要复制父进程的页表等数据结构,阻塞的时间跟页表的大小有关,页表越大,阻塞的时间也越长;
- 创建完子进程后,如果父进程修改了共享数据中的大 Key,就会发生写时复制,这期间会拷贝物理内存,由于大 Key 占用的物理内存会很大,那么在复制物理内存这一过程,就会比较耗时,所以有可能会阻塞父进程。
大 key 除了会影响持久化之外,还会有以下的影响。
-
客户端超时阻塞。由于 Redis 执行命令是单线程处理,然后在操作大 key 时会比较耗时,那么就会阻塞 Redis,从客户端这一视角看,就是很久很久都没有响应。
-
引发网络阻塞。每次获取大 key 产生的网络流量较大,如果一个 key 的大小是 1 MB,每秒访问量为 1000,那么每秒会产生 1000MB 的流量,这对于普通千兆网卡的服务器来说是灾难性的。
-
阻塞工作线程。如果使用 del 删除大 key 时,会阻塞工作线程,这样就没办法处理后续的命令。
-
内存分布不均。集群模型在 slot 分片均匀情况下,会出现数据和查询倾斜情况,部分有大 key 的 Redis 节点占用内存多,QPS 也会比较大。
如何避免大 Key 呢?
最好在设计阶段,就把大 key 拆分成一个一个小 key。或者,定时检查 Redis 是否存在大 key ,如果该大 key 是可以删除的,不要使用 DEL 命令删除,因为该命令删除过程会阻塞主线程,而是用 unlink 命令(Redis 4.0+)删除大 key,因为该命令的删除过程是异步的,不会阻塞主线程。
下一篇: 库存(采购、销售、库存、会计)流程摘要
推荐阅读
-
Redis 的大 Key 对持久性有何影响?
-
不同的靶材料(铜、铬、钴、钼、铁靶)对 XRD 光谱有何影响?
-
大咖说·禾连健康|“云原生”的应用对企业有什么样的影响
-
页脚、页面内容与导航中的链接对SEO有何影响?
-
当我们还在谈“性”变色时,这群高中生拍了一部“小黄片”-sex的英剧在国内悄悄的火了,光是小肯关注的公号里,就发现已经不下十个公号写过这部网剧了。 这是一部由英美合拍的小众网剧,被称为校园版的《X爱大师》,它还有一个很直白的剧名《性爱自修室》。 没错,这是一部从标题就能看出“有点黄”的剧,当然,剧中的大尺度戏份也并不少。 比如第一集开始就出现的大尺度画面,让人非常措手不及了。 但就是这样一部从标题到剧情都很sex的剧,在国内掀起了一股不小的热潮,豆瓣评分高达9.1分,基本上看过这部剧的人都给了好评。 当然,如果这是一部只是在写“性爱”这么肤浅的剧的话,在豆瓣上是绝对达不到这样的高分。其实,《性爱自修室》又名《性教育》,是围绕青少年“性”问题展开的喜剧。 在剧中,你可能会意外的发现,这群高中生在青春期遇到的性问题,尴尬,不被理解的压抑,以及爱的问题,都是那么的真实。 这部剧到底拍的有多好呢? 不少网友在看完这部剧后,提到最多的一句话便是:“这哪里是我们的青春,这是我们羡慕的青春!” 在国内传统思想的影响下,“性教育”一直是我们缺失很久的一门课。 还记得,小时候与父母一起看电视每当看到有亲热戏的部分,父母都会第一时间跳转到另一个频道,而自己也不好意思的移开视线,这大概是和父母最默契的时刻。 在国外,许多孩子的性知识大多来自于父母或者老师。对比国内的小孩,大概许多人对“性”的了解,都来自于某部电影或者小说,而这部分没有父母的参与。 在《性爱自修室》中,男主奥帝斯是名高中生,和众多普通学生一样,在校园里很不显眼,也不被关注。普通的奥帝斯最特殊的地方大概是,他的妈妈是一名性治疗师。 每个小孩大概都问过父母同样的一个问题“我是怎么来的?” 大人都想着小孩子什么都不懂,所以随便找个理由忽悠一下就行,很少有父母愿意真正的向他们的孩子解释“你到底是怎么来到这个世界上的。” 而答案天花乱坠又刚刚好错过最正确的那个,我们听到最多的那个答案大概就是:“你是上天赐给我们的礼物。” 更别说告诉自己的孩子“什么是性爱?” 在剧中,奥帝斯就有这样的经历,大概在他六七岁的时候,他目睹了父亲的出轨,懵懂的他问母亲珍“什么是性”。作为性爱治疗室的珍,用极具学术性的语言为他解决了这个问题:性的意思就是,男性的生殖器官进入女性的生殖器官。
-
未曾有因缘经-尔时波斯匿王。国大夫人。出入行来。常使四人。名扇提罗(扇提罗者汉言石女无男女根故名石女)。最大筋力。令此四人。担皇后舆。皇后所乘。七宝辇舆。留在祇洹精舍门外。敕诸黄门。令守护之。黄门转令四扇提罗。守夫人舆。其身自往佛边听法。扇提罗等。各于舆下。睡眠不识。时有凶人。偷取夫人珍宝辇舆一摩尼珠。尔时黄门。暂出看舆。不见宝珠。心中惶怖。惧夫人责。问石女言。使汝守舆。何故偷珠各各答言。实不偷也。黄门大怒。鞭打石女。苦痛彻骨。时有一石女。自审不偷横受楚毒。奔走逃突入精舍中。称怨大唤众皆闻之莫知所由。 波斯匿王和皇后出宫的时候经常用四名力气很大的石女抬轿。皇后所乘的轿子有七宝装饰。这一次被留在世尊精舍的门外,让太监看守。太监就转命四名石女守着轿子,自己跟随听佛讲法。这四名石女睡着了,有人偷了轿于上的一颗摩尼宝珠,她们也不失道。这时太监不放心,出来察看。发现轿子上的宝珠没有了,心中十分害怕皇后斥责,便问石女说:让你们看护轿于,你们怎么监守自盗偷宝珠呢?这些石女都说:不是她们偷的。太监发了脾气,用鞭子抽打石女,痛彻骨隋。其中有一名石女觉得自己没有偷窃宝珠而被鞭打,便逃入世尊讲法精舍,大声喊冤。大家听了都不知道发生了什么事情。 佛语阿难。汝可出往彼黄门所。无令横鞭无过之人。何以故。此四石女者。乃是皇后前世之师。自无过罪。何以横鞭。自造后世恶业因缘。是时皇后。闻佛此语。即起恭敬。合掌白佛。如世尊说。四担舆石女。乃是皇后前世时师。迷意不解。惟愿世尊。说其因缘。令诸会众普得闻知。佛告皇后。唤石女来。于世尊前。验其虚实。皇后奉命。即遣黄门。摄之将来。时四石女。见佛叩头啼哭。长跪合掌。白世尊曰。实不偷珠。有何因缘。横罗此罪。鞭打楚痛。身体破坏。世尊告言。罪业因缘。自身所造。非父母为。非从天堕。人行善恶。受苦乐报。如响应声。贪现前利。心行邪谄。不知后世累劫受殃。夫恶从心生。反以自贼。如铁生垢。消毁其形。王叉手白佛。前后说法。皆有因缘。令四石女。先世本业有何因缘愿佛为说。开悟盲冥多所利益。众人蒙祐。 佛对阿难说:你去到太监那里让他不要鞭打没有过错的人,这四名石女是皇后前生的老师,没有犯什么错,为什么要鞭打她们呢?这会造作后世的恶业因缘。皇后听到佛说这话,于是恭敬起立,合掌问佛:世尊所说这四名抬轿石女是我前世的老师,我十分迷惑,请您说说其中因缘由来,让大家都能明了知晓。佛告诉皇后:你召唤石女进来,在我面前可以验证虚实。皇后就命令太监把四名石女传来。四名石女见佛后,叩头啼哭,顶礼世尊说:实在不是我们偷了宝珠,因为什么缘故而遭此痛苦,鞭打加身呢?世尊说道:罪业的因缘是自己所造,并不是父母所为,更不是从天而降。人们造作善恶之事,就会有苦乐报应,就如同喊话回声一样如影随形。为了贪得现前的利益而做奸邪欺骗的事情,却不知后世多生多劫会遭受苦报。恶从心生,却是自己的敌人,如同铁器生锈,腐蚀其形。波斯匿王向佛致礼问道:世间的事情都有前后因缘,这四名石女前生有什么因缘请佛说一说,开导我们这些无知之人,利益大众。 佛告王曰。欲闻者善。着心谛听。吾今说之。佛复惟曰。今我法中。有诸比丘。言行不同。心口相违。或为利养钱财饮食。或为名誉要集眷属。或有厌恶。王法役使出家为道。都无有心向三脱门。度三有苦。以不净心。贪受信施。不知后世。弥劫受殃。偿其宿债。为是等故。岂得不说。