摘要:本文旨在指出中集成的一些性能陷阱,在另一篇文章各組件詳解里有組件介紹及如何正確使用的內(nèi)容。因此的做法會大大降低性能,并且將大部分的時間都花在反復(fù)重建這些對象上。提供的可以讓使用避免頻繁創(chuàng)建的問題。至于使用的性能測試則留給同學(xué)自己做了。
Github
本文旨在指出Spring/Spring Boot中集成JMS的一些性能陷阱,在另一篇文章Spring JMS各組件詳解里有Spring JMS組件介紹及如何正確使用的內(nèi)容。
JmsTemplate性能問題Spring提供了JmsTemplate用來簡化JMS的操作,但是JmsTemplate的性能是有很大問題的,主要體現(xiàn)在以下幾個方面:
頻繁創(chuàng)建connection,session,producer根據(jù)Artemis官方文檔的說法,JmsTemplate是一種anti-pattern,如果在使用JmsTemplate的情況下覺得很慢,那么就不要怪Artemis。
并且Connection,Session,Producer,Consumer這些對象本身設(shè)計上是可以復(fù)用的。因此JmsTemplate的做法會大大降低性能,并且將大部分的時間都花在反復(fù)重建這些對象上。
Spring提供的Workaround
可以讓JmsTemplate使用SingleConnectionFactory避免頻繁創(chuàng)建Connection的問題。或者其子類CachingConnectionFactory避免頻繁創(chuàng)建Connection,Session,Producer,Consumer的問題。
頻繁創(chuàng)建臨時QueueJmsTemplate#sendAndReceive方法可以用來模擬RPC調(diào)用過程,內(nèi)部原理是:
A程序創(chuàng)建一個臨時Queue作為接受相應(yīng)的Queue
send一個Message到Queue,并在這個臨時Queue上等待結(jié)果
B程序consume了這個Message把結(jié)果send到那個臨時Queue
A接受到結(jié)果,把這個臨時Queue干掉
當(dāng)然整個過程中還包括前面提到的創(chuàng)建Connection,Session,Producer,Consumer的動作。
不出所料,Artemis官方文檔也提到了,頻繁創(chuàng)建臨時Queue是一種anti-pattern,會大大影響性能。
@JmsListener性能問題 使用sync方法consume消息使用@JmsListener注解可以很方便的用來consume消息,但它是同步而非異步,這個和官方文檔所說的恰恰相反(關(guān)于sync/async consume消息的資料)。
Spring Boot的JmsAnnotationDrivenConfiguration默認(rèn)使用DefaultJmsListenerContainerFactory生成DefaultMessageListenerContainer ,而它的內(nèi)部原理是使用TaskExecutor發(fā)起多個線程同時從Queue中拉取消息,這也就是為什么Spring官方文檔里說如果監(jiān)聽的是Topic且concurrency > 1,那么可能會收到重復(fù)消息的原因。
DefaultMessageListenerContainer的javadoc中說道:
Actual MessageListener execution happens in asynchronous work units which are created through Spring"s TaskExecutor abstraction
這里就有個矛盾,如果使用async的方式consume消息,那么只需給consumer設(shè)置MessageListener就行了,何必使用TaskExecutor呢?
一看代碼果然不出所料:
DefaultMessageListenerContainer#runcallinvokeListener
然后callAbstractPollingMessageListenerContainer#receiveAndExecute
然后calldoReceiveAndExecute
然后callreceiveMessage
然后callreceiveFromConsumer
然后callJmsDestinationAccessor#receiveFromConsumer這個方法調(diào)用了MessageConsumer#consume
也就是說Spring只是使用一個或多個線程在不停的同步的consume消息而已。
雖然可以使用concurrency參數(shù)提高并發(fā),但是多線程從Queue/Topic中consume消息的性能比javax.jms.MessageConsumer#setMessageListener的方法要低上很多。
有興趣的同學(xué)可以使用Artemis Example(下載地址)里的JMS Perf代碼做一下測試,它的測試代碼用的是javax.jms.MessageConsumer#setMessageListener的方式來consume消息的,在配置正確的情況下可以達(dá)到接近10w/s。至于使用MessageConsumer.receive的性能測試則留給同學(xué)自己做了。
為@JmsListener創(chuàng)建的session默認(rèn)transacted=true還是之前提到的JmsAnnotationDrivenConfiguration,使用的DefaultJmsListenerContainerFactoryConfigurer默認(rèn)是把session設(shè)置為transacted的。
根據(jù)測算,當(dāng)一個session是transacted的時候其性能會相差20%,有興趣的同學(xué)可以使用Artemis Example(下載地址)里的JMS Perf代碼做一下測試。
下載之后找到examples/jms/perf目錄,看這個目錄下的readme.html獲得執(zhí)行方法,在執(zhí)行之前修改src/main/resources/perf.properties文件,下面是部分參數(shù)的解釋:
num-messages,測試多少個消息
num-warmup-messages,熱身用的消息數(shù),熱身過之后性能會提升
durable,對應(yīng)DeliveryMode
transacted,是否transacted
batch-size,批量commit的大小
drain-queue,是否測試前先把隊列里已有的消息都清空
可以使用以下兩套配置對比transacted的性能差別:
配置一,transacted=false:
num-messages=100000 num-warmup-messages=1000 message-size=1024 durable=false transacted=false batch-size=1 drain-queue=true destination-lookup=perfQueue connection-factory-lookup=/ConnectionFactory throttle-rate=-1 dups-ok-acknowledge=false disable-message-id=true disable-message-timestamp=true
配置二,transacted=true:
num-messages=100000 num-warmup-messages=1000 message-size=1024 durable=false transacted=true batch-size=1 drain-queue=true destination-lookup=perfQueue connection-factory-lookup=/ConnectionFactory throttle-rate=-1 dups-ok-acknowledge=false disable-message-id=true disable-message-timestamp=true@JmsListener創(chuàng)建的session默認(rèn)加入了事務(wù)控制
關(guān)于加入事務(wù)控制是否會有性能問題沒有實際測試過,不過值得注意的這是Spring Boot的默認(rèn)行為。
相關(guān)連接:代碼1, 代碼2,代碼3,Javadoc。
Spring Boot配置 ConnectionFactory全局只有一個實例Spring將JMS的集成變得非常簡單,只需提供幾個配置參數(shù)就可以了,但是只能提供一種默認(rèn)配置,不管業(yè)務(wù)場景如何都使用同一種配置是非常有問題的。
spring-boot提供了以下幾種方式(文檔)集成JMS:
JNDI
Artemis, native模式和embedded模式
ActiveMQ
這幾種模式的缺點都是只能配置一個ConnectionFactory,這對于簡單應(yīng)用來說沒問題,對于復(fù)雜應(yīng)用來說就顯得不夠用了,這讓你喪失了針對不同場景配置不同ConnectionFactory的機(jī)會。
而且Artemis的native模式只支持host:port,不支持更豐富參數(shù)的url模式。
看過DefaultJmsListenerContainerFactoryConfigurer和JmsAnnotationDrivenConfiguration的代碼就明白了。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/64939.html
摘要:除此之外,還為不同的應(yīng)用程序體系結(jié)構(gòu)提供了基礎(chǔ)支持,包括消息傳遞事務(wù)數(shù)據(jù)和持久性以及,它還包括基于的框架,以及與之并行的反應(yīng)性框架。還支持依賴項注入和公共注解規(guī)范,應(yīng)用程序開發(fā)人員可以選擇使用這些規(guī)范,而不是提供的特定于的機(jī)制。 概述 Spring使創(chuàng)建Java企業(yè)應(yīng)用程序變得很容易,它提供了在企業(yè)環(huán)境中使用Java語言所需要的一切,支持Groovy和Kotlin作為JVM上的替代語言...
摘要:地址前面一個部分講解了如何使用工具來測試項目,現(xiàn)在我們講解如何使用工具來測試項目。所以我們可以利用這個特性來進(jìn)一步簡化測試代碼。因為只有這樣才能夠在測試環(huán)境下發(fā)現(xiàn)生產(chǎn)環(huán)境的問題,也避免出現(xiàn)一些因為配置不同導(dǎo)致的奇怪問題。 Github地址 前面一個部分講解了如何使用Spring Testing工具來測試Spring項目,現(xiàn)在我們講解如何使用Spring Boot Testing工具來測...
摘要:會話管理一直是企業(yè)級應(yīng)用的重要部分。傳統(tǒng)會話管理技術(shù)的問題的目的是解決傳統(tǒng)的會話管理技術(shù)的各種問題。對如和之類的閉源產(chǎn)品,找到適合它們的會話管理技術(shù)的替代實現(xiàn)則通常是不可能的。典型的應(yīng)用會將當(dāng)前用戶的身份及其安全級別或角色存儲在會話里面。 歡迎大家前往騰訊云+社區(qū),獲取更多騰訊海量技術(shù)實踐干貨哦~ 本文來自云+社區(qū)翻譯社,由Tnecesoc編譯。 會話管理一直是 Java 企業(yè)級應(yīng)用的...
摘要:基于工廠,會有多種應(yīng)用上下文的實現(xiàn)的模塊在模塊中,面向切面編程提供了豐富的支持,該模塊是應(yīng)用系統(tǒng)中開發(fā)切面的基礎(chǔ),可以幫助應(yīng)用對象解耦。的主頁安全對于許多應(yīng)用都是一個非常關(guān)鍵的切面。 簡化Java開發(fā) JavaBean:Enterprise JavaBean、EJBJDO:Java數(shù)據(jù)對象、Java Data ObjectPOJO:Plain Old Java ObjectDI:依賴注...
閱讀 3327·2021-11-18 10:02
閱讀 1546·2021-10-12 10:08
閱讀 1368·2021-10-11 10:58
閱讀 1354·2021-10-11 10:57
閱讀 1255·2021-10-08 10:04
閱讀 2200·2021-09-29 09:35
閱讀 848·2021-09-22 15:44
閱讀 1343·2021-09-03 10:30