加载测试BindException

时间:2018-02-15 05:22:49

标签: java rest spring-boot weblogic load-testing

我们有2个APP,其中一个是服务器,另一个是客户端。

服务器在weblogic(APP A)上,客户端在spring-boot上(在tomcat上 - APP B)。当我们正在进行负载测试时,A向B发送请求。但是在某一点之后有一段时间出现了Bind Exception错误,比负载测试保持正常运行,比Bind Exception,正常等等。如果我们做加载测试更高的TPS我们更频繁地得到这些例外。这是场景:

  • 负载测试继续运行,无错误,300 TPS,消息计数10.000
  • 负载测试继续运行,无错误,300 TPS,消息数30.000
  • Bind Exception,300 TPS,mesasge count 32.000
  • 负载测试继续运行,无错误,300 TPS,消息计数40.000
  • 负载测试继续运行,无错误,300 TPS,消息计数50.000
  • Bind Exception,300 TPS,mesasge count 52.000
  • 负载测试继续运行,无错误,300 TPS,消息计数60.000 ... ...

错误是:

org.springframework.web.client.ResourceAccessException: I/O error on POST request for "http://XXXXXXX:9090/api/8252": Cannot assign requested address; nested exception is java.net.BindException: Cannot assign requested address
        at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:666)
        at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:613)
        at org.springframework.web.client.RestTemplate.postForLocation(RestTemplate.java:355)
        at com.ttech.tims.tes.pushws.impl.PushConsumerThread.tryToSendPushRequest(PushConsumerThread.java:207)
        at com.ttech.tims.tes.pushws.impl.PushConsumerThread.pushMessage(PushConsumerThread.java:162)
        at com.ttech.tims.tes.pushws.impl.PushConsumerThread.run(PushConsumerThread.java:350)
        at java.lang.Thread.run(Thread.java:745)
Caused by: java.net.BindException: Cannot assign requested address
        at sun.nio.ch.Net.connect0(Native Method)
        at sun.nio.ch.Net.connect(Net.java:454)
       at sun.nio.ch.Net.connect(Net.java:446)
        at sun.nio.ch.SocketChannelImpl.connect(SocketChannelImpl.java:648)
        at weblogic.socket.NIOSocketMuxer.newSocket(NIOSocketMuxer.java:432)
        at weblogic.socket.NIOSocketMuxer.newSocket(NIOSocketMuxer.java:364)
        at weblogic.socket.ChannelSocketFactory.createSocket(ChannelSocketFactory.java:98)
        at weblogic.net.http.HttpClient.openServer(HttpClient.java:384)
        at weblogic.net.http.HttpClient.openServer(HttpClient.java:511)
        at weblogic.net.http.HttpClient.New(HttpClient.java:313)
        at weblogic.net.http.HttpClient.New(HttpClient.java:292)
        at weblogic.net.http.HttpURLConnection.connect(HttpURLConnection.java:295)
        at org.springframework.http.client.SimpleBufferingClientHttpRequest.executeInternal(SimpleBufferingClientHttpRequest.java:78)
        at org.springframework.http.client.AbstractBufferingClientHttpRequest.executeInternal(AbstractBufferingClientHttpRequest.java:48)
        at org.springframework.http.client.AbstractClientHttpRequest.execute(AbstractClientHttpRequest.java:53)
        at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:652)
        ... 6 more

到目前为止我尝试了什么:

  • 增加客户端最大线程数(在application.properties中从100到500等)
  • 通过控制台
  • 将weblogics最大并发线程数从100增加到200(300,400等)
  • 检查服务器和客户端的最大打开文件。
  • 检查服务器和客户端之间的防火墙。
  • 使用Java Mission Control进行监视并检查线程阻塞状态。当异常发生时,由于log4j写入错误300TPS,线程被阻止。但是这并没有解决为什么我们有这些例外的问题。将信息级别从“信息”更改为“错误”。

到目前为止没有任何改进,仍然在某些时候获得BindExceptions。有什么建议吗?

1 个答案:

答案 0 :(得分:0)

感谢EJP的建议。这是我如何解决问题。 Spring Rest模板正在等待unix关闭连接。因此,在达到最大套接字连接后,连接在TIME_WAIT状态下等待。当我们将Apache ClientHttpRequestFactory作为spring RestTemplate的工厂发送时,apache会处理带有连接池的请求。以下是实施:

    @Bean("apacheRequestFactory")
    public ClientHttpRequestFactory createRequestFactory() {

        PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();

        // maximum connections in the pool
        connectionManager.setMaxTotal(this.systemPropertyBean.getPushConsumerThreadCnt());

        // maximum concurrent connection to the hosts is equal to the our push thread count.
        connectionManager.setDefaultMaxPerRoute(this.systemPropertyBean.getPushConsumerThreadCnt());

        RequestConfig config = RequestConfig.custom()
                .setConnectTimeout(this.systemPropertyBean.getPushTimeoutMillis())// 3 sn
                .setConnectionRequestTimeout(this.systemPropertyBean.getPushTimeoutMillis())
                .setSocketTimeout(this.systemPropertyBean.getPushTimeoutMillis()).build(); // read timeout

/*      the Connection Timeout (http.connection.timeout) – the time to establish the connection with the remote host
        the Socket Timeout (http.socket.timeout) – the time waiting for data – after the connection was established; maximum time of inactivity between two data packets
        the Connection Manager Timeout (http.connection-manager.timeout) – the time to wait for a connection from the connection manager/pool
*/        
        CloseableHttpClient httpClient = HttpClientBuilder.create().setConnectionManager(connectionManager).setDefaultRequestConfig(config).build();
        return new HttpComponentsClientHttpRequestFactory(httpClient);
    }

    @Bean
    public RestTemplate restTemplate() {
// I was using SimpleClientHttpRequestFactory before.
        RestTemplate restTemplate = new RestTemplate(createRequestFactory());
        restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
        restTemplate.getMessageConverters().add(new StringHttpMessageConverter());
        return restTemplate;
    }