https://blog.openresty.com.cn/cn/ngx-cycle-pool-frag/?src=org_news
章亦春发布于 Feb 14, 2023更新于 Mar 2, 2023

预计阅读 6 分钟
阅读次数
 

我们最近使用 OpenResty XRay 帮助一个销售 CDN 和流量网关服务的企业客户优化了他们的 OpenResty/Nginx 服务器的内存使用。这个客户在他们的 OpenResty/Nginx 配置文件中定义了许多虚拟服务器和 URI location。OpenResty XRay 在客户的生产环境中自动进行了大部分分析,基于分析结果给出的方案让 nginx 进程的内存占用减少了大约 30%。

和我们的 OpenResty Edge 的 nginx worker 进程相比显示, 进一步的优化将会继续减少约 90%。

OpenResty XRay 是一个动态追踪产品,它可以自动分析正在运行中的应用程序,以排除性能问题、行为问题和安全漏洞,并提供可行的建议。在底层实现上,OpenResty XRay 由我们的 Y 语言驱动,可以在不同环境下支持多种不同的运行时,如 Stap+, eBPF+, GDB 和 ODB。

挑战

这个 CDN 供应商使用一个超大的“nginx.conf”配置文件来为他们的 OpenResty 服务器中的近万个虚拟主机服务。每个 nginx 主进程在启动后占用了好几个 G 的内存,在一次或多次 HUP reload 后,内存几乎翻倍。从下面 OpenResty XRay 生成的图中可以看出,最大内存占用约为 4.60GB。

我们可以从 OpenResty XRay 的应用层面内存使用明细表中看到,Glibc 分配器占用了大部分常驻内存,有 4.55GB。

而 OpenResty XRay 发现 Nginx cycle pool 占用了大量的内存:

当 Nginx 加载配置文件时,我们都知道它为这个 cycle pool 内的配置数据分配了数据结构。虽然庞大到有 1.62GB,但远远小于上面提到的 4.60GB。

RAM 依然是昂贵和稀缺的硬件资源,特别是在 AWS 和 GCP 这样的公有云上。客户希望通过降级到内存较小的机器来节约成本。

分析

OpenResty XRay 对客户的在线进程进行了深入分析。它不需要客户的应用程序进行任何协作。

  • 没有额外的插件、模块或库。
  • 没有代码注入或补丁。
  • 没有特殊的编译或启动选项。
  • 甚至不需要重新启动应用程序进程。

分析完全是以“事后”的方式进行的。多亏了 Openresty XRay 采用的动态追踪技术。

太多的空闲区块

OpenResty XRay 用 Glibc 内存分配器的分析器自动对在线 nginx 进程进行采样。分析器生成了以下柱状图,显示了分配器管理的空闲块的大小是如何分布的。

Glibc 分配器通常不会立即释放空闲块给操作系统(OS)。它可能会保留一些空闲块,以加快后续的分配速度。但有意保留的通常很小,不可能到上 G 字节。这里我们看到空闲块的大小累计已经达到 2.3GB。因此,更常见的原因是内存碎片。

查看普通堆中的内存碎片问题

大多数小的内存分配通过 brk Linux 系统调用,发生在“普通堆”中。这个堆就像一个线性的 “堆“,只能通过移动其”顶部"指针来增加或减少。在堆中间的所有空闲块不能被释放给操作系统。直到它们上面的所有块也变成空闲,它们才会被释放。

OpenResty XRay 的内存分析器可以帮助我们查看这种堆的状态。请看下面的堆图,它是在 nginx 主进程响应 HUP 信号加载新配置后的采样图。

我们可以看到,堆是向上增长的,也就是说,向高位内存地址增长。注意 brk top 指针,这是唯一可以移动的东西。绿色框属于 Nginx 的新 “cycle pool“,而粉色框属于旧 ”cycle pool”。一个有趣的现象是,Nginx 会保留旧的 cycle pool 或旧的配置数据,直到新的 cycle pool 被成功加载。这种行为是由于 Nginx 的保护机制,当新的配置加载失败时,会优雅地退回到旧的配置。不幸的是,正如我们在上面看到的,旧的配置数据的盒子(绿色)在新的数据(粉色)下面,因此只有当新的配置数据也被释放后,它们才能释放到操作系统。

事实上,在 Nginx 释放了旧的配置数据和旧的 cycle pool 后,它们原来的位置变成了空闲块,被卡在新的 cycle pool 的块下面。

这是一个教科书式的内存碎片化的例子。普通堆只能在顶部释放内存;因此,它比其他内存分配机制,如 mmap 系统调用,更容易受到内存碎片的影响。但是,mmap 会在这里拯救我们吗?不一定。

mmap 的世界

Glibc 分配器也可以通过 mmap 系统调用来分配内存。这些系统调用分配离散的内存块或内存段,这些内存块或内存段可能位于进程地址空间的几乎任何地址,并跨越任何数量的内存页。

这听起来是一个缓解上述内存碎片问题的好方法。但是当我们有意阻断普通堆的增长方式时,根据 OpenResty XRay 的分析器所产生的图表,类似程度的内存碎片仍然发生。

当应用程序(这里是 Nginx)请求分配较小内存块的时候,Glibc 倾向于分配相对较大的内存段,这里是 1MB。因此,内存碎片仍然会发生在这些 1MB 的 mmap 段内。如果一个小内存块仍在使用,那么整个内存段就不会被释放给操作系统。

在上图中,我们可以看到旧的 cycle pool 块(粉红色)和新的 cycle pool 块(绿色)仍然在许多 mmap 段中交错。

解决方案

我们为客户提出了几个解决方案。

简单方式

最简单的方式是直接解决内存碎片的问题。根据上面我们使用 OpenResty XRay 做的分析,我们应该做以下一个或多个变动。

  1. 避免在“普通堆”中分配 cycle pool 内存(即取消这种分配的 brk 系统调用)。
  2. 要求 Glibc 使用适当的 mmap 段内存大小(不要太大!)来满足 cycle pool 的内存分配请求。
  3. 将不同 cycle pool 的内存块干净地分离到不同的 mmap 段中。

我们为 OpenResty XRay 的付费客户提供详细的优化说明。因此根本就不需要编码。

更好的方式

是的,还有一个更好的方式。开源的 OpenResty 软件提供了 Lua APIs 和 Nginx 配置指令,以动态加载(和卸载)Lua 层面的新的配置数据,而不需要通过 Nginx 配置文件机制。这使得使用一个小的恒定大小的内存来处理更多的虚拟 server 和 location 的配置数据成为可能。同时,Nginx 服务器的启动和重新加载时间也大大缩短(从很多秒到几乎为零)。事实上,有了动态配置加载,HUP reload 操作本身变得非常罕见。这种方式的一个缺点是,这需要在我们用户侧进行一些额外的 Lua 编码。

我们的 OpenResty Edge 软件产品以 OpenResty 作者所设想的最佳方式实现了这种动态配置加载和卸载。它不需要用户进行任何编码。所以这也是一个容易的选项。

结果

这位客户决定先尝试简单的方式,结果在几次 HUP reload 后,总的内存占用减少了 30%。

仍然有一些剩余的片段值得进一步关注。但我们的客户已经很满意了。此外,上面提到的更好的方式可以节省超过 90% 的总内存占用(就像在我们的 OpenResty Edge 产品中一样):

关于作者

章亦春是开源 OpenResty 项目创始人兼 OpenResty Inc. 公司 CEO 和创始人。

章亦春(Github ID: agentzh),生于中国江苏,现定居美国湾区。他是中国早期开源技术和文化的倡导者和领军人物,曾供职于多家国际知名的高科技企业,如 Cloudflare、雅虎、阿里巴巴, 是 “边缘计算“、”动态追踪 “和 “机器编程 “的先驱,拥有超过 22 年的编程及 16 年的开源经验。作为拥有超过 4000 万全球域名用户的开源项目的领导者。他基于其 OpenResty 开源项目打造的高科技企业 OpenResty Inc. 位于美国硅谷中心。其主打的两个产品 OpenResty XRay(利用动态追踪技术的非侵入式的故障剖析和排除工具)和 OpenResty Edge(最适合微服务和分布式流量的全能型网关软件),广受全球众多上市及大型企业青睐。在 OpenResty 以外,章亦春为多个开源项目贡献了累计超过百万行代码,其中包括,Linux 内核、Nginx、LuaJITGDBSystemTapLLVM、Perl 等,并编写过 60 多个开源软件库。

关注我们

如果您喜欢本文,欢迎关注我们 OpenResty Inc. 公司的博客网站 。

我们也在 B 站上也有 OpenResty 官方的视频分享空间,欢迎订阅。

同时欢迎扫码关注我们的微信公众号:

[转帖]优化超大 Nginx 配置导致的内存碎片的更多相关文章

  1. Nginx使用教程(三):Nginx配置性能优化之I/O和TCP配置

    配置Nginx I/O <br\> Sendfile 当应用程序传输文件时,内核首先缓冲数据,然后将数据发送到应用程序缓冲区. 应用程序反过来将数据发送到目的地. Sendfile方法是一 ...

  2. [转帖]nginx配置ssl加密(单/双向认证、部分https)

    nginx配置ssl加密(单/双向认证.部分https) https://segmentfault.com/a/1190000002866627   nginx下配置ssl本来是很简单的,无论是去认证 ...

  3. Nginx服务器性能优化与安全配置实践指南

    转载自:https://www.bilibili.com/read/cv16151784?spm_id_from=333.999.0.0 1.引言 1.1 目的 为了更好的指导部署与测试艺术升系统ng ...

  4. Nginx配置性能优化

    大多数的Nginx安装指南告诉你如下基础知识--通过apt-get安装,修改这里或那里的几行配置,好了,你已经有了一个Web服务器了.而且,在大多数情况下,一个常规安装的nginx对你的网站来说已经能 ...

  5. nginx 配置优化的几个参数

    nginx 配置优化的几个参数 2011-04-22 本文地址: http://blog.phpbean.com/a.cn/7/ --水平有限欢迎指正-- -- 最近在服务器上搞了一些nginx 研究 ...

  6. Nginx配置性能优化(转)

    大多数的Nginx安装指南告诉你如下基础知识——通过apt-get安装,修改这里或那里的几行配置,好了,你已经有了一个Web服务器了.而且,在大多数情况下,一个常规安装的nginx对你的网站来说已经能 ...

  7. Nginx配置性能优化与压力测试webbench【转】

    这一篇我们来说Nginx配置性能优化与压力测试webbench. 基本的 (优化过的)配置 我们将修改的唯一文件是nginx.conf,其中包含Nginx不同模块的所有设置.你应该能够在服务器的/et ...

  8. Nginx配置不当可能导致的安全问题

    Nginx配置不当可能导致的安全问题 Auther: Spark1e目前很多网站使用了nginx或者tenginx(淘宝基于Nginx研发的web服务器)来做反向代理和静态服务器,ningx的配置文件 ...

  9. 关于Nginx配置性能优化

    基本的 (优化过的)配置 将修改的唯一文件是nginx.conf,其中包含Nginx不同模块的所有设置.在服务器的/etc/nginx目录中找到nginx.conf. 首先,我们将谈论一些全局设置,然 ...

  10. Nginx配置优化参考

    Nginx配置优化参考                                                                                          ...

随机推荐

  1. Boost程序库完全开发指南:1.1-C++基础知识点梳理

      主要整理了N多年前(2010年)学习C++的时候开始总结的知识点,好长时间不写C++代码了,现在LLM量化和推理需要重新学习C++编程,看来出来混迟早要还的. 1.shared_ptr 解析:sh ...

  2. 案例解析关于ArkUI框架中ForEach的潜在陷阱与性能优化

    本文分享自华为云社区<深入解析ForEach的潜在陷阱与性能优化:错误用法与性能下降的案例分析>,作者:柠檬味拥抱 . 在ArkUI框架中,ForEach接口是基于数组类型数据进行循环渲染 ...

  3. 看完这篇,DWS故障修复不再愁

    摘要:本文详细梳理分析了DWS服务面临软硬件故障场景和对应的修复原理,希望借此能够让你对DWS的集群故障修复有个全面深入的了解. 本文分享自华为云社区<GaussDB(DWS)故障修复系统性介绍 ...

  4. iOS分发证书过期或手动吊销,会影响App的下架吗?

    ​ iOS distribution发布证书过期或者被手动revoke了app会被下架吗? 在距离distribution 证书过期一个月(或被手动revoke了)的时候会受到apple的邮件 ​编辑 ...

  5. appuploader 入门使用

    回想一下我们发布 iOS 应用,不仅步骤繁琐,非常耗时.一旦其中一步失误了,又得重新来.作为一名优秀的工程师不应该让这些重复的工作在浪费我们的人生.在软件工程里面,我们一直都推崇把重复.流程化的工作交 ...

  6. Mac 修改文件默认打开方式

    Mac 播放 swf Flash文件 选中文件,Command+i 打开简介 不过文件图标还没变过来.重新下明天再看看

  7. 23年校招Java开发同花顺、滴滴等面经

    前言 已经工作近半年时间了,最近突然翻到这份面经,于是想整理一下一些面试的经验,大中小公司都有 青书一面 50min 数据库.java基础. Cas机制. Tcp/udp区别 堆排序介绍,答错了,弄成 ...

  8. 【计算机网络】身份认证Oauth2

    身份认证Oauth2 https://www.bilibili.com/video/BV1FL411h7es/?spm_id_from=333.999.0.0&vd_source=d11276 ...

  9. 前端知识点 | 查看已登录网站 Cookie 信息

    方法一:针对 Chrome 浏览器 设置 \(\to\) 隐私设置和安全性 \(\to\) Cookie 及其他网站数据 \(\to\) 查看所有 Cookie 和网站数据 or chrome://s ...

  10. 解决SUM函数返回为NULL

    解决SUM函数返回为NULL SUM函数的作用:计算某一字段中所有行的数值和, 使用SUM函数进行对符合条件的结果行数进行求和. 问题产生: sum 求和时会对 null 进行过滤,不计算,但如果没有 ...