草庐IT

java - Docker内存限制导致SLUB无法使用大页面缓存进行分配

coder 2023-05-06 原文

给定一个通过mmap文件创建大型Linux内核页面缓存的进程,在具有内存限制的docker容器(cgroup)中运行会导致内核slab分配错误:

Jul 18 21:29:01 ip-10-10-17-135 kernel: [186998.252395] SLUB: Unable to allocate memory on node -1 (gfp=0x2080020)
Jul 18 21:29:01 ip-10-10-17-135 kernel: [186998.252402]   cache: kmalloc-2048(2412:6c2c4ef2026a77599d279450517cb061545fa963ff9faab731daab2a1f672915), object size: 2048, buffer size: 2048, default order: 3, min order: 0
Jul 18 21:29:01 ip-10-10-17-135 kernel: [186998.252407]   node 0: slabs: 135, objs: 1950, free: 64
Jul 18 21:29:01 ip-10-10-17-135 kernel: [186998.252409]   node 1: slabs: 130, objs: 1716, free: 0

观看slabtop,我可以看到在以内存限制开头的容器中,buffer_head,radix_tree_node和kmalloc *对象的数量受到严格限制。这似乎会对应用程序中的IO吞吐量产生病理影响,并且可以通过iostat观察到。即使页面缓存消耗了在容器外部运行的主机OS上的所有可用内存或没有内存限制的容器,也不会发生这种情况。

这似乎是内核内存记帐中的一个问题,其中不将内核页面高速缓存计入容器内存,而是将其支持的SLAB对象计入容器内存。该行为似乎是异常的,因为在预先分配了大的平板对象池时运行,内存受限的容器运行良好,可以自由地重用现有的平板空间。只有在容器中分配的平板才计入容器。内存和内核内存容器选项的组合似乎无法解决此问题(除非根本不设置内存限制,或者不设置太大的限制而不限制平板,但这会限制可寻址空间)。我试图通过在引导时传递cgroup.memory=nokmem来完全禁用kmem计费,但没有成功。

系统信息:
  • Linux ip-10-10-17-135 4.4.0-1087-aws#98-Ubuntu SMP
  • AMI ubuntu/images/hvm-ssd/ubuntu-xenial-16.04-amd64-server-20190204.3
  • Docker 18.09.3版,内部版本774a1f4
  • java 10.0.1 2018-04-17

  • 要重现该问题,可以使用我的PageCache Java代码。这是embedded database library的基本示例,它在很大程度上利用了内存映射文件来部署在非常快速的文件系统上。该应用程序通过ECS部署在AWS i3.baremetal实例上。我正在将主机上的大容量映射到存储内存映射文件的Docker容器。 AWS ECS代理要求为所有容器设置非零内存限制。内存限制会导致病理性平板行为,并且由此产生的应用程序IO吞吐量完全 Not Acceptable 。

    使用drop_caches在运行之间对echo 3 > /proc/sys/vm/drop_caches很有帮助。这将清除页面缓存和关联的平板对象池。

    欢迎提供有关如何修复,解决该问题或什至在哪里报告此问题的建议。

    更新
    看来使用4.15内核更新到Ubuntu 18.04确实可以解决观察到的kmalloc分配错误。 Java的版本似乎无关紧要。这似乎是因为每个v1 CGroup只能分配不超过内存限制的页面高速缓存(对于多个cgroup,通过Shared Page Accounting方案仅“收费”一个cgroup会更复杂)。我相信现在这与预期的行为一致。在4.4内核中,我们发现观察到的kmalloc错误是在内存限制和非常大的页面缓存的v1 Cgroup中使用软件raid0的交叉。我相信4.4内核中的cgroup可以映射无限数量的页面(我们发现该错误非常有用),直到内核为关联的slab对象耗尽内存为止,但是我仍然没有吸烟的原因。

    在4.15内核中,要求我们的Docker容器设置内存限制(通过AWS ECS),因此我们实现了一项任务,一旦在/sys/fs/cgroup/memory/docker/{contarainer_id}/memory.limit_in_bytes中创建了容器,便取消设置内存限制。尽管确实不是一个好习惯,但这似乎可行。这允许我们想要的行为-在主机上无限共享页面缓存资源。由于我们正在运行具有固定堆的JVM应用程序,因此降低了下行风险。

    对于我们的用例,完全可以为cgroup减少页面缓存(mmap的磁盘空间)和关联的slab对象的选择,而为docker进程保留堆和堆栈的限制,这将是很棒的选择。当前的“共享页面计费”方案很难推论,我们宁愿允许LRU页面缓存(和关联的SLAB资源)使用主机内存的全部范围,就像根本没有设置内存限制的情况一样。

    我已经开始关注LWN上的一些对话,但是我有点茫然。也许这是一个可怕的主意?我不知道。欢迎提供有关如何进行下一步操作的建议。

    最佳答案

    java 10.0.1 2018-04-17



    您应该尝试使用Java 10的最新版本(或11或...)

    我在去年五月(2019)的“Docker support in Java 8 — finally!”中提到,Java 10向后移植到Java 8中的Java 10的新改进意味着Docker将更准确地报告所使用的内存。

    article from may 2018报告:

    Succes! Without providing any flags Java 10 (10u46 -- Nightly) correctly detected Dockers memory limits.



    OP Davidthe comments中进行确认:

    The docker - jvm integration is a big improvement in Java 10.
    It is really to do with setting sane XMS and the number of processors. These now respect the docker container limits rather than picking up the host instance values (you can turn this feature off using -XX:-UseContainerSupport depending on your use case).

    I have not found it helpful in dealing with the page cache though.
    The best solution I have found is to disable the docker memory limit, after the container is created if need be.
    This is definitely a hack - user beware.

    关于java - Docker内存限制导致SLUB无法使用大页面缓存进行分配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57103486/

    有关java - Docker内存限制导致SLUB无法使用大页面缓存进行分配的更多相关文章

    1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

      我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

    2. ruby - 使用 RubyZip 生成 ZIP 文件时设置压缩级别 - 2

      我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看ruby​​zip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d

    3. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

      类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

    4. ruby-on-rails - 使用 Ruby on Rails 进行自动化测试 - 最佳实践 - 2

      很好奇,就使用ruby​​onrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提

    5. ruby - 在 Ruby 中使用匿名模块 - 2

      假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于

    6. ruby-on-rails - Ruby net/ldap 模块中的内存泄漏 - 2

      作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代

    7. ruby - 使用 ruby​​ 和 savon 的 SOAP 服务 - 2

      我正在尝试使用ruby​​和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我

    8. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

      关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

    9. ruby-on-rails - 由于 "wkhtmltopdf",PDFKIT 显然无法正常工作 - 2

      我在从html页面生成PDF时遇到问题。我正在使用PDFkit。在安装它的过程中,我注意到我需要wkhtmltopdf。所以我也安装了它。我做了PDFkit的文档所说的一切......现在我在尝试加载PDF时遇到了这个错误。这里是错误:commandfailed:"/usr/local/bin/wkhtmltopdf""--margin-right""0.75in""--page-size""Letter""--margin-top""0.75in""--margin-bottom""0.75in""--encoding""UTF-8""--margin-left""0.75in""-

    10. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

      我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

    随机推荐