nginx内存占用高—内存池使用思考


问题现象

nginx top 进程 虚拟内存 200G 实际内存5G 和 CDN 平台相比要高很多

排查思路

  1. 使用pmap -p 进程号,发现从系统角度确实 有分配几百G,但是实际内存5G 说明分配的大部分内存没有实际使用,且不是内存泄漏,属于内存碎片问题。

  2. 由于存在陡增现象,怀疑是否与某些特殊请求有关,post 大文件?过滤访问日志,同时间段两日对比没有找到特别的请求。由于最近出现,怀疑是否与最近的XXXX_line_buffer_size 修改增大有关。过滤配置修改时间和zabbix 内存统计趋势,没有严格匹配到。

  3. 使用工具systemtap (https://github.com/zengxiaobai/systemtap-scripts)排查是否存在内存泄漏,没有存在泄漏,但是有时候发现下面的未释放栈内存泄漏。但是从代码角度看内存都是从nginx r->pool 申请且有在请求结束时释放,说明可能请求没有结束,r->pool 一直占用着,说明当回源较慢并发较高时可能造成内存陡增现象,且与XXXX_line_buffer_size 200K 有关。由于stap 是明确 malloc -free,r->pool 又有在请求结束时释放,说明 该现象还不是内存碎片,需要再追踪一次,再次追踪发现陡增时malloc - free == 0, 确实有释放,属于内存碎片问题

  4. 使用工具systemtap 排查分配TOP的函数栈, 发现是改写模块分配内存太多。

bytes(not free yet): 138598400
value |-------------------------------------------------- count
8192 | 0
16384 | 0
32768 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 2707
65536 | 0
131072 | 0ngx_alloc+0xf [nginx]
ngx_palloc_large+0x13 [nginx]
ngx_palloc+0x42 [nginx]
ngx_create_temp_buf+0x27 [nginx]
ngx_http_subs_match+0xa99 [nginx]
ngx_http_subs_body_filter+0x40d [nginx]
ngx_http_pagerewrite_body_filter+0x88 [nginx]
ngx_http_sub_output+0xb0 [nginx]
ngx_http_sub_body_filter+0xb21 [nginx]
ngx_http_gunzip_body_filter+0x765 [nginx]
ngx_http_trailers_filter+0x5f [nginx]
ngx_http_lua_capture_body_filter+0x84 [nginx]
ngx_output_chain+0x8a4 [nginx]
ngx_http_copy_filter+0x191 [nginx]

分析代码,发现响应内容只要匹配到满足要求的正则,就会申请一块XXXX_line_buffer_size 大小 设置为200K(临时解决线上core时设置),并进行内容处理,处理完再copy 到 响应内容dst。由于配置200K, 无法使用nginx 默认pool 大小 4K ,也就是说 存在 一个响应内容 频繁申请 且申请都是非内存池的现象,易导致内存碎片问题。

结合 squid 的内存池设计和 nginx 的内存池设计,进行对比

squid 针对每个请求过程中 不同结构体 申请一块内存对象,并入内存池栈中,内存结构体对象 在释放后,只会把内容清零,不归还给系统,且该空间可以给任意请求,只要申请这个结构体对象就可以使用。

squid 内存池虽然可以复用请求过程中的结构体对象,但是零碎分配,从0 开始增长到n,且不同请求任意穿插 ,这中间可能会存在内存碎片,

nginx 内存池在请求进入时申请一块较大空间(4K),后续请求过程需要申请的内存都从这个4K 的大池子申请

,请求结束时 释放整块4K 大小空间,只要不超过这个4K 大小,并发请求申请的内存极有可能是连续的,有利于glibc 的内存合并机制。

nginx 机制,没有结构体对象概念,不同请求不能复用空间,但是有利于内存合并。

缺点:并发较高 pool size 较大时,占用内存可能较多。且一旦分配大小一次性超过4K. nginx 是另外分配一个空间挂到pool中,在请求结束时一起释放,所以凡是分配超过pool 大小的内存,就违背了nginx pool 设计规则。内存问题会尤为显著,增加内存占用时间,且碎片率较高。一次性分配100 K 和10次分配10K 字节所带来的效果不同,假设pool 中有50K 剩余,一次性分配100K 无法利用50K 而需要再申请100K, 而10次分配10K 只需要再申请 50K

调优

  1. 优化 XXXX_line_buffer_size 页面改写处理逻辑,避免多次拷贝分配
  2. 流处理 避免大块处理,将js 内容 从> 分隔换成 \n 换行分隔,将大块内存一次性分配换成多个小块处理
  3. pool 内避免一次性分配大块内存,按需分配
  4. 结合具体业务场景可以适当调高poolsize
  5. 使用jemalloc 等
  6. 使用malloc_trim 进行紧缩

总结

结合 squid 的内存池设计和 nginx 的内存池设计,进行对比 ,我们可以发现其设计很像 coss 缓存机制和aufs 缓存机制的区别:

coss 存储机制 在一定程度上根据请求业务的时间局部性可以使得一个页面相关元素的缓存位置访问能够空间和时间局部相邻,相同类型的元素过期时间也一一般一致。良好的局部连续性和复用是系统调优设计的关键。

后续测试

ps -o maj_flt -o min_flt -p pid
旧版本访问2000 次内存页错误:2134330,随请求增加增加
新版本访问2000 次内存页错误:567849,随请求增加增加
关闭 subs_line_buffer_size 500k 0 配置访问2000次内存页错误: 25528 后续不随请求数增长而增长,nginx 中 较大的内存分配更容易产生碎片问题

nginx内存占用高---内存池使用思考相关推荐

  1. java应用程序占用高内存_对Java应用程序中的内存问题进行故障排除

    java应用程序占用高内存 重要要点 解决内存问题可能很棘手,但是正确的方法和正确的工具集可以大大简化此过程. Java HotSpot JVM可以报告几种OutOfMemoryError消息,因此务 ...

  2. win7计算机内存占用高,WIN7系统电脑内存占用高的解决办法有哪些

    现在经常很多用户的WIN7系统内存都占用太多,导致电脑的运行速度变得很慢.所以这里小编就给大家介绍一下如何解决这个内存占用高的办法. Win7内存占用高解决方法一 1:单击 按钮,在搜索框输入&quo ...

  3. Win11内存占用高怎么办,Win11内存占用高解决方法

    ​Win11内存占用高怎么办?Win11系统是目前非常火热的电脑操作系统,很多用户安装使用Win11系统后发现系统内存占用率非常高,不知道win11内存占用高怎么解决,我们可以尝试通过关闭一些不需要的 ...

  4. 桌面窗口管理器(dwm.exe)占用高内存的解决方法

    前往我的主页以获得更好的阅读体验桌面窗口管理器(dwm.exe)占用高内存的解决方法 - DearXuan的主页https://blog.dearxuan.com/2022/01/14/%E6%A1% ...

  5. 计算机内存占用过高,电脑内存占用高怎么办 Win7内存占用高解决办法

    Win7系统在正常使用的时候会占用很多资源,比如网络诊断,缓存还有其他各种平时大部分时候我们都用不上的资源,如果我们电脑本身内存比较小只有2G内存或者以下,打开程序稍微多加个就会造成Win7内存占用高 ...

  6. win7计算机内存占用高,win7系统内存占用高的解决方法

    我们在操作win7系统电脑的时候,常常会遇到win7系统内存占用高的困惑吧,一些朋友看过网上零散的win7系统内存占用高的处理方法,并没有完完全全明白win7系统内存占用高是如何解决的,今天小编准备了 ...

  7. java事务占用内存吗,如何排查java应用中CPU使用率高或内存占用高的问题

    如何排查java应用中CPU使用率高或内存占用高的问题?这类问题的排查步骤基本通用的.现在通过一个具体的例子来说明. 问题描述 最近有个线上项目每天0点过后CPU使用率会上升至200%到300%. 排 ...

  8. 如何清理占用计算机内存,win10如何清理电脑内存占用高怎么办

    随着Win10的更新,越来越多的用户将系统升级到了Win10,可是不少Win7.Win8系统的用户升级后,发现C盘内存空间严重变少了,磁盘占用比之前的系统还多,win10如何清理电脑内存占用高怎么办? ...

  9. VS2019 内存占用高

    VS2019 内存占用高 在VS2019 16.1.3 中内存占用过高处理方式 在VS2019 16.1.3 中内存占用过高处理方式 我是用VS2019 开发 .net Framework 的应用, ...

最新文章

  1. C++ 内存泄漏检测:valgrind和AddressSanitizer
  2. 给history命令加上执行用户和时间
  3. 计算机领域中,增量是什么意思?
  4. 帝国cms7.0调用指定栏目,指定顺序排列
  5. Prim算法的C语言程序
  6. ASP.NET MVC:WebViewPage.cs
  7. 《循序渐进Oracle:数据库管理、优化与备份恢复》一一第1章 Oracle数据库的创建...
  8. WPF DataGridComboBoxColumn使用(绝对良心版)
  9. 日期计算器输入天数计算日期_如何在Windows计算器中执行日期计算
  10. 开机显示被调用的对象已与其客户端断开连接,解决方案亲测有效
  11. Java环境安装步骤
  12. 争对让望对思野葛对山栀注解_望对思的上句,望对思的上一句是
  13. Windows IPC 连接详解
  14. 利用matlab的SPM12功能核磁共振成像数据处理_Auditory fMRI data(二)
  15. 计算机毕业设计教学资源网站的设计与实现
  16. POJ-2001-Shortest Prefixes
  17. Redis第 2讲:配置Redis访问密码及端口号
  18. 电气领域-输电线路杆塔鸟巢检测图像数据(含标签,原始图像未经扩充)
  19. 个人云服务器部署leanote(蚂蚁笔记)
  20. DSY2287*消失之物

热门文章

  1. nethogs监控linux流量
  2. .NET 权限笔记-Attribute+Reflect+Remoting
  3. 关于建立完整商业应用软件框架库的设想
  4. shell脚本的规范
  5. bootstrap-按钮(按钮工具栏)
  6. UbuntuでPostgreSQLをインストールからリモートアクセスまでの手順
  7. dplyr 数据操作 常用函数(2)
  8. How to use kingshard building a MySQL cluster
  9. javascript工具类(util)-持续更新
  10. Table布局及其它布局