一直維護着舊游戲服務器 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千人時候,也有不少空閑線程.登錄游戲響應有明顯提升
至於改動后性能測試,大家可以自己測試咯。主要是分享解決思路。