所以,我在spring jms 50-100中使用了并发性,允许最大连接数达到200。一切都按预期工作,但是如果我尝试从队列中检索100k消息,我的意思是我的sqs上有10万条消息,我正在阅读它们通过spring jms正常方法。
@JmsListener
Public void process (String message) {
count++;
Println (count);
//code
}
我在控制台中看到了所有日志,但是大约17k之后,它开始引发异常
类似的东西:aws sdk异常:端口已在使用中。
为什么我会看到此异常以及如何处理。我摆脱了吗?
我尝试在互联网上寻找它。什么都找不到。
我的设置:
并发50-100
每个任务设置消息数:50
客户确认
timestamp=10:27:57.183, level=WARN , logger=c.a.s.j.SQSMessageConsumerPrefetch, message={ConsumerPrefetchThread-30} Encountered exception during receive in ConsumerPrefetch thread,
javax.jms.JMSException: AmazonClientException: receiveMessage.
at com.amazon.sqs.javamessaging.AmazonSQSMessagingClientWrapper.handleException(AmazonSQSMessagingClientWrapper.java:422)
at com.amazon.sqs.javamessaging.AmazonSQSMessagingClientWrapper.receiveMessage(AmazonSQSMessagingClientWrapper.java:339)
at com.amazon.sqs.javamessaging.SQSMessageConsumerPrefetch.getMessages(SQSMessageConsumerPrefetch.java:248)
at com.amazon.sqs.javamessaging.SQSMessageConsumerPrefetch.run(SQSMessageConsumerPrefetch.java:207)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Caused by: com.amazonaws.SdkClientException: Unable to execute HTTP request: Address already in use: connect
更新:我一直在寻找问题,似乎正在创建新的套接字,直到每个套接字都用完为止。
我的spring jms版本应该是4.3.10
要复制此问题,只需执行上述配置,最大连接数为200,货币设置为50-100,并将40k消息推送到sqs队列。一个人可以使用https://github.com/adamw/elasticmq作为本地堆栈服务器复制到Amazon sqs。注释jms侦听器并使用soap ui负载测试,并调用发送消息以激发许多消息。仅仅因为您评论了@jmslistener批注,它就不会占用队列中的消息。看到您已发送40k消息后,请停止。取消注释@jmslistener并重新启动服务器。
更新:
DefaultJmsListenerContainerFactory factory =
new DefaultJmsListenerContainerFactory();
factory.setConnectionFactory(connectionFactory);
factory.setDestinationResolver(new DynamicDestinationResolver());
factory.setErrorHandler(Throwable::printStackTrace);
factory.setConcurrency("50-100");
factory.setSessionAcknowledgeMode(Session.CLIENT_ACKNOWLEDGE);
return factory;
更新:
SQSConnectionFactory connectionFactory = new SQSConnectionFactory( new ProviderConfiguration(), amazonSQSclient);
更新:
客户端配置详细信息:
Protocol : HTTP
Max connections : 200
更新:
我使用了缓存连接工厂类,看来。我阅读了堆栈溢出及其官方文档,以不使用缓存连接工厂类和默认的jms侦听器容器工厂。
https://stackoverflow.com/a/21989895/5871514
它给出了我之前遇到的相同错误。
更新
我的目标是要获得500 tps,即我应该能够消耗那么多。.所以我尝试了这种方法,看来我可以达到100-200,但不超过此数量。高并发阻塞..如果您使用它..如果您有更好的解决方案来实现它..我很高兴。
**已更新**
我正在使用amazonsqsclient
答案 0 :(得分:4)
饥饿的消费者
JMS客户端倾向于实现的一种可能的优化是消息消耗缓冲区或“预取”。有时可以通过消息数量或字节大小来调整此缓冲区。
这样做的目的是防止使用者每次收到消息时都去服务器,而不是批量提取多条消息。
在有许多“快速使用者”(这些库可能采取的观点)的环境中,此预取设置为较高的默认值,以最大程度地减少这些往返行程。
但是,在消息使用者较慢的环境中,这种预取可能是个问题。较慢的使用者正在阻止较快的使用者从预取的消息中消耗消息。在高度并发的环境中,这可能会迅速导致饥饿。
在这种情况下,SQSConnectionFactory
有一个property for this:
SQSConnectionFactory sqsConnectionFactory = new SQSConnectionFactory( new ProviderConfiguration(), amazonSQSclient);
sqsConnectionFactory.setNumberOfMessagesToPrefetch(0);
生产者的饥饿(即通过JmsTemplate
)
这些JMS实现通常期望通过某些中介与代理接口。这些中介实际上缓存和重用连接,或者使用池化机制重用它们。在Java EE世界中,这通常是通过Java EE服务器上的JCA适配器或其他方法来解决的。
由于Spring JMS的工作方式,它希望存在ConnectionFactory
的中间代理来进行此缓存/池化。否则,当Spring JMS要连接到代理时,每次您想对代理进行操作时,它将尝试打开新的连接和会话(!)。
为解决此问题,Spring提供了一些选项。最简单的是CachingConnectionFactory
,它缓存单个Connection
,并允许在该Session
上打开许多Connection
。将其添加到上面的@Configuration
的简单方法是:
@Bean
public ConnectionFactory connectionFactory(AmazonSQSClient amazonSQSclient) {
SQSConnectionFactory sqsConnectionFactory = new SQSConnectionFactory(new ProviderConfiguration(), amazonSQSclient);
// Doing the following is key!
CachingConnectionFactory connectionfactory = new CachingConnectionFactory();
connectionfactory.setTargetConnectionFactory(sqsConnectionFactory);
// Set the #connectionfactory properties to your liking here...
return connectionFactory;
}
如果您希望将其作为JMS池解决方案的更多选择(除了多个Connections
之外还将为您池MessageProducer
和Session
),可以使用相当新的PooledJMS project的JmsPoolConnectionFactory
等来自他们的库。