一个 openresty 内存“泄漏”问题

Question:

大家好,这里向大家咨询一个在 openresty-1.9.15.1 下的泄漏问题,复现手段非常简单:

  1. 直接在 openresty 下 ./configure 的时候,开启 mp4 模块,即 --with-http_mp4_module, 然后再配置文件配置一个location,开启 mp4 指令,例如:

     location /live/hls/ {
         mp4;
         root /home/test;
     }
    

    保证有一个测试 mp4 文件是可以访问的。

  2. 使用ab测试该location,例如:

    ab -c 1000 -n 1000 "http://192.168.182.128:8081/live/hls/chuntianli.mp4?start=1&end=10"

Answer:

这里的原因应该是启用 ngx_lua 模块时,会强制 glibc 的 malloc 使用 mmap 来分配内存,而不是 sbrk 这样的系统调用在 data segment 里面分配,目的是为了把低 2GB 的内存地址空间都预留给 LuaJIT 的 GC 来使用。glibc 对于 mmap 分配的块可能会更加激进地缓存 free 掉的内存页。所以你看到的所谓的“不释放”其实并不是应用程序不释放,而只是 glibc 这样的基础系统库缓存了起来。

为进一步确认这一点,你可以持续无限制地保持压力,然后观察 nginx worker 进程的 RSS 是否会无限增长。

在书鑫老师的建议下,春哥在 lua-nginx-module 仓库的 malloc-trim 分支里实现了 lua_malloc_trim N 这个新的 nginx 配置指令。该指令会在 nginx 每处理 N 个请求之后,自动调用 libc 的 malloc_trim() 函数(如果当前 libc 有这个函数的话)。默认 N 是 1000. 将 N 置为 0 时即禁掉自动 trim 的行为。这个新功能应该会显著降低流量高峰以后 nginx worker 进程的(RSS)内存占用。

更多细节请参见:

https://github.com/openresty/lua-nginx-module/tree/malloc-trim

https://github.com/openresty/lua-nginx-module/commit/f0b45946d

https://github.com/openresty/lua-nginx-module/issues/872#issuecomment-250988928

相同的,如果 nginx 因为某些原因内存占用在不停增长但是却无法正常减少,这时候建议把你的 openresty 里面的 lua-nginx-module 升级到 github 仓库里 master 分支上的最新版本。然后在生产 nginx.conf 配置用于测试:

lua_malloc_trim 1;

生产上不建议使用 1 这么小的数字,但测试时为了效果明显,用 1 比较清楚。因为使用 glibc 缓存了很多由应用释放掉的内存块,而没有把这些内存及时归还给操作系统。

书鑫老师先前弄了一个独立的最小化的 C 程序来演示 glibc 内存分配器行为的一些细微方面,主要是和 OpenResty/LuaJIT 相关的细节。我又自己做了一些修改,使它的自动化程度更高一些。大家可以自己改一改,玩一玩:http://agentzh.org/misc/test-malloc-trim.c。当然了,只能在 Linux + glibc 上面跑哈。

参考下面链接进行整理:

https://groups.google.com/forum/#!searchin/openresty/lua_malloc_trim%7Csort:relevance/openresty/JA1mZwPgKtU/GZVsvmjzBQAJ

results matching ""

    No results matching ""