项目性能优化经验--ZY项目
最近负责给公司某个ZY项目进行性能优化的一些经验分析
碰到问题:
1. 压力测试到100并发,任何一个场景CPU暴高,接近100%
查询jstack日志,发现大部分的线程block在tomcat 的 http11.connect 的poll方法上 或者是c3p0连接池的获取上
同时发现该项目数据库连接池配置了2000+,仍然不够用,100并发
分析原因: 数据库连接有问题
打开hibernate日志,关于transcation的
<logger name="org.hibernate.transaction" level="DEBUG"/>
<logger name="org.hibernate.cache" level="DEBUG"/>
<logger name="org.hibernate.type" level="DEBUG"/>
在logback.xml 中配置
然后本地运行代码,发现成百的下面日志
DEBUG org.hibernate.transaction.JDBCTransaction - begin
DEBUG org.hibernate.transaction.JDBCTransaction - current autocommit status: true
DEBUG org.hibernate.transaction.JDBCTransaction - disabling autocommit
DEBUG org.hibernate.transaction.JDBCTransaction - commit
这里显而易见出了问题,整个流程中怎么可能打开和关闭如此多的事务,要知道每次commit的时候都会去数据库连接池申请并释放连接,不要说2000,加个0都不够用
仔细查看代码,在整个系统DaoImpl的Base类上,被加了@Transcational 注释,同时几乎大部分的方法加了次注释
要知道,spring看到这个注释就会打开事物的,方法结束关闭事物
所以首先要做的就是,去掉多余的事物
将显而易见的事物去掉之后,系统性能显著提高,至少压倒500并发,CPU也只有在60-70%
2. 数据库连接依旧不够用
经过上面的调优,发现数据库连接池依旧不够用, 500并发以上,出现大量BLOCK 线程在等待数据库连接资源
需要继续调休代码
继续review日志
发现仍旧很多事物操作,特别是空事物操作(即打开关闭之间什么数据库操作都没有)
发现系统db操作框架仍旧有问题:
举例一:
@Transcational
public void delete(String ids...)
{
if( ids != null){
for(String id : ids){
delete(id);
}
}
}
这个方法有两个严重的问题:
1. 如果ids 为空 那么就会有一个空事物操作
2. 循环的一个个delete
第一个问题,可以通过提供一个统一的入口来判断,然后非空在进入到事物操作中
第二个问题,代码框架的不完整性,作为一个合适的base框架至少要对于delete要提供一套根据ID删,根据ID组删(用delete in list(ids)), delete 对象方法等,而不是简单的一个delete方法,任何其他delete都使用这个
再次清掉很多空数据库连接之后,系统数据库连接仍旧不够用
3. 继续找问题
轮到业务逻辑调整:
1. 连接数太多的问题
因为系统采用了 freemarker的框架, 在ftl的模板中涉及到了header和footer
这两个模板文件中,加入了对用户信息的查询请求,导致这个流程中对于/member/info.jhtml的调用多次出现,同时还有其他很多的请求,一个产品列表的页面,会导致8次jthml的连接请求,整个测试流程更是多达几十次的连接
所以,需要优化连接数量,减少连接,对于重复不必要的连接,将信息缓存在session中, 对于一些连接尽量能合并的合并
减少连接,能够连接建立和释放连接的开销(提高整体响应速度)
2. 查询太多
整个流程中,光是涉及到产品的查询及其级联查询多达5,6百条,不可忍受,绝对需要缓存,必须缓存
这样既可以提高每个线程db连接使用的时间,间接就提高了连接池连接释放的概率,降低了连接等待的可能
经过以上的代码调优,目前整个系统已经达到客户要求
整个系统代码框架为
html5(jquery) ----------freemarker ---------spring MVC --------memcached --------- hibernate ---------MYSQL
然后系统搭建
最外层 使用 nagix (主备) 转发请求
后台 tomcat 6 个集群
使用 mysql 中间件 Amoeba
mysql 做 读写分离 + 主备 (2 台 读 , 2台写)