背景:
问题:
有个渠道支付服务,负责与所有支付相关服务进行交互,包括 渠道下单支付,渠道成功通知,渠道的对账等
服务4台机,平时跑的都很稳定,通过thrift进行对外提供服务,且平时并未发现访问超时的情况,已经平稳在线上跑了1年多了,没出现过超时问题。
但最近发现,每天到了晚上凌晨2点开始大量服务访问超时,且定位到每次都是抢到对账任务的那台服务出现问题。
解决:
后通过监控和打印GC日志发现,出现问题机器服务的Major GC频率增加,应该是内存问题。
故把对账程序拆出后单独部署后, 再没出现服务访问超时情况。
分析,对账时,因为要捞出当天支付数据到内存进行对账(随着业务发展订单开始猛增)故触发了GC。其实增加分批limit当然也可以解决
这是最近第二次踩到GC的坑了, 第一次是每次访问给每个线程分配的内存过多,并发上来后性能严重降低,导致WEB超时,有必要总结下了
重现下:
死磕重现下,
模拟业务部分,假使每个业务需要500ms返回,代码如下:
/** * 模拟当系统中使用大对象时,对JVM造成的影响 * * @author 包子(何锦彬). 2017.01.07 * @QQ 277803242 */ @WebServlet("/Test") public class Test extends HttpServlet { private static final long serialVersionUID = 1L; private Logger logger = Logger.getLogger(Test.class.getName()); protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { long startTime = System.currentTimeMillis(); // deal try { // 模拟业务花费时间 Thread.sleep(500); } catch (InterruptedException e) { } long costTime = (System.currentTimeMillis() - startTime); // 接口1秒timeout,打印出日志 if (costTime > 1000) { logger.warning("cost time:" + costTime); } Writer out = response.getWriter(); out.append("ok"); } }
放入tomcat,加入垃圾回收方式和堆内存大小,打印垃圾回收日志
JAVA_OPTS="-Xmx1200m -Xms1200m -Xmn200m -Xss228k -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+PrintGCDetails"
用jmeter压测1分钟后,发现正常,每次返回均在500毫秒左右,日志里也没有出现访问超时。
加入模拟对账部分代码,1分钟后对账开启,持续提供服务,为了让它触发GC,模拟加载了1G的待对账数据,(当然,在生产环境里只是一个大对象,但OU区本来就有东西了)