0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

谷歌在内存方面依赖于per memcg lru lock

Linux阅码场 来源:Linuxer 作者:Linuxer 2021-01-15 14:00 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

自电子计算机诞生以来,内存性能一直是行业关心的重点。内存也随着摩尔定律,在大小和速度上一直增长。现在的阿里云服务器动辄单机接近TB的内存大小,加上数以百记的CPU数量也着实考验操作系统的资源管理能力。

作为世间最流行的操作系统Linux, 内核使用LRU, Last Recent Used 链表来管理全部用户使用的内存,用一组链表串联起一个个的内存页,并且使用lru lock来保护链表的完整性。

b3ca29b4-56f1-11eb-8b86-12bb97331649.png

所有应用程序常用操作都会涉及到LRU链表操作,例如,新分配一个页,需要挂在inactive lru 链上, 2次访问同一个文件地址, 会导致这个页从inactive 链表升级到active 链表, 如果内存紧张, 页需要从active 链表降级到inactive 链表, 内存有压力时,页被回收导致被从inactive lru链表移除。不单大量的用户内存使用创建,回收关系到这个链表, 内核在内存大页拆分,页移动,memcg 移动,swapin/swapout, 都要把页移进移出lru 链表。

可以简单计算一下x86服务器上的链表大小:x86最常用的是4k内存页, 4GB 内存会分成1M个页, 如果按常用服务器256GB页来算, 会有超过6千万个页挂在内核lru 链表中。超大超长的内存链表和频繁的lru 操作造成了2个著名的内核内存锁竞争, zone lock, 和 lru lock. 这2个问题也多次在阿里内部造成麻烦, 系统很忙, 但是业务应用并没得到多少cpu时间, 大部分cpu都花在sys上了。一个简单2次读文件的benchmark可以显示这个问题, 它可以造成70%的cpu时间花费在LRU lock上。

作为一个知名内核性能瓶颈, 社区也多次尝试以各种方法解决这个问题, 例如,使用更多的 LRU list, 或者LRU contention 探测。

但是都因为各种原因被linux 内核拒绝。

寻找解决方案

通过仔细的观察发现, 内核在2008年引进内存组-memcg以来, 系统单一的lru lists已经分成了每个内存组一个lru list, 由每个内存组单独管理自己的lru lists。那么按道理lru lock的contention应该有所减小啊?为什么还是经常在内部服务器观察到lru lock hot引起的sys 高?

原来, 内核在引入per memcg lru lists后,并没有使用per memcg lru lock, 还在使用旧的全局lru lock 来管理全部memcg lru lists. 这造成了本来可以自治的memcg A, 却要等待memcg B 释放使用的lru lock。然后A拿起的lru lock又造成 memcg C的等待。。。

那么把全局lru lock拆分到每一个memcg中, 不是可以理所当然的享受到了memcg独立的好处了吗?这样每个memcg 都不会需要等待其他memcg 释放lru lock。锁竞争限制在每个memcg 内部了。

b426b940-56f1-11eb-8b86-12bb97331649.png

要完成lru lock 拆分,首先要知道lru lock 保护了多少对象, 通常情况中, page lru lock需要保护lru list完整性, 这个是必须的。与lru list相关的还有page flags中的lru bit,这个lru bit用作页是否在lru list存在的指示器, 可以避免查表才能知道页是否在list中。那么lru lock保护它也说的通。

但是lru lock 看起来还有一些奇怪的保护对象,承担了一些不属于它的任务:

1.PageMlock bit,保护 munlock_vma 和split_huge_page 冲突,

其实, 上述2个函数在调用链中都需要 page lock, 所以冲突可以完全由page lock来保证互斥。这里lru lock使用属于多余。

2.pagecache xa_lock和memcg->move_lock,

xa_lock并没有需要lru lock保护的场景,这个保护也是多余。相反,lru lock放到xa_lock 之下, 符合xa_lock/lock_page_memcg, 的使用次序。反而可以优化 lru lock 和 memcg move_lock的关系。

3.lru bit in page_idle_get_page, 用在这里是因为担心 page_set_anon_rmap中, mapping 被提前预取访问,造成异常。用memory barrier 方式可以避免这个预取, 所以可以在page idle中撤掉lru lock.

+ WRITE_ONCE(page->mapping, (struct address_space *) anon_vma);

经过这样的修改, lru lock 可以在memory lock 调用层次中降级到最底层。

b46d8b40-56f1-11eb-8b86-12bb97331649.png

这时, lru lock已经非常简化,可以用per memcg lru lock来替换全局的lru lock了吗?还不行,使用per memcg lru lock 有一个根本问题,使用者要保证 page所属的memcg不变,但是页在生命周期中是可能转换memcg的,比如页在memcg之间migration,导致 lru_lock随着memcg变化, 拿到的lru lock是错误的,好消息是memcg 变化也需要先拿到lru lock锁,这样我们可以获得lru lock之后检查这个是不是正确的锁:

b4a700dc-56f1-11eb-8b86-12bb97331649.png

如果不是, 由反复的relock 来保证锁的正确性。bingo! 完美解决!

由此, 这个feature曲折的upstream 之路开始了。。。

最终解决

这个patchset 2019年发出到社区之后, google的 Hugh Dickins 提出, 他和facebook的Konstantin Khlebnikov 同学已经在2011发布了非常类似的patchset,当时没有进主线。不过google内部生产环境中一直在使用。所以现在Hugh Dickins发出来他的upstream版本。关键路径和我的版本是一样的

2个相似patchset的PK, 引起了memcg 维护者Johannes 的注意, Johannes发现在compaction的时候, relock并不能保护某些特定场景:

b55f3e36-56f1-11eb-8b86-12bb97331649.png

所以他建议,也许增加原子的lru bit操作作为 lru_lock 的前提也许可以保护这个场景。Hugh Dickins 则不认为这样会有效,并且坚持他patchset已经在google内部用了9年了。一直安全稳定。。。

Johannes的建议的本质是使用lru bit代替lru lock做page isolation互斥,但是问题的难点在其他地方, 比如在通常的一个swap in 的场景中:

b5bc905e-56f1-11eb-8b86-12bb97331649.png

swap in 的页是先加入lru, 然后charge to memcg, 这样造成页在加入lru 时,并不知道自己会在那个memcg上, 我们也拿不到正确的per memcg lru_lock, 所以上面场景中左侧CPU 即使提前检查PageLRU 也找不到正确的lru lock 来阻止右面cpu的操作, 然并卵。

正确的解决方案, 就是上面第9步移动到第7步前面, 在加入lru前charge to memcg. 并且在取得lru lock之前检查lru bit是否存在, 这样才可以保证我们可以拿到的是正确的memcg 的lru lock。由此提前清除/检查lru bit的方法才会有效。这个memcg charge的上升, 在和Johannes讨论后, Johannes在5.8 完成了代码实现并且和入主线。

在新的代码基础上, 增加了lru bit的原子操作TestClearPageLRU, 把lru bit移出了lru lock的保护,相反用这个bit来做page isolation的互斥条件, 用isolation来保护页在memcg间的移动, 让lru lock只完成它的最基本任务, 保护lru list完整性。至此方案主体完成。lru lock的保护对象也由6个减小到一个。编码实现就很容易了。

b61bc128-56f1-11eb-8b86-12bb97331649.png

测试结果

方案完成后, 上面提到的file readtwice 测试中,多个memcg的情况下,lru lock 竞争造成的sys 从70% 下降了一半,throughput 提高到260%。(80个cpu的神龙机器)

b652d294-56f1-11eb-8b86-12bb97331649.png

Upstream过程

经过漫长4轮的逐行review, 目前这个feature 已经进入了 linus的 5.11 https://github.com/torvalds/linux

第一版patch 发到了社区后, google的skakeel butt立刻提出, google曾经在2011发过一样的patchset来解决 per memcg lru lock 问题。所以,skakeel 要求我们停止自己开发, 基于google的版本来解决这个问题。然后我才发现真的2011年 google Hugh Dickins 和 Facebook Konstantin Khlebnikov 就大约同时提出类似的patchset。, 但是当时引起的关注比较少,也缺乏benchmark来展示补丁的效果, 所以很快被社区遗忘了。不过google内部则一直在维护这组补丁,随他们内核版本升级。

对比google的补丁, 我们的实现共同点都是使用relock来确保page->memcg线性化, 其他实现细节则不尽相同。测试表明我们的patch性能更好一点。于是我基于自己的补丁继续修改并和Johannes讨论方案改进。这也导致了以后每一版都有google同学的反对:我们的测试发现你的patchset 有bug, 请参考google可以工作的版本。并在linux-next上发现一个小bug时达到顶峰:https://lkml.org/lkml/2020/3/6/627 google同学批评我们抄他们的补丁还抄出一堆bug.

b6a804d0-56f1-11eb-8b86-12bb97331649.png

其实这些补丁和Hugh Dickins的补丁毫无关联, 并且在和Johannes的持续讨论中,解决方案的核心:page->memcg的线性化已经进化了几个版本了, 从relock 到 lock_page_memcg, 再到TestClearPageLRU. 和google的补丁是路线上的不同。

面对这样的无端指责,memcg 维护者 Johannes 看不下去, 出来说了一些公道话:我和Alex同学都在尝试和你不同的方案来解决上次提出的compacion冲突问题,而且我记得你当时是觉得这个冲突你无能为力的:

b7422466-56f1-11eb-8b86-12bb97331649.png

之后google同学分享了他们的测试程序,然后在这个话题上沉默了一段时间。

后来memcg charge的问题解决后, 就可以用lru bit来保证page->memcg互斥了。v17 coding很快完成后。intel 的Alexander Duyck, 花了5个星期, 逐行逐字的review整个patchset, 并其基于补丁的改进, 提出了一些后续优化补丁。5个星期的review, 足以让一个feature 错过合适的内核upstream 窗口。但是也增强了社区的信心。

(重大内核的feature 的merge窗口是这样的:大的feature 在进入linus tree之前, 要在linux-next tree 待一段时间, 主要的社区测试如Intel LKP, google syzbot 等等也会在着重测试Linux-next。所以为了保证足够的测试时间, 进入下个版本重要feature 必须在当前版本的rc4之前进入linux-next。而当前版本-rc1通常bug比较多, 所以最佳rebase 版本是 rc2, 错过最佳merge 窗口 rc2-rc4. 意味着需要在等2个月到下一个窗口。并且还要适应新的内核版本的相关修改。)

基于5.9-rc2的 v18 版本完成后, google hugh dickins同学强势归来,主动申请测试和review,根据他的意见v18 做了很多删减和合并,甚至推翻了一些Alexander Duyck要求的修改。patch 数量从32个压缩到20个。Hugh Dickin 逐行review 了整整4个星期。也完美错过了5.10和入窗口。之后v19, Johannes 同学终于回来开始review. Johannes比较快,一个星期就完成了review。现在v20, 几乎每个patch 都有了2个reviewed-by: Hugh/Johannes.

然而, 这次不像以前, 以前 patchset 没有人关心, 这次大家的review兴趣很大,来了就停不住, SUSE的 Vlastimil Babka 同学又过来开始review, 并且提出了一些coding style 和代码解释要求。不过被强势的Hugh Dickins 驳回:

b781fed8-56f1-11eb-8b86-12bb97331649.png

Hugh 的影响力还是很大的, Vlastimil 和其他潜在的reivewer都闭上了嘴。代码终于进了基于5.10-rc 的 linux-next。不过这个驳回也引起一个在5.11提交窗口的麻烦, memory总维护者 Andrew Morthon突然发现Vlastimil Babka 表示过一些异议。所以他问我:是不是舆论还不一致, 还有曾经推给你一个bug, 你解决了吗?

I assume the consensus on this series is 'not yet"?

Hugh再次出来护场:我现在觉得patchset 足够好了, 足够多人review过足够多的版本了, 已经在linux-next 安全运行一个多月了,没有任何功能和性能回退, Vlastimil也已经没有意见了。至于那个bug, Alex有足够的证据表明和这个补丁无关。。。

b7cd8df8-56f1-11eb-8b86-12bb97331649.png

最终这个patchset享受到了Andrew 向 Linus单独推送的待遇。进了5.11。

后记

在 Linux 上游做事情,有很多成就感,也可以保证自己需要的feature,一直在线, 免去了内核升级维护之苦。但也会面临荆棘和险阻, 各种内部不关心的场景都要照顾到, 不能影响其他任何人的feature。所以相比coding, 大量的社区讨论大概是coding的3~5倍时间,主要是反复的代码解释和修改.

在整个upstreaming的过程中特别值得一提的是一些google的同学态度转变, 从一开始的反对,到最后加入我们。从google方面来说, google在内存方面有很多优化都依赖于per memcg lru lock. 这个代码加入内核也解除了他们9年来的代码维护痛苦。

原文标题:memcg lru lock 血泪史

文章出处:【微信公众号:Linuxer】欢迎添加关注!文章转载请注明出处。

责任编辑:haq

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • Linux
    +关注

    关注

    88

    文章

    11628

    浏览量

    217982
  • 操作系统
    +关注

    关注

    37

    文章

    7329

    浏览量

    128639

原文标题:memcg lru lock 血泪史

文章出处:【微信号:LinuxDev,微信公众号:Linux阅码场】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    Molex Mini-Lock SMT接头技术解析与应用指南

    Molex Mini-Lock SMT插头具有直角和垂直两种选项,提供2至15个位置。这些插头与外壳配合使用,外壳具有终端位置保证 (TPA) 功能,确保端子完全嵌入外壳,并具有耐电弧功能
    的头像 发表于 11-20 15:03 183次阅读

    为什么单片机中很少使用malloc,而PC程序频繁使用呢?

    对程序的影响。 操作系统的支持单片机:在许多单片机应用中,程序运行不依赖于复杂的操作系统,而是基于裸机或轻量级实时操作系统(RTOS)来进行管理。裸机系统往往没有内存管理单元(MMU)和动态内存分配
    发表于 11-20 06:55

    请问OTA是否一定依赖于ymodem协议?

    缺少什么步骤,通过对比发送的固件内容(日志打印)与“downloader”内容一致。 3,现在的需求是通过串口2,接收上位机发送过来的固件包更新。不依赖于ymodem等任何协议。不知这种想法是否成立。
    发表于 09-17 08:25

    澜起科技凭借在内存接口和高速互连芯片领域的突破性创新荣膺《财富》中国科技50强

    近日,《财富》杂志正式发布“中国科技50强”榜单,澜 起科技凭借在内存接口和高速互连芯片领域的突破性创新与全球影响力成功入选,成为中国半导体行业中技术实力与国际化发展兼备的杰出代表企业之一。 据悉
    的头像 发表于 08-25 10:03 2229次阅读
    澜起科技凭借<b class='flag-5'>在内存</b>接口和高速互连芯片领域的突破性创新荣膺《财富》中国科技50强

    一次消谐器核心功能依赖于其非线性电阻材料

    一次消谐器在电力系统中发挥着至关重要的作用,今天我们来看看它的主要构成材料: 1. 核心材料:非线性电阻的“灵魂” 一次消谐器的核心功能依赖于其非线性电阻材料,主要分为两类:碳化硅(SiC)基:早期
    的头像 发表于 08-02 06:20 732次阅读
    一次消谐器核心功能<b class='flag-5'>依赖于</b>其非线性电阻材料

    集装箱智能识别系统主要依赖哪些技术?

    现代集装箱智能识别系统是港口自动化、智慧物流和电子口岸建设的关键基础设施,其高效运转依赖于多项前沿技术的综合应用。以下是这类系统的核心技术组成: 一、智能视觉感知技术 系统采用高分辨率工业相机阵列
    的头像 发表于 07-16 11:22 457次阅读
    集装箱智能识别系统主要<b class='flag-5'>依赖</b>哪些技术?

    【创龙TL3562-MiniEVM开发板试用体验】Grove移植9之LCD

    关键修改 1 i2c通信依赖于以下几个库 pip install smbus2 apt-get install i2c-tools apt-get install python3-smbus
    发表于 07-10 21:28

    摆脱依赖英伟达!OpenAI首次转向使用谷歌芯片

    电子发烧友网报道(文/李弯弯)近日,据知情人士透露,OpenAI近期已开始租用谷歌的张量处理单元(TPU),为旗下ChatGPT等热门产品提供算力支持。这一举措不仅标志着OpenAI首次实质性
    的头像 发表于 07-02 00:59 7995次阅读

    时间的力量:RTC如何赋能万物精准运行?

    这些我们习以为常的“准时”与“精确”,背后都依赖于电子设备的“时序基准源”——实时时钟(Real-Time Clock, RTC)。
    的头像 发表于 05-28 17:21 674次阅读
    时间的力量:RTC如何赋能万物精准运行?

    Altera Agilex 5 D系列FPGA的性能和能效

    随着边缘计算领域的迅速发展,许多应用日益依赖于内存技术来实现更高的性能或每瓦性能。Altera 的 Agilex 5 D 系列 FPGA 可提供一系列经过精心设计的内存选择,助力用户轻松采用先进的
    的头像 发表于 03-27 13:36 1126次阅读

    云服务器需要网络吗?怎么设置

    需要。云服务器的运行依赖于网络连接,以确保用户能够通过互联网远程访问和管理服务器资源。网络设置是云服务器配置过程中的重要环节,它涉及到IP地址分配、子网配置、网关设置、DNS解析以及网络安全等多个方面
    的头像 发表于 02-21 10:25 805次阅读

    稳定性建设之依赖设计

    作者:京东物流 冯志文 背景 随着分布式微服务的发展,一个普通的应用可能会依赖于许多其他服务,这给系统的限流降级、优化改造等操作带来了困难。在没有明确强弱依赖关系的情况下,我们很难有效地进行这些操作
    的头像 发表于 02-21 09:49 698次阅读
    稳定性建设之<b class='flag-5'>依赖</b>设计

    可控硅的控制奥秘:依赖直流还是交流?

    可控硅是一种重要的半导体器件,通过控制极的触发信号实现对电流的控制。它可以在直流和交流电路中应用,分别用于开关、调节、调光等功能。直流控制和交流控制的特点和应用场景有所不同,但都依赖于精确的触发电路设计。通过合理设计控制电路和保护电路,可以充分发挥可控硅的性能,实现对电路的精确控制。
    的头像 发表于 01-10 15:44 3029次阅读
    可控硅的控制奥秘:<b class='flag-5'>依赖</b>直流还是交流?

    RAID 5 硬件与软件 RAID 的区别

    RAID 5硬件RAID与软件RAID之间存在显著的差异,这些差异主要体现在实现方式、性能、数据安全性、灵活性以及成本等方面。 一、实现方式 硬件RAID : 依赖于专用的硬件RAID控制器来管理
    的头像 发表于 12-27 18:05 1855次阅读

    虚拟设计与优化电力电子系统依赖于半导体芯片模型

    方法,该方法结合了静态和动态表征技术以及参数拟合,从而能够创建高度精确的模型。电力电子技术几乎存在于现代生活的各个方面,从消费电子到可再生能源集成和交通。这些系统
    的头像 发表于 12-10 11:57 840次阅读
    虚拟设计与优化电力电子系统<b class='flag-5'>依赖于</b>半导体芯片模型