zoukankan      html  css  js  c++  java
  • 一次线上OOM解决记录:GC overhead limit exceeded

    问题发现:

    最近线上一个后端接口项目连续两天中午12点30分左右QPS激增,导致2台实例中的某一台由于垃圾回收问题,导致CPU占用持续偏高,触发监控系统CPU占用告警和响应时间超时告警。

    现象如下:

     QPS瞬时激增后回落

    接口非200请求比例上升

     响应时间增加

    服务器CPU占用增高 

     TCP连接情况

     

    使用

    jstat -gcutil ps

    命令打印JVM 的gc日志,发现JVM一直出于频繁Full gc的状态,这也是导致机器CPU占用一直居高不下的原因。

    接下来使用

     jmap -dump:file=xxx.dump ps

     命令导出内存映像文件,并使用Eclipse MAT 工具分析内存映像文件,结果如下:

    说明:
    Shallow Heap(浅堆)表示此对象占用的堆大小,包含对象的对象头,实例数据、对齐空间。
    Retained Heap(深堆)表示该对象被回收后,能够释放的内存大小。

     问题解决:

      从内存占用分析可看出,大部分的内存空间都被byte数组占用了,Http11OutPutBuffer 这个类也占用了500多KB的内存,上图的依赖树表里可以看出Http11InPutBuffer、Http11OutPutBuffer 中大部分的空间都被byte数组占用了,而持有byte数组的类 是HeapByteBuffer。

    我们知道Http11OutPutBuffer 这个类,是属于tomcat中的,而我的项目中使用的是外置的Tomcat 9,所以就需要检查一下Tomcat中的相关配置:

    <Connector port="8084" relaxedPathChars="|{}[]," relaxedQueryChars="|{}[],"
            executor="tomcatThreadPool" connectionTimeout="30000" keepAliveTimeout="-1" maxKeepAliveRequests="-1" protocol="org.apache.coyote.http11.Http11Nio2Protocol" enableLookups="false" socketBuffer="65536"  maxHttpHeaderSize ="512000" URIEncoding="UTF-8" redirectPort="8443" />
    <Executor name="tomcatThreadPool" namePrefix="catalina-exec-" maxThreads="600" minSpareThreads="100"/>

    由上可发现maxHttpHeaderSize的大小竟然和上面的byte数组大小一致,而官方文档 中的默认配置仅为8192,也就是8KB。

    所以我将maxHttpHeaderSize值调整为了默认值8192,同时将socketBuffer的值也减小为了默认值9000。

    另外,还将tomcat线程池的配置也优化了一下,通过观察监控,发现这个后台接口平均QPS在600左右,所以我将minSpareThreads这个值修改成了600,保证有足够的空闲线程支撑平时的访问量,同时将maxThreads调整成了2000,注意这个值不能调的过大,过大的话会导致CPU 花费过多的时间在线程 上下文切换上,导致运行效率的下降。我的这个后台接口仅做数据查询,对CPU资源消耗较少,所以我将maxThreads设置的较大一点,同时也满足高峰时的并发请求。

    同时,由于项目中是使用的Nginx作为前置代理网关,为保证Nginx和Tomcat之间的连接高效,我将Nginx和Tomcat之间的连接配置成了长连接。参考:https://blog.csdn.net/nimasike/article/details/81129163

     上图中的keepalive 600 为配置Nginx和Tomcat之间的 空闲长连接个数为600个,另外配置了proxy_http_version 1.1;  proxy_set_header Connection ""; 保证Nginx和Tomcat之间的网络连接高效利用。

    而客户端到Nginx端我根据我们业务的情况,限制了他们之间的长连接:

    http{
    keepalive_timeout  15s;
    keepalive_requests 10;
    }

    以便于在高峰期尽快释放连接。

    同时还配置了Nginx里的请求体压缩功能,这个也是常见的优化手段。

    优化后的效果如下:

     12点30分高峰准时来临

     

     非200响应无较大变化

     

     响应时间无较大变化

     

     CPU飙升后迅速回落

     

     TCP连接情况,可以看到_tw 也就是timewait状态的连接相比之前变多了,这是我们调整限制了Nginx和客户端之间的长连接后的结果。

    以上就是这次线上OOM问题的解决过程,欢迎讨论。

  • 出处: http://www.cnblogs.com/hiscode/
    本文版权归作者和博客园共有,转载请在文章页面明显位置标明原文链接。
查看全文
  • 相关阅读:
    大小端表示法
    构建二叉树并求其深度
    输入一行字符反向输出
    C++读取一行字符串输入
    关于递归调用的深度
    2016-9-22题目:extern char* 与char[]
    Ubuntu安装搜狗输入法
    判断字符串相等
    [Warning] deprecated conversion from string constant to 'char*' 原因
    ArcGIS API for JavaScript 4.2学习笔记[31] (补充学习)Task类
  • 原文地址:https://www.cnblogs.com/hiscode/p/handle_a_GC_overhead_limit_exceeded.html
  • Copyright © 2011-2022 走看看