版本信息如下 Tengine version: Tengine/2.2.1 (nginx/1.8.1) nginx内存使用不释放,会不断增长,直到占满整个系统内存。 每次将nginx进行reload和重启操作后即释放。 系统版本:CentOS6.5 64位; 内存有32g; 请求帮助,谢谢!
[alibaba/tengine]异常:nginx内存使用不释放,会不断增长,直到占满整个系统内存
回答
描述的这种情况很可能跟第三方模块有关,而且可能在特定使用方式容易触发。 最好给一下编译的模块列表。如果可能,给出能复现问题的关键配置片段。
To Lax: 编译模块列表如何提供?是不是我安装时的./configure信息 配置片段是指什么?
./configure 选项即可。 获取模块列表 ./nginx -m
获取配置信息:./nginx -d。尽量是能复现问题的最小配置。 @maronggang
To Lax: $ ./nginx -m Tengine version: Tengine/2.2.1 (nginx/1.8.1) nginx: loaded modules: nginx: ngx_core_module (static) nginx: ngx_errlog_module (static) nginx: ngx_conf_module (static) nginx: ngx_dso_module (static) nginx: ngx_events_module (static) nginx: ngx_event_core_module (static) nginx: ngx_epoll_module (static) nginx: ngx_procs_module (static) nginx: ngx_proc_core_module (static) nginx: ngx_openssl_module (static) nginx: ngx_regex_module (static) nginx: ngx_http_module (static) nginx: ngx_http_core_module (static) nginx: ngx_http_log_module (static) nginx: ngx_http_upstream_module (static) nginx: ngx_http_static_module (static) nginx: ngx_http_gzip_static_module (static) nginx: ngx_http_autoindex_module (static) nginx: ngx_http_index_module (static) nginx: ngx_http_auth_request_module (static) nginx: ngx_http_auth_basic_module (static) nginx: ngx_http_access_module (static) nginx: ngx_http_limit_conn_module (static) nginx: ngx_http_limit_req_module (static) nginx: ngx_http_realip_module (static) nginx: ngx_http_geo_module (static) nginx: ngx_http_map_module (static) nginx: ngx_http_split_clients_module (static) nginx: ngx_http_referer_module (static) nginx: ngx_http_rewrite_module (static) nginx: ngx_http_ssl_module (static) nginx: ngx_http_proxy_module (static) nginx: ngx_http_fastcgi_module (static) nginx: ngx_http_uwsgi_module (static) nginx: ngx_http_scgi_module (static) nginx: ngx_http_memcached_module (static) nginx: ngx_http_empty_gif_module (static) nginx: ngx_http_browser_module (static) nginx: ngx_http_user_agent_module (static) nginx: ngx_http_upstream_hash_module (static) nginx: ngx_http_upstream_ip_hash_module (static) nginx: ngx_http_upstream_consistent_hash_module (static) nginx: ngx_http_upstream_check_module (static) nginx: ngx_http_upstream_least_conn_module (static) nginx: ngx_http_upstream_keepalive_module (static) nginx: ngx_http_upstream_dynamic_module (static) nginx: ngx_http_stub_status_module (static) nginx: ngx_http_write_filter_module (static) nginx: ngx_http_header_filter_module (static) nginx: ngx_http_chunked_filter_module (static) nginx: ngx_http_range_header_filter_module (static) nginx: ngx_http_gzip_filter_module (static) nginx: ngx_http_postpone_filter_module (static) nginx: ngx_http_ssi_filter_module (static) nginx: ngx_http_charset_filter_module (static) nginx: ngx_http_sub_filter_module (static) nginx: ngx_http_userid_filter_module (static) nginx: ngx_http_footer_filter_module (static) nginx: ngx_http_trim_filter_module (static) nginx: ngx_http_headers_filter_module (static) nginx: ngx_http_upstream_session_sticky_module (static) nginx: ngx_http_reqstat_module (static) nginx: ngx_http_lua_module (static) nginx: ngx_http_copy_filter_module (static) nginx: ngx_http_range_body_filter_module (static) nginx: ngx_http_not_modified_filter_module (static)
To Lax: 由于是生产环境,配置文件很多,我先提供一个主配置文件吧nginx.conf。请见附件 nginx.txt
看配置用到了 shm 作为temp和cache,这也是放在内存里的。 检查一下是不是 /dev/shm/ 里的文件没有清理掉?
其它配置暂时看不出容易消耗内存的。
To Lax: 看了下/dev/shm,空间大小为0,该目录下有子目录,但是都是空目录。具体如下: [root@a121a129 ~]# cd /dev/shm/ [root@a121a129 shm]# ls cache_ngx tmp_ngx [root@a121a129 shm]# ll total 0 drwx------ 18 culngx culngx 360 Jun 18 2017 cache_ngx drwx------ 2 culngx culngx 40 Apr 27 09:05 tmp_ngx [root@a121a129 shm]# du -msh . 0 . [root@a121a129 shm]# cd cache_ngx/ [root@a121a129 cache_ngx]# ls 0 1 2 3 4 5 6 7 8 9 a b c d e f [root@a121a129 cache_ngx]# ll total 0 drwx------ 31 culngx culngx 620 Mar 20 22:35 0 drwx------ 33 culngx culngx 660 Mar 20 22:35 1 drwx------ 28 culngx culngx 560 Mar 20 22:35 2 drwx------ 23 culngx culngx 460 Mar 20 22:36 3 drwx------ 31 culngx culngx 620 Mar 20 22:37 4 drwx------ 24 culngx culngx 480 Mar 20 22:37 5 drwx------ 35 culngx culngx 700 Mar 20 22:36 6 drwx------ 29 culngx culngx 580 Mar 20 22:36 7 drwx------ 22 culngx culngx 440 Apr 3 12:03 8 drwx------ 36 culngx culngx 720 Mar 20 22:37 9 drwx------ 28 culngx culngx 560 Mar 20 22:39 a drwx------ 28 culngx culngx 560 Mar 20 22:35 b drwx------ 30 culngx culngx 600 Mar 20 22:35 c drwx------ 34 culngx culngx 680 Mar 20 22:35 d drwx------ 33 culngx culngx 660 Mar 20 22:35 e drwx------ 32 culngx culngx 640 Mar 20 22:35 f [root@a121a129 cache_ngx]# [root@a121a129 cache_ngx]# [root@a121a129 cache_ngx]# [root@a121a129 cache_ngx]# [root@a121a129 cache_ngx]# [root@a121a129 cache_ngx]# cd 0 [root@a121a129 0]# ls 06 09 16 36 40 54 6e 77 85 8c 99 af d4 ed f1 07 11 1a 3e 44 56 71 7b 87 94 9b cb e8 ef [root@a121a129 0]# du -msh . 0 . [root@a121a129 0]# cd 06/ [root@a121a129 06]# ls [root@a121a129 06]#
你可以用这个工具来观察你的nginx内存分配情况,如下:
To hongxiaolong: 我下载tengine-master,直接通过命令gdb,有报错,请看看如何使用该分析工具。 报错信息如下:
[culngx@a2a115 sbin]$ gdb -q -x /home/culngx/tengine-master/modules/ngx_debug_pool/debug_pool.gdb -p 21112 Attaching to process 21112 Reading symbols from /home/culngx/culp/ngx/sbin/nginx...done. Reading symbols from /lib64/libpthread.so.0...(no debugging symbols found)...done. [Thread debugging using libthread_db enabled] Loaded symbols for /lib64/libpthread.so.0 Reading symbols from /lib64/libdl.so.2...(no debugging symbols found)...done. Loaded symbols for /lib64/libdl.so.2 Reading symbols from /lib64/libcrypt.so.1...(no debugging symbols found)...done. Loaded symbols for /lib64/libcrypt.so.1 Reading symbols from /home/culngx/culp/luajit/lib/libluajit-5.1.so.2...(no debugging symbols found)...done. Loaded symbols for /home/culngx/culp/luajit/lib/libluajit-5.1.so.2 Reading symbols from /lib64/libm.so.6...(no debugging symbols found)...done. Loaded symbols for /lib64/libm.so.6 Reading symbols from /usr/lib64/libssl.so.1.0.0...(no debugging symbols found)...done. Loaded symbols for /usr/lib64/libssl.so.1.0.0 Reading symbols from /usr/lib64/libcrypto.so.1.0.0...(no debugging symbols found)...done. Loaded symbols for /usr/lib64/libcrypto.so.1.0.0 Reading symbols from /lib64/libz.so.1...(no debugging symbols found)...done. Loaded symbols for /lib64/libz.so.1 Reading symbols from /lib64/libc.so.6...(no debugging symbols found)...done. Loaded symbols for /lib64/libc.so.6 Reading symbols from /lib64/ld-linux-x86-64.so.2...(no debugging symbols found)...done. Loaded symbols for /lib64/ld-linux-x86-64.so.2 Reading symbols from /lib64/libfreebl3.so...(no debugging symbols found)...done. Loaded symbols for /lib64/libfreebl3.so Reading symbols from /lib64/libgcc_s.so.1...(no debugging symbols found)...done. Loaded symbols for /lib64/libgcc_s.so.1 0x0000003fbc032caa in sigsuspend () from /lib64/libc.so.6 Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.132.el6.x86_64 libgcc-4.4.7-18.el6.x86_64 nss-softokn-freebl-3.14.3-9.el6.x86_64 zlib-1.2.3-29.el6.x86_64 (gdb) debug_pool No symbol "ngx_pool_stats" in current context. (gdb) No symbol "ngx_pool_stats" in current context. (gdb) No symbol "ngx_pool_stats" in current context. (gdb) quit A debugging session is active.
Inferior 1 [process 21112] will be detached.
Quit anyway? (y or n) y
hi @maronggang
- 这个模块默认不安装的,需要编译期 打开
$ ./configure --add-module=./modules/ngx_debug_pool
$ make && make install
- 另外也可以直接配置这个页面,就不需要gdb上去
http {
server {
listen 80;
location = /debug_pool {
debug_pool;
}
}
}
根据提示编译安装后,可以通过curl http://localhost:80/debug_pool命令来显示NG内存情况。但是,导致一个新的问题:https双向认证出现问题,直接导致我们应用无法正常访问。 后来我们的研发说,是因为String client_cert_dn=request.getHeader("client_cert_dn");这个对象为空导致,后来我将ng程序包回退后就正常了。 说明,安装ngx_debug_pool全过程没有对.conf文件进行修改,所以我觉得肯定是安装该模块后导致该问题。conf文件中是有proxy_set_header client_cert_dn $ssl_client_s_dn;相关配置的。 附件是对应应用的conf文件 newprepayhttps.txt
请求大神帮助。
之前的问题搞定了,目前ngx_debug_pool也已实现,当前的输出结果具体如下: 还请大神帮忙看下,为什么nginx内存没释放的问题。
$ curl http://localhost:8080/debug_pool pid:1649 size: 8192 num: 218804 cnum: 1 lnum: 274233 ngx_http_create_request size: 11408552 num: 2 cnum: 1 lnum: 109 ngx_init_cycle size: 25088 num: 290104 cnum: 33 lnum: 663616 ngx_event_accept size: 155648 num: 31 cnum: 31 lnum: 3 ngx_http_upstream_check_add_timer size: 0 num: 3 cnum: 0 lnum: 21 ngx_http_map_block size: 304416 num: 42641 cnum: 29 lnum: 40238 ngx_http_upstream_connect size: 0 num: 1 cnum: 0 lnum: 0 main size: 11MB num: 551586 cnum: 95 lnum: 978220 [SUMMARY] $
- 从配置上看没有什么异常泄露的三方模块(单etc/*.conf不确定)
- 从debug pool显示,nginx内部自身的pool也不存在内存泄露。可能其他nginx内部的直接malloc/free逻辑触发内存泄露(一般不会,ssl/spdy部分存在类似逻辑但是没遇见过泄露情况)。另外务必确保你内存泄露的时候采集的debug pool信息。
- 增加一项检测:如果默认编译,使用的是libc的ptmalloc内存分配器库,这个库可能有一定的内存碎片问题,我们线上也有遇到过,见comment最后
- 任然无法查出,得上通用的内存分配扫描工具 。比如systap脚本抓取malloc/free的栈记录,然后分析记录信息查看。比如valgrind --mem-leak(往上可以搜索方法, 注意)
- glibc库的ptmalloc2信息采集:
强制nginx worker调用malloc_stats()函数,让其将数据输出到stderr(nginx重定向到error.log)
--------
$ gdb -p $(pgrep -P $(cat logs/nginx.pid)) -ex 'call malloc_stats()'
error.log内dump出来的信息
-----
Arena 0: <<< 线程 0(一般tengine worker内只有1个thread)
system bytes = 1372160 <<< 从os抽取的内存(一般为mmap)
in use bytes = 1198448 <<< 应用程序malloc的
Total (incl. mmap):
system bytes = 1372160
in use bytes = 1198448
max mmap regions = 6
max mmap bytes = 2789376
- for jemalloc:
$ gdb -batch -ex 'call malloc_stats_print(0,0,0)' -p <pid>
To chobits 谢谢! 1)采集debug pool信息,是在内存泄漏的时候采集的。 2)关于“glibc库的ptmalloc2信息采集”中提供的2个gdb采集方法,有什么风险吗?生产环境,不敢随便操作。
hi @maronggang
2)关于“glibc库的ptmalloc2信息采集”中提供的2个gdb采集方法,有什么风险吗?生产环境,不敢随便操作。
会导致程序中断一段时间(该时间用于调用malloc_stats函数,理论上较短)。
虽然我们这边线上调用过没有实际影响,但建议你切掉流量再调用。