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