共计 1301 个字符,预计需要花费 4 分钟才能阅读完成。
一、发生故障
今天发现服务查询一直卡住,就看了一下服务器:
当时就愣住了就这一个服务就把 CPU 占满了,再看了下端口号:
出现了大量的 CLOSE_WAIT。看到这里我就只有一个想法:程序代码有问题或者是配置的问题
二、排查
为此我先重启了服务并加上参数用 jconsole 查看服务状况:-Djava.rmi.server.hostname=xxx.xxx.xxx.xxx
-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=10000
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false
再打印 GC 日志:-verbose:gc
-Xloggc:/usr/app/ydjAgent/gc_log
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
启动参数太长了我又把它添加到环境变量里:vim /etc/profile
export JAVA_OPTS=’-Xms1024m -Xmx4096m -Djava.rmi.server.hostname=120.0.0.1 -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=10000 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -verbose:gc -Xloggc:/usr/app/ydjAgent/gc_log -XX:+PrintGCDetails -XX:+PrintGCTimeStamps’
根据 jconsole 概览和 GC 日志可以看的出,是因为系统频繁进行 GC 导致的:
一般情况下,young gc 频繁是正常的,full gc 如果非常频繁,一般情况下有问题的就是接口查询中的集合的数据,存起来了,一直没删除,导致 gc 没有及时回收。
然后将堆信息 dump 下来后用 Eclipse memory analyze 分析了一下,发现 char[] 数组和 byte[] 数组占了大部分内存。
综上分析后查明,因为业务需要统计一个月内的所有订单中的商品以及品牌排行,因为原有表的设计的主键 id 是 UUID,服务在启动的时候只给了最大 4G 内存,即使是只查询订单 id,都占了很大一部分空间,更别说后面查询出来的订单信息会占用更大的内存空间,而因为这样,数据库的压力和应用的压力也会很大,应用一直处于 FULL GC 状态,把 cpu 占满。
三、解决办法
因为该应用和数据库是在同一个服务器上,所以就先把应用部署到另一个服务器上然后用 nginx 通过内网将请求转发,把内存设置 8G,缓解原来服务器的 CPU 压力,即便如此,在数据访问的时候还是对数据库造成了很大的压力。因为我代码写的太烂了哈哈。。事发之后先向老板做了汇报,老板表示理解。。给我时间去重新设计原有的架构。。。不说了写代码去。。。