投产OutOfMemory砸了我的1024

坐标广州,金融系统开发。程序员节刚好碰上投产点,晚上十点正常开始,支付系统投产了一半,积分系统的同事说,积分系统重启后,交易一进来就报java.lang.OutOfMemoryError: Java heap space。问这次上线有没有改了什么,他说把-Xms256m -Xmx256m 改成了Xms2048m -Xmx2048m,其他的都没动。考虑到系统的稳定性,先考虑把参数回退看行不行。

凌晨2点,支付系统投产及验证完毕。大家可以抽出来处理积分的问题了。这个时候已经确定了参数回退还会继续报错。其实结果是预料之中的,heap OutOfMemoryError 不可能是参数调大引起的。这里先介绍下积分系统,积分系统是一个比较老的java工程,通过sh脚本调用main方法启动。支付系统、商城系统等通过socket连接调用积分系统的查询、扣减等接口。这里贴下积分系统的启动的sh脚本。$JAVA_HOME/bin/java -Xmn1280m -Xms2048m -Xmx2048m -cp ${APP_HOME}bin:./../lib:.:${JAVA_HOME}/jre/lib/rt.jar:${JAVA_HOME}/jre/lib/t。为了方便看head dump ,加了内存溢出的heap dump的保留路径,还有打印gc的信息及加上监控jvm的端口,如下:$JAVA_HOME/bin/java -Xmn1280m -Xms2048m -Xmx2048m  -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/home/weblogic/heapdump/ -XX:+PrintGCDetails  -Dcom.sun.management.jmxremote.port=10999 -cp ${APP_HOME}bin:./../lib:.:${JAVA_HOME}/jre/lib/rt.jar:${JAVA_HOME}/jre/lib/t。

凌晨3点,测试环境测试没有问题,把参数仍到生产。系统重启后,刚刚进来的几笔请求,积分系统返回很快,一切看起来不很正常。但那只是五分钟的事情,后面,日志打印出现卡顿,OutOfMemoryError 如约而来,接着返回java.io.IOException: Broken pipe。明显是服务端返回不及时,客户端已经超时断开了。

一顿操作(此处省略9012行),才发现OutOfMemoryError是数据库报起,那就有可能查询返回大量数据,直接导致java heap被塞满了。jvm进行gc,stop the world ,对于请求处理不及时,导致返回卡死。针对此接口,揪出了sql。发现商城的请求有个客户号为空,然后积分系统没判好空,导致查出了所有了用户的积分数据。几百万的数据一下子全部涌过来。至此水落石出,全部搞定后,天已泛亮,以最1024的方式过了一个1024.

后记:回顾昨晚的一整个流程,感觉很多时候我们都喜欢往最偏的地方想。一开始,出现OutOfMemoryError,我们就想要怎么调jvm参数和gc回收策略。参数调整以后,在测试环境可以正常,到了生产环境以后又挂了。我们这个时候有怀疑生产的服务器有没有可能出现问题了。最后静下心来看日志(ps:日志打印前面一定要加上线程id,要不然很难分的清,哪个日志是哪个请求的),看最初的报错OutOfMemoryError,才发现是数据库驱动报起的,才想到是不是可能是数据库查询引起的。我们一直没有往这方面想的原因是因为一直积分系统都好好的,这次上线都没改业务点,应该不会出现sql的问题。最后忽略了请求参数变动引起的我们被动的变动。