一直维护着旧游戏服务器 java写的,一台服务器还有3,4千人在线,看来老外还蛮怀旧的。
服务器出现无法登录时候,在服务器JDB 记录下多线程调用堆栈记录 以下是出现次数最多堆栈
[1] com.mchange.v2.resourcepool.BasicResourcePool.checkoutResource (BasicResourcePool.java:201)
[2] com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool.checkoutPooledConnection (C3P0PooledConnectionPool.java:232)
[3] com.mchange.v2.c3p0.PoolBackedDataSource.getConnection (PoolBackedDataSource.java:94)
[4] com.mchange.v2.c3p0.ComboPooledDataSource.getConnection (ComboPooledDataSource.java:521)
[5] org.springframework.orm.hibernate3.LocalDataSourceConnectionProvider.getConnection (LocalDataSourceConnectionProvider.java:82)
[6] org.hibernate.jdbc.ConnectionManager.openConnection (ConnectionManager.java:417)
[7] org.hibernate.jdbc.ConnectionManager.getConnection (ConnectionManager.java:144)
[8] org.hibernate.jdbc.JDBCContext.connection (JDBCContext.java:119)
[9] org.hibernate.transaction.JDBCTransaction.begin (JDBCTransaction.java:57)
[10] org.hibernate.impl.SessionImpl.beginTransaction (SessionImpl.java:1,326)
[11] org.springframework.orm.hibernate3.HibernateTransactionManager.doBegin (HibernateTransactionManager.java:558)
[12] org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction (AbstractPlatformTransactionManager.java:374)
[13] org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary (TransactionAspectSupport.java:263)
[14] org.springframework.transaction.interceptor.TransactionInterceptor.invoke (TransactionInterceptor.java:101)
[15] org.springframework.aop.framework.ReflectiveMethodInvocation.proceed (ReflectiveMethodInvocation.java:171)
[16] org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept (Cglib2AopProxy.java:635)
看堆栈调用线程多阻塞在获取数据库连接时候,我查过数据配置连接池100-500 ,运行线程数量也没那么多,线程池里面数据库连接应该 没有用光的
查看了[1] com.mchange.v2.resourcepool.BasicResourcePool.checkoutResource (BasicResourcePool.java:201)行代码其实是同步函数 .
网上对synchronized 解析如下
当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块
网上搜索下类似问题,可以改成用jdbc来操作DB,效率也高,不过我不想改动太多代码,毕竟是老项目,改太多会造成不稳定
所以我想可不可以这样。减少对连接池的getConnection 调用,这样减少c3p0的线程阻塞,按照这样思路我把频繁调用保存DB的代码改成批量保存。
单独开个线程缓存对象列表 ,然后批量保存,代码如下,
@Override
public void saveListTransingTrade(final List<TransingTrade> listpo) {
// TODO Auto-generated method stub
hibernateTemplate.execute(new HibernateCallback() {
@Override
public Object doInHibernate(Session arg0) throws HibernateException,
SQLException {
// TODO Auto-generated method stub
long start=System.currentTimeMillis();
int count = 0;
for(TransingTrade t:listpo)
{
hibernateTemplate.saveOrUpdate(t);
if(count > 0&& count%SovtConfig.getInstance().getBatchsavecount() == 0)
{
arg0.flush();
arg0.clear();
}
count++;
}
arg0.flush();
arg0.clear();
log.error("batch save TransingTrade:" + listpo.size() + ",cost:"+(System.currentTimeMillis()-start));
return null;
}
});
}
改动经过测试后,放在公网运行后,发现即使在线人数3,4千人时候,也有不少空闲线程.登录游戏响应有明显提升
至于改动后性能测试,大家可以自己测试咯。主要是分享解决思路。