情况如下:

某服务,在测试环境测试的时候整个响应过程也就0.5s左右,测试环境和生产环境axis2版本一致,tomcat版本一致,但是生产环境需要差不多20S。

后来,越来越慢,导致服务一起来,整个生产环境的CPU负载长期超过200%,响应超时2分钟,生产环境OSB大面积报错。并且由于CPU负载过高,导致此axis2容器下的其他服务均不能正常执行。

开始着手解决问题:

第一步当然是重启大法,重启tomcat服务,仍然不行,此服务响应刚开始能做到20S,但是慢慢的就开始变慢,半小时后,响应超过两分钟,超时。

并且奇怪的是服务一启动,CPU负载立马超过100%。(真是心都凉了!!!!!!)

开始思考:

1.由于业务逻辑是交由数据库处理的,java代码部分只负责数据的传递,考虑业务处理部分的代码逻辑问题。

2.考虑网络传输时间问题。

3.考虑环境差异问题。

针对问题1,查看了数据库的死锁情况,的确发现该部分逻辑对应的某张表发生了死锁现象,于是先kill该部分进程,并在update之后都加入commit动作。(当时想的是如果commit还不能解决,就把这个存储过程设为自治事务处理。)幸运的是,做了commit,之后,情况暂时好了很多,至少在kill进程之后,开始响应OSB了。

问题2,数据反馈封装的包也就1Kb左右,生产环境之间都是用的光纤,且该axis2容器其他部分的对接OSB服务的响应少于100MS,故排除。

问题3,tomcat版本和测试环境一致,axis2版本与测试环境一致。jdk都是1.6版本,生产环境系统32位,测试环境64位,但是我觉得即使系统性能应该没有问题,毕竟其他服务都是OK的。

。。。。。。

于是加入时间戳,开始判断是否由于程序处理过慢导致的问题。

通过时间分析发现,业务逻辑处理部分其实也就花了不到1s的时间,并且业务处理的开始时间就是OSB系统的触发时间。

也就是说,20S的总时长,除去程序处理的1s,剩下的19s都花在了return之后的部分,排除网络传输的时间问题,那么到底这19s的时间axis2在干嘛?

。。。。。。

陷入僵局,开始谷歌找资料。

。。。。。。

思路1.

一个Tomcat高CPU占用问题的定位

生产环境下JAVA进程高CPU占用故障排查

的确查找到某个线程占用CPU过高的现象,但是没找到具体原因,大概是跟GC有关系,遂放弃。

思路2。axis2响应超时的路子,经过查证,排除。相关资料自行谷歌。

思路3。查看tomcat的catalina.out文件,发现大量内存泄露的异常

参考:Tomcat6.0的Thisisverylikelytocreateamemoryleak异常

但是,文档提到的方案1和方案2上头不允许采取,方案3无实际意义,和大神讨论之后放弃此思路。

思路4.本地用soapui调用了生产环境的wsdl,响应时间18000ms。确定不是tomcat到OSB系统的数据传输问题。

思路5.要不,重构一遍?

开玩笑,刚上线的代码,太打脸了。

功能人员和我的内心都是拒绝的,并且时间不允许,但是测试环境又没有任何问题,我拒绝是代码的问题。

。。。。。。。

不过也只能从代码层去思考问题了,既然花在了return上面,那么就从rerurn返回的数据结构开始查找吧。

(return部分的数据结构是遗留代码,并且询问遗留此代码的人员之后,得到的建议是此段代码尽量不要动,是当初客户端的系统直接提供的封装好的代码,改出过问题。)

不过查找代码也不是没有收获,里面看到了大量的synchronized

public synchronized boolean equals(java.lang.Object obj) {
//。。。
}

一看这就是通过工具生成的代码嘛。

并且老实说,synchronized这个东西我不熟,没用过,于是查资料。

找到以下一些资料

为什么用synchronized修饰的代码块里的代码执行的比普通代码慢?
应该 被synchronized 修饰的方法 是线程安全的,一次只能被一个线程使用,所以 相对其他方法 就慢!

关于synchronized锁和Spring事务

Java多线程总结之由synchronized说开去

关于程序加锁自己的一点见解:

建议程序中尽量不要加锁;
尽量在业务和代码层,解决线程安全的问题,实现无锁的线程安全;
如果以上两点都做不到,一定要加锁,尽量使用java.util.concurrent包下的锁(因为是非阻塞锁,基于CAS算法实现,具体可以查看AQS类的实现);
如果以上三点仍然都做不到,一定要加阻塞锁:synchronized锁,两个原则:(1)尽量减小锁粒度;(2)尽量减小锁的代码范围;
synchronized可能造成死锁。

Java Web 服务,第 3 部分: Axis2 数据绑定

不过,验证对性能具有很大的影响(正如您在下一篇文章中将看到的,即使不对每个文档调用 validate(),XMLBeans 也已经非常慢了)

内心一喜,删除所有的冗余代码,重新打包丢生产开始测试。

然并卵,仍然20S。

绝望。。。


我是成功的分割线


大神打开生产环境的wsdl服务地址,浏览器响应特别慢,我开始认为是因为生产环境cpu负载过高的问题,然而他打开其他的wsdl服务地址都特别快,于是决定从这里下手。

但是测试环境又特别快。

打开wsdl服务地址需要差不多6S,刷新一次也需要差不多6S。(我猜测是不是三次握手18秒再加程序处理1S这不刚好就凑齐了20S),于是确定是程序本身的问题。

最后,大神看了一眼axis2下的其他aar包都只有几十KB,而问题服务的包却高达5M,问我为啥这么大?

我说里面导入了很多jar包啊,并且有个叫axis的包。

大神看了一眼,说,会不会是jar包冲突啊?容器是axis2的。要不,干掉他?

我说,不要啊,我以前干掉这些jar包直接扔测试环境,过不去啊,报各种axis相关的错误啊。

大神说,试一试嘛。

于是就把纯class生成的aar,不包含任何jar包的aar扔到了测试环境。

我觉得要崩,服务起不来。

麻溜儿的重启进入tomcat,打开axis2服务列表,该服务好好的躺在那里。点开,正常。

我当场就懵逼了。

大神淡定的说了一句,他删除的冗余代码里面有很多类似这样的东西

public static org.apache.axis.description.TypeDesc getTypeDesc() {
return typeDesc;
}

我嘞个大X。

于是把这个aar直接丢生产,用soapui测试,第一次反馈仍然是17000ms,我对大神呵呵一笑。

大神不服,说,你再试一下。

第二次反馈,300ms。

WTF???

ok,确定了问题,就是那些冗余代码中的锁和axis包共同引起的。

结论:

1.代码中大量的synchronized导致某个线程锁,于是jstack看到某个线程占用CPU高达50%找到原因。

2.代码中的xmlbean和synchronized验证导致return之后的过程变慢。

3.怀疑axis和axis2同时存在的情况下有一定的阻塞或者冲突。

4.为什么在测试环境里面能保证1S以内,因为测试环境的axis2没有负载那么多active的服务。

记一次生产环境axis2服务特别慢的问题。的更多相关文章

  1. 记一次生产环境thrift服务的配置问题

    问题现象 有客户反馈我们的产品有时反应很慢,处理会出现超时. 问题分析过程 1.第一反应可能是用户增加,并发量太大了,询问了运营,最近用户注册数据并没有猛增. 2.分析access日志,发现有隔一段时 ...

  2. 如何将生产环境的服务Docker镜像拉取到本地进行调试

    背景 很多时候我们在将开发环境的代码推送到GitLab上面以后,我们在测试的时候发现了问题后无法通过现有的日志输出级别来定位问题,比如我们需要看EFCore生成的SQL语句,在生产环境我们是不可能输出 ...

  3. 记一次生产环境tomcat线程数打满情况分析

    前言 旨在分享工作中遇到的各种问题及解决思路与方案,与大家一起学习. -- 学无止境, 加油 ! Just do it ! 问题描述 运行环境描述 tomcat-8.5 单节点(该应用集群20个节点) ...

  4. [BI项目记]-搭建代码管理环境之服务端

    上一篇介绍如何搭建环境进行文档版本的管理,这篇主要介绍搭建环境进行代码版本的管理. 即使是BI项目也要进行代码版本管理.代码版本管理的工具有很多,VSS, SVN等都是当下大家经常提起的,这里主要介绍 ...

  5. 记一次生产环境Nginx日志骤增的问题排查过程

    摘要:众所周知,Nginx是目前最流行的Web Server之一,也广泛应用于负载均衡.反向代理等服务,但使用过程中可能因为对Nginx工作原理.变量含义理解错误,或是参数配置不当导致Nginx工作异 ...

  6. 记一次生产环境presto删表失败的问题

    场景,开发用java程序连接presto创建一个表,这个表在hdfs的权限为: 然后用presto去删除这个表 报错,没有权限删除,查看上一级目录权限,发现权限正常 直连hive删表 发现正常. 然后 ...

  7. 记一次生产环境nginx图片上传不了的问题

    在server节点目录下配置: client_max_body_size 8M; client_body_buffer_size 8M; 不过还是不能上传就执行下面这条命令: cd /var/lib/ ...

  8. django 生产环境部署建议

    参考django官方建议 一种优秀的作法是使用前缀/ws/来区分WebSocket连接和普通HTTP连接,以便修改配置后,使Channels更容易部署到生产环境中. 特别是对于大型站点,可以配置像ng ...

  9. S初始化生产环境数据

    一.将开发机的库文件导出10.10.1.139开发机服务器,桌面上的BAT文件,将数据库表结构和表数据导出来,导到E:\Repository,设置SADMIN密码永不过期BAT文件内容如下: ::导出 ...

随机推荐

  1. C++ string append方法的常用用法

    append函数是向string的后面追加字符或字符串. 1).向string的后面加C-string string s = “hello “; const char *c = “out here “ ...

  2. Only a type can be imported. classname resolves to a package的解决

    Only a type can be imported. l1.l2.MyClass resolves to a package ==========这里是解决方案=============== 把生 ...

  3. java 获取当前进程id 线程id

    java  获取当前进程id  线程id RuntimeMXBean (Java Platform SE 8 ) https://docs.oracle.com/javase/8/docs/api/j ...

  4. 原!上线遇到的问题, java序列化关键字transient 修饰的属性变成null了

    1.问题描述: 某个功能点,user对象 放入session,后再另外地方取出,结果某个字段没有了.再本地和测试环境都是ok的,但是线上环境就是不行. 后来看到这个user对象的那个属性是加了tran ...

  5. 洛谷P5151 HKE与他的小朋友 快速幂/图论+倍增

    正解:矩阵快速幂/tarjan+倍增 解题报告: 传送门! 跟着神仙做神仙题系列III 这题首先一看到就会想到快速幂趴?就会jio得,哦也不是很难哦 然而,看下数据范围,,,1×105,,,显然开不下 ...

  6. 【手机自动化测试】monkey测试

    1             概述 Monkey测试是Android自动化测试的一种手段.Monkey测试本身非常简单,就是模拟用户的按键输入,触摸屏输入,手势输入等,看设备多长时间会出异常. 当Mon ...

  7. Linux下如何执行Shell脚本

    Linux下你可以有两种方式执行Shell脚本: 1.用shell程序执行脚本:根据你的shell脚本的类型,选择shell程序,常用的有sh,bash,tcsh等(一般来说第一行#!/bin/bas ...

  8. 右值引用与转移语义(C++11)

    参考资料: http://www.cnblogs.com/lebronjames/p/3614773.html 左值和右值定义: C++( 包括 C) 中所有的表达式和变量要么是左值,要么是右值.通俗 ...

  9. JDBC连接数据库(二)

    原文地址https://blog.csdn.net/jq_ak47/article/details/55049639 Mysql for java 的JDBC 驱动库安装 1.将下载下来的5.1.40 ...

  10. 4.4 Routing -- Specifying A Route's Model

    一.概述 应用程序中,templates被models支持.但是templates是如何知道它们应该显示哪个model呢? 例如,你有一个photos模板,它是如何知道它该呈现哪个model呢? 这就 ...