西拉免费代理IP

你当前的位置:西拉免费代理IP   >   新闻中心   >   如履薄冰:Redis 懒惰删除的巨大牺牲

如履薄冰:Redis 懒惰删除的巨大牺牲

来源: 西拉IP   作者: 张祁无   2018年12月13日 15:04

如履薄冰:Redis 懒惰删除的巨大牺牲

大家都知道 Redis 是单线程的,但是 Redis 4.0 增加了懒惰删除功能,懒惰删除需要使用异步线程对已删除的节点进行内存回收,这意味着 Redis 底层其实并不是单线程,它内部还有几个额外的鲜为人知的辅助线程。

这几个辅助线程在 Redis 内部有一个特别的名称,就是“BIO”,全称是 Background IO,意思是在背后默默干活的 IO 线程。

不过内存回收本身并不是什么 IO 操作,只是 CPU 的计算消耗可能会比较大而已。

懒惰删除的最初实现不是异步线程


Redis 大佬 Antirez 实现懒惰删除时,它并不是一开始就想到了异步线程。它最初的尝试是在主线程里,使用类似于字典渐进式搬迁的方式来实现渐进式删除回收。

比如对于一个非常大的字典来说,懒惰删除是采用类似于 scan 操作的方法,通过遍历第一维数组来逐步删除回收第二维链表的内容,等到所有链表都回收完了,再一次性回收第一维数组。这样也可以达到删除大对象时不阻塞主线程的效果。

但是说起来容易做起来却很难。渐进式回收需要仔细控制回收频率,它不能回收得太猛,这会导致 CPU 资源占用过多,也不能回收得像蜗牛那么慢,因为内存回收不及时可能导致内存消耗持续增长。

Antirez 需要采用合适的自适应算法来控制回收频率。他首先想到的是通过检测内存增长的趋势是增长“+1”还是下降“-1”,来渐进式调整回收频率系数,这样的自适应算法实现也很简单。

但是测试后发现在服务繁忙的时候,QPS 会下降到正常情况下 65% 的水平,这点非常致命。

所以 Antirez 才使用了如今的方案——异步线程。异步线程这套方案就简单多了,释放内存不用为每种数据结构适配一套渐进式释放策略,也不用搞个自适应算法来仔细控制回收频率,只是将对象从全局字典中摘掉,然后往队列里一扔,主线程就干别的去了。异步线程从队列里取出对象来,直接走正常的同步释放逻辑就可以了。

不过使用异步线程也是有代价的,主线程和异步线程之间在内存回收器(jemalloc)的使用上存在竞争。

这点竞争消耗是可以忽略不计的,因为 Redis 的主线程在内存的分配与回收上花的时间相对整体运算时间而言是极少的。

异步线程方案其实也相当复杂


上文笔者刚说异步线程方案很简单,为什么在这里又说它很复杂呢?因为有一点,笔者之前没有提到,这点非常可怕,严重阻碍了异步线程方案的改造,那就是 Redis 的内部对象有共享机制。

比如集合的并集操作 sunionstore 用来将多个集合合并成一个新集合。

如履薄冰:Redis 懒惰删除的巨大牺牲

我们看到新的集合包含了旧集合的所有元素。但是这里有一个我们没看到的 trick,那就是底层的字符串对象被共享了,如下图所示。

如履薄冰:Redis 懒惰删除的巨大牺牲

为什么对象共享是懒惰删除的巨大障碍呢?因为懒惰删除相当于彻底砍掉某个树枝,将它扔到异步删除队列里去。

注意这里必须是彻底删除,不能藕断丝连。如果底层对象是共享的,那就做不到彻底删除。如图 2 所示的删除就不是彻底删除。

如履薄冰:Redis 懒惰删除的巨大牺牲

所以 Antirez 为了支持懒惰删除,将对象共享机制彻底抛弃,它将这种对象结构称为“share-nothing”,也就是无共享设计。

但是甩掉对象共享谈何容易!这种对象共享机制散落在源代码的各个角落,牵一发而动全身,改起来犹如在布满地雷的道路上小心翼翼地行走。

不过 Antirez 还是决心改了,它将这种改动描述为“绝望而疯狂”,可见改动之大、之深、之险,前后花了好几周时间才改完。

不过这次修改的效果也是很明显的,对象的删除操作再也不会导致主线程卡顿了。

异步删除的实现


主线程需要将删除任务传递给异步线程,它是通过一个普通的双向链表来传递的。因为链表需要支持多线程并发操作,所以它需要有锁来保护。

执行懒惰删除时,Redis 将删除操作的相关参数封装成一个 bio_job 结构,然后追加到链表尾部。异步线程通过遍历链表摘取 job 元素来挨个执行异步任务。

如履薄冰:Redis 懒惰删除的巨大牺牲

我们注意到这个 job 结构有三个参数。为什么删除对象需要三个参数呢?我们看如下代码。

如履薄冰:Redis 懒惰删除的巨大牺牲

可以看到,通过组合这三个参数可以实现不同结构的释放逻辑。

接下来我们继续追踪普通对象的异步删除 lazyfreeFreeObjectFromBioThread 是如何进行的,请仔细阅读代码注释。

如履薄冰:Redis 懒惰删除的巨大牺牲

如履薄冰:Redis 懒惰删除的巨大牺牲

这些代码散落在多个不同的文件,我将它们凑到了一块便于读者阅读。从代码中我们可以看到释放一个对象要深度调用一系列函数,每种对象都有它独特的内存回收逻辑。

5.9.4 队列安全


前面提到任务队列是一个不安全的双向链表,需要使用锁来保护它。当主线程将任务追加到队列之前需要给它加锁,追加完毕后,再释放锁,还需要唤醒异步线程——如果其在休眠的话。

如履薄冰:Redis 懒惰删除的巨大牺牲

异步线程需要对任务队列进行轮询处理,依次从链表表头摘取元素逐个处理。摘取元素的时候也需要加锁,摘出来之后再解锁。如果一个元素都没有,它需要等待,直到主线程来唤醒它继续工作。

如履薄冰:Redis 懒惰删除的巨大牺牲

研究完这些加锁解锁的代码后,笔者开始有点担心主线程的性能。我们都知道加锁解锁是一个相对比较耗时的操作,尤其是悲观锁最为耗时。如果删除很频繁,主线程岂不是要频繁加锁解锁。

所以这里肯定还有优化空间,Java 的 ConcurrentLinkQueue 就没有使用这样粗粒度的悲观锁,它优先使用 cas 来控制并发。那就让我们就期待 Redis 在未来的版本里对它进一步改造优化吧!

阅读 431   

相关推荐

Adaptive Server Enterprise(ASE)

Adaptive Server Enterprise(ASE)是关系数据库管理系统(RDBMS),可在Linux和其他基于Unix的操作系统,Windows NT和Windows 2000以及Ma . . .

2018年12月14日
一道微软面试题 一道微软面试题
一道微软面试题

面试题目是这样子的: 两个单词如果包含相同的字母,次序不同,则称为字母易位词(anagram)。例如,“silent”和“listen”是字母易位词,而“apple”和“ap . . .

2018年12月14日
webshell你不知道的那些事 webshell你不知道的那些事
webshell你不知道的那些事

1.利用md5绕过waf的一句话 本体: 本质 利用方式 MD5("3fion0hj596569 . . .

2018年12月14日
设计模式之简单工厂模式 设计模式之简单工厂模式
设计模式之简单工厂模式

工厂,顾名思义,能够生产产品的一个地方。产品,在面向对象中,就是类的实例。所以,“工厂”就是一个能够产生其它类型的对象的类。工厂类设计模式主要有三种,即简单工厂模式,工厂模式,抽象工厂模式三种 . . .

2018年12月13日
谷歌搜索重返中国按下暂停键,CEO 皮查伊“对决”美国国会 谷歌搜索重返中国按下暂停键,CEO 皮查伊“对决”美国国会
谷歌搜索重返中国按下暂停键,CEO 皮查伊“对决”美国国会

在经历了今年 “Project Maven”项目和“蜻蜓”计划的道德滑坡的声讨过后,Google 公司仍旧“流年不顺”。 先是 Google Cloud 的三位女 . . .

2018年12月13日
45K!刚面完 AI 岗,这几点分享给你! 45K!刚面完 AI 岗,这几点分享给你!
45K!刚面完 AI 岗,这几点分享给你!

互联网虽然寒冬,但人工智能热度不减,成果不断。今年所有的互联网公司,都在ALL in AI。百度、腾讯、阿里巴巴、京东等互联网巨头甚至都在美国硅谷大肆高薪挖掘人工智能人才。 . . .

2018年12月13日
一个中年“码农”的困局 一个中年“码农”的困局
一个中年“码农”的困局

01 杨俊是一个70后,个头中等,略微发福,戴着一副厚如啤酒瓶底的眼镜,眼神犀利,一看就是个精明人。 杨俊年轻时就读于国内一所211院校的计算机系,写得一手好代 . . .

2018年12月13日
什么是高速缓存代理? 什么是高速缓存代理?
什么是高速缓存代理?

高速缓存代理是一种Internet /网络高速缓存技术 ,它使 代理服务器 能够保存最近和频繁的网站/网页请求以及一台或多台客户机请求的数据。 . . .

2018年12月12日
什么是分叉代理服务器?

分叉 代理服务器 是一种在各种不同的用户位置或S IP地址 之间分发SIP请求的服务器。它支持在不同SIP位置/端点之间分支或分支SIP . . .

2018年12月12日
什么是文件传输协议(FTP) 什么是文件传输协议(FTP)
什么是文件传输协议(FTP)

文件传输协议(FTP)是一种客户端/服务器协议, 用于将文件传输到主机或与主机交换文件。它可以使用用户名和密码进行身份验证。匿名FTP允许用户从Internet访问文件,程序和其 . . .

2018年12月12日

新闻中心 代理分享 | 蜘蛛地图

全网最大的免费网页代理ip平台,提供大量免费http代理服务器免费ip代理地址

© 2016 - 2021. 西拉免费代理ip, All rights reserved. 鄂ICP备18017015号-4

在线客服