將Spring用于高并發環境的隱憂
最近協助一些BEA客戶做調優,他們使用了Spring,出現了各種各樣的性能問題,這些問題其實都是不容易重現的,其中,我自己捕獲了一些ThreadDump,并report了給Spring JIRA。這個Case的情況是:Spring會偶然出現CPU 100%的情況,WebLogic Server崩潰,我后來分析了線程Dump,覺得是一種Lock Contention的情形,幸好,Juergen Hoeller很快給我Fixed了這個Bug:
http://jira.springframework.org/browse/SPR-4664
使用Java編程的同學都建議Review一下,呵呵:
這是2.5.4以前的代碼:
*?Cache?of?TransactionAttributes,?keyed?by?DefaultCacheKey?(Method?+?target?Class).
*?<p>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.
*?<p>Defaults?to?the?class's?transaction?attribute?if?no?method?attribute?is?found.
*? @param ?method?the?method?for?the?current?invocation?(never?<code>null</code>)
*? @param ?targetClass?the?target?class?for?this?invocation?(may?be?<code>null</code>)
*? @return ?TransactionAttribute?for?this?method,?or?<code>null</code>?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).
?????*?<p>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.
?????*?<p>Defaults?to?the?class's?transaction?attribute?if?no?method?attribute?is?found.
?????*? @param ?method?the?method?for?the?current?invocation?(never?<code>null</code>)
?????*? @param ?targetClass?the?target?class?for?this?invocation?(may?be?<code>null</code>)
?????*? @return ?TransactionAttribute?for?this?method,?or?<code>null</code>?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 閱讀(11100) 評論(21) 編輯 收藏 所屬分類: BEA新聞頻道