将spring用于高并发环境的隐忧 -凯发k8网页登录

 

将spring用于高并发环境的隐忧

最近协助一些bea客户做调优,他们使用了spring,出现了各种各样的性能问题,这些问题其实都是不容易重现的,其中,我自己捕获了一些threaddump,并report了给spring jira。这个case的情况是:spring会偶然出现cpu 100%的情况,weblogic server崩溃,我后来分析了线程dump,觉得是一种lock contention的情形,幸好,很快给我fixed了这个bug:


使用java编程的同学都建议review一下,呵呵:

这是2.5.4以前的代码:

/**
* cache of transactionattributes, keyed by defaultcachekey (method   target class).

as this base class is not marked serializable, the cache will be recreated
* after serialization - provided that the concrete subclass is serializable.
*/
final  map attributecache  =   new  hashmap();

/**
* determine the transaction attribute for this method invocation.

defaults to the class's transaction attribute if no method attribute is found.
@param  method the method for the current invocation (never null)
@param  targetclass the target class for this invocation (may be null)
@return  transactionattribute for this method, or null if the method
* is not transactional
*/
public  transactionattribute gettransactionattribute(method method, class targetclass) {
//  first, see if we have a cached value.
object cachekey  =  getcachekey(method, targetclass);
synchronized  ( this .attributecache) {
object cached 
=   this .attributecache.get(cachekey);
if  (cached  !=   null ) {
//  value will either be canonical value indicating there is no transaction attribute,
//  or an actual transaction attribute.
if  (cached  ==  null_transaction_attribute) {
return   null ;
}
else  {
return  (transactionattribute) cached;
}
}
else  {
//  we need to work it out.
transactionattribute txatt  =  computetransactionattribute(method, targetclass);
//  put it in the cache.
if  (txatt  ==   null ) {
this .attributecache.put(cachekey, null_transaction_attribute);
}
else  {
if  (logger.isdebugenabled()) {
logger.debug(
" adding transactional method [ "    method.getname()    " ] with attribute [ "    txatt    " ] " );
}
this .attributecache.put(cachekey, txatt);
}
return  txatt;
}
}
}


这是2.5.4 fixed后的代码:

     /**
     * cache of transactionattributes, keyed by defaultcachekey (method   target class).
     * 

as this base class is not marked serializable, the cache will be recreated
     * after serialization - provided that the concrete subclass is serializable.
      */
    
final  map attributecache  =  collectionfactory.createconcurrentmapifpossible( 16 );


    
/**
     * determine the transaction attribute for this method invocation.
     * 

defaults to the class's transaction attribute if no method attribute is found.
     *  @param  method the method for the current invocation (never null)
     * 
@param  targetclass the target class for this invocation (may be null)
     * 
@return  transactionattribute for this method, or null if the method
     * is not transactional
     
*/
    
public  transactionattribute gettransactionattribute(method method, class targetclass) {
        
//  first, see if we have a cached value.
        object cachekey  =  getcachekey(method, targetclass);
        object cached 
=   this .attributecache.get(cachekey);
        
if  (cached  !=   null ) {
            
//  value will either be canonical value indicating there is no transaction attribute,
            
//  or an actual transaction attribute.
             if  (cached  ==  null_transaction_attribute) {
                
return   null ;
            }
            
else  {
                
return  (transactionattribute) cached;
            }
        }
        
else  {
            
//  we need to work it out.
            transactionattribute txatt  =  computetransactionattribute(method, targetclass);
            
//  put it in the cache.
             if  (txatt  ==   null ) {
                
this .attributecache.put(cachekey, null_transaction_attribute);
            }
            
else  {
                
if  (logger.isdebugenabled()) {
                    logger.debug(
" adding transactional method [ "    method.getname()    " ] with attribute [ "    txatt    " ] " );
                }
                
this .attributecache.put(cachekey, txatt);
            }
            
return  txatt;
        }
    }


但是2.5.4 snapshot是未经很好测试的版本,客户一般不太敢用。
我不知道其实有多少客户真正地把spring投入到高并发性环境下使用,
如果有,他们应该会能碰到我所碰到的情形。

posted on 2008-04-19 09:47 david.turing 阅读(10964) 评论(21)  编辑  收藏 所属分类: bea新闻频道

# re: 将spring用于高并发环境的隐忧[未登录] 2008-04-19 10:03

没错,我们以前的公司也是weblogic hibernate,出了性能问题了,虽然调整解决了,但不管怎么说,因为这些开源软件之前开发的时候并没有考虑高并发和集群的情况,还是比较容易出现问题的,尤其是没有经过严格的压力测试。我个人认为,目前做的比较好的软件,依然是商业的。  回复     

# re: 将spring用于高并发环境的隐忧 2008-04-19 10:56

1. 的确,许多开源软件在版本发布之前是否有能力去做高并发压力测试,值得怀疑
2. 我想,看到david这次发现的问题,用户更应该当心的是下次如果某个开源产品出了问题怎么办。
3. 不过目前来说是,不是“用不用开源的问题”(可以是一定要用),而是“用了开源怎么办”的问题。所以这是开源商业模式的一个机会,比如david就可以去做开源调优的凯发k8网页登录的服务支持了,哈
4. 这篇blog在我的firefox 3.0b5下排版混乱,不得不到ie下面来留言  回复     

# re: 将spring用于高并发环境的隐忧[未登录] 2008-04-19 17:43

我一直认为开源代码是用来学习的,实际项目中还是不要用的好。  回复     

# re: 将spring用于高并发环境的隐忧[未登录] 2008-04-19 21:08

我很想知道在spring1.2.9或spring2.0.8有没有这个问题  回复     

# re: 将spring用于高并发环境的隐忧 2008-04-20 13:24

@flyisland
firefox不仅仅3.0乱,2.0也乱,于是ie留言之。  回复     

# re: 将spring用于高并发环境的隐忧[未登录] 2008-04-20 18:29

@af
你能担保自己写的就可以解决掉所有问题?  回复     

# re: 将spring用于高并发环境的隐忧 2008-04-21 18:05

我用firefox 2.0.0.13浏览本文再正常不过了  回复     

# re: 将spring用于高并发环境的隐忧 2008-04-21 21:44

new hashmap();

这个本来就不是线程安全的东东。。。
在写高并发程序的时候用脚后脚想想就知道了。。。:)  回复     

# re: 将spring用于高并发环境的隐忧 2008-04-22 10:16 david.turing

说的没错,任何优秀的产品都会有bug,但除非用的场景足够多和复杂,否则某些严重的bug还是会隐藏的很深。  回复     

# re: 将spring用于高并发环境的隐忧[未登录] 2008-04-22 12:36

你们以为websphere,weblogic就不会有这样的问题了吗??  回复     

# re: 将spring用于高并发环境的隐忧 2008-04-22 17:41

@af
呵呵,我是不同意最好不用开源软件的观点。商业软件也同样会有问题,只不过可能隐藏的更深而已。自己写就更不用说了,重复造轮子不说,也许还造的不如人家的圆。
  回复     

# re: 将spring用于高并发环境的隐忧 2008-04-22 17:49

这算是历史的遗留问题吧,spring应该使用java5的api重写了,至少还和guice有一。,开源问题太多了,以前经常和spring team的人扯皮一些小问题,不过我写代码的质量远不如他们写的  回复     

# re: 将spring用于高并发环境的隐忧 2008-04-23 11:01 david.turing

邢总说对了,佩服。不过,厂家的支持会让spring更适用于商业化。未来的weblogic版本(essex),应该对spring有较大的优化,包括:

1, 基于spring的部署方式实现本地wls部署,我们可以将spring module实现weblogic.application.module接口,即可让spring模块享受weblogic的2阶段部署的特性。

2, 一些预配置的beans能够无需spring配置声明即可注入到spring应用中,applicationcontext看上去会简洁很多

3, 为beans提供scope,比如clusteringscope,以便支持集群技术

4, weblogic consle展示spring应用的runtimembeans

5, 9.2之后wldf可以用于上面的runtimembeans,可以定期抓取runtime信息了

6, spring应用默认支持openjpa作为持久层支持,当然,kodo、hibernate切换也是简单的
  回复     

# re: 将spring用于高并发环境的隐忧 2008-04-23 13:34

修正后的代码,满足不了之前的并发需求吧??  回复     

# re: 将spring用于高并发环境的隐忧 2008-04-23 13:59

是呀,第一段代码能够保证同一个transactionattribute只被创建一次,而第二段代码无法做到吧?有可能同一个transactionattribute被创建多次,然后被put到map中覆盖。  回复     

# re: 将spring用于高并发环境的隐忧[未登录] 2008-04-24 13:05

1.5的concurrent hashmap产生的用途就是为了hashmap同步  回复     

# re: 将spring用于高并发环境的隐忧 2008-04-24 18:55

@david.turing

确实是同步,但是它只能保证多个线程在同时操作map时保证同步,但是上面的第一段代码是分两步来操作map的  回复     

# re: 将spring用于高并发环境的隐忧[未登录] 2008-05-18 17:59

朋友是bea的? 。。。 我们公司用了spring作了框架 然后再weblogic中 redeploy的话似乎spring的context没有被销毁。 我们已经在listener中调用了context的关闭销毁方法但是似乎没啥效果。。。 redeploy多次后java heap就不行了。。。 不知道其他地方有没有这种情况?????  回复     

# re: 将spring用于高并发环境的隐忧 2008-06-14 09:49 david.turing

典型的部署期泄露,这种有可能是spring的bug,它可能没有正确实现j2ee的context销毁接口。  回复     

# re: 将spring用于高并发环境的隐忧 2009-06-17 14:14

(web server软件)ufo不会出现一个字节的内存泄漏和一个线程的不能回收,使用ufo做web server的好处是网站能做得很稳定,永远也不会自己down掉;ufo在托管机房丢包率很高、遭受hacker攻击、互联网 骨干网被黑等恶劣的环境条件下仍然能很好地运行;ufo在对付hacker方面(防hacker弄down和hacker抓取不该访问的资源)也有足够措施。
另外,ufo几乎不会进行垃圾回收,消耗cpu很少,在普通的pc server上用ufo运行网站,平时cpu占用率<0.1%,最多时也不会超 过5%。您知道,jvm的垃圾回收会导致大量的运算,消耗很多cpu,从而导致server的负载能力和响应速度下降。ufo在对象管理方面采 用了很好的机制和算法,做得很出色。用ufo运行网站,可以一直保证高负载能力,快速的响应速度和低cpu消耗。发布网址:www.gm365.com
  回复     

# re: 将spring用于高并发环境的隐忧[未登录] 2014-05-14 17:12

@flyisland
我也混乱了,ff29.  回复     

导航

统计

常用链接

留言簿(109)

我参与的团队

随笔分类(126)

随笔档案(155)

文章分类(9)

文章档案(19)

相册

搜索

积分与排名

最新随笔

最新评论

阅读排行榜

评论排行榜

网站地图