当前位置: 首页 > 面试题库 >

使用Spring REST模板,创建过多的连接或速度慢

涂选
2023-03-14
问题内容

我有一个非常快速的RESTful服务。我正在本地主机上对其进行测试。客户端正在使用Spring REST模板。我从使用幼稚的方法开始:

RestTemplate restTemplate = new RestTemplate(Collections.singletonList(new GsonHttpMessageConverter()));

Result result = restTemplate.postForObject(url, payload, Result.class);

当我提出许多此类请求时,出现以下异常:

Caused by: org.springframework.web.client.ResourceAccessException: I/O error on POST request for "http://localhost:8080/myservice":No buffer space available (maximum connections reached?): connect; nested exception is java.net.SocketException: No buffer space available (maximum connections reached?): connect

这是由于未关闭连接并使其处于TIME_WAIT状态而引起的。当临时端口用尽时,该异常开始发生。然后执行将等待端口再次释放。我看到了长时间休息的最佳表现。我得到的速率几乎是我所需要的,但是这些TIME_WAIT连接当然不是很好。在Linux(Ubuntu
14)和Windows(7)上进行了测试,由于端口范围不同,在不同时间的结果相似。

为了解决这个问题,我尝试将Apache Http Components库中的HttpClient与HttpClientBuilder一起使用。

RestTemplate restTemplate = new RestTemplate(Collections.singletonList(new GsonHttpMessageConverter()));
HttpClient httpClient = HttpClientBuilder.create()
        .setMaxConnTotal(TOTAL)
        .setMaxConnPerRoute(PER_ROUTE)
        .build();
restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory(httpClient));

Result result = restTemplate.postForObject(url, payload, Result.class);

有了这个客户,我没有例外。客户端现在仅使用数量非常有限的临时端口。但是无论我使用什么设置(TOTAL和PER_ROUTE),都无法获得所需的性能。

使用该netstat命令,我发现到服务器的连接没有很多。我尝试将数字设置为数千,但似乎客户端从未使用过那么多。

有什么我可以做的以提高性能,而无需打开太多的连接?

更新:我尝试将总数和每条路由的连接数设置为5000和2500,但看起来客户端创建的总数不超过100(从判断netstat -n | wc -l)。REST服务是使用JAX-RS实现的,并在Jetty上运行。

UPDATE2:我现在已经用一些内存设置调整了服务器,并且我获得了非常好的吞吐量。天真的方法仍然要快一些,但我认为这只是客户端池中的一点开销。


问题答案:

实际上,Spring
Boot不会泄漏连接。您在这里看到的是Linux内核(以及每个主要OS)的标准行为。从机器上关闭的所有插座都会在TIME_WAIT一段时间内进入状态。这是为了防止使用该临时端口的下一个套接字接收实际上打算用于该端口上一个套接字的数据包。您看到的两者之间的差异是每个人采用的连接池方法的结果。

更具体地说,默认情况下RestTemplate
使用连接池。这意味着每个rest调用都会打开一个新的本地临时端口和一个到服务器的新连接。如果您的服务速度非常快,它将立即在可用的本地端口范围内爆炸。使用Apache
HttpClient,您可以利用连接池。这将防止您的应用程序看到您描述的问题。但是,鉴于您的服务能够比Linux内核从中取出套接字更快地做出响应TIME_WAIT,因此无论您做什么,连接池都会使您的客户端变慢(如果它没有使任何事情变慢,那么您就用光了本地临时端口)。

尽管可以在Linux内核中启用TCP重用,但这样做可能会很危险(数据包可能会延迟,并且临时端口可能会收到他们不了解的随机数据包,这可能会导致各种问题)。这里的解决方案是使用连接池,就像在第二个示例中一样,使用足够大的数量来达到接近您想要的性能。

为了帮助您调整连接池,您需要调整maxConnPerRoutemaxConnTotal参数。maxConnPerRoute限制将对单个IP:Port对maxTotal建立的连接数,并限制将永远打开的总连接数。在您的情况下,由于似乎所有请求都发送到同一位置,因此可以将它们设置为相同(较高)值。



 类似资料:
  • 我有一个非常快速的RESTful服务。我正在本地主机上测试它。客户端正在使用Spring REST模板。我从一个天真的方法开始: 当我提出很多这样的请求时,我得到了以下例外: 这是由于连接未关闭且挂起在TIME_WAIT状态造成的。当临时端口耗尽时,异常开始发生。然后执行等待端口再次空闲。我看到了长时间Rest的最佳表现。我得到的速度几乎是我所需要的,但当然,这些时间等待连接并不好。在Linux(

  • 我在编辑速度模板。它们用于生成PDF。问题是我不能预览它们。我看不出模板呈现时会是什么样子。有什么工具可以用来吗?我试过谷歌搜索,但什么也找不到。 另外,我知道如果我在本地加载它,它不会显示变量。我感兴趣的是知道它会是什么样子。布局等。,

  • 我正在将一个应用程序从WebSphere迁移到Tomcat,从Ant迁移到Maven。在此过程中,我们决定对Spring进行更新,并对较新的版本进行少量其他更新。该应用程序可以追溯到2005年。所以不是所有的,都是最新和最伟大的。 其中一个障碍是,迁移到Spring5.0,下降了对速度的支持。我们的应用程序广泛使用的工具。我们用的是Spring2.8之类的!:) 现在,我看到这些声明:

  • 我是Java Spring的新手,学习JDBC模板来访问数据库。现在我有3个关系表,我需要使用JDBC模板连接它们,并需要打印结果。我如何实现它。任何可行的例子都会对我有很大帮助。 谢谢

  • 问题内容: 下面的代码通过SSH在一台计算机上运行grep并打印结果: 我如何一次将5台机器全部置入grep(这样就不会造成重大延迟),而不是将所有这些都放入5个变量中并全部打印出来。 问题答案: 您需要将调用放在单独的线程(或进程中,但这可能会过大),这反过来又要求代码位于函数中(无论如何,这是一个好主意:模块的顶部没有大量代码水平)。 例如: If you had many more than