复现java.net.SocketException: Connection reset 的一种场景

最近项目中使用httpClient配置的RestTemplate,写了一个http请求工具,设置了连接池,SocketTimeOut等参数。但是在高频率的请求某个接口的时候,会报错提示java.net.SocketException: Connection reset, 后来找到原因是请求方式写错了,POST请求被我发成了GET. 但是出现这种问题会是什么原因呢。

代码大致如下:

private static final String URL = "http://localhost:8081/test";

private ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat("test-pool-%d").build();

private ExecutorService executorService = new ThreadPoolExecutor(300, 300, 0,
            TimeUnit.SECONDS, new LinkedBlockingDeque<>(1000), threadFactory, new ThreadPoolExecutor.AbortPolicy());

@Autowired
private RestTemplate restTemplate;

@Override
public void run(String... args) throws Exception {
  List<CompletableFuture> futureList = new ArrayList<>();
  CountDownLatch latch = new CountDownLatch(300);
  for (int i = 0; i < 301; i++) {

    CompletableFuture future = CompletableFuture.runAsync(() -> {
      try {
        latch.countDown();
        latch.await();
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      ResponseEntity<Object> res = restTemplate.exchange(URL, HttpMethod.GET, null, Object.class);
      log.info("返回的是:{}", res.getBody());
    }, executorService);
    futureList.add(future);
  }
  CompletableFuture<Void> future = CompletableFuture.allOf(futureList.toArray(new CompletableFuture[]{}));
  log.info("都派发结束了");
  future.join();
  log.info("都请求结束了");
}

异常详情我就不贴了,大致就是请求完以后还没有来得及读取返回结果,连接就断开了。本着研究问题的角度,启动了另一个服务,另一个服务提供一个http接口,同时设置tomcat的SocketTimeOut 为0, 也就是服务端处理结束后,socket连接立马就关闭。使用的SpringBoot内置的tomcat, 所以直接在代码设置。

@Configuration
public class TomcatConfig {

    @Bean
    public TomcatServletWebServerFactory configTomcat() {
        TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
        tomcat.addConnectorCustomizers(connector -> {
            Http11NioProtocol protocol = (Http11NioProtocol) connector.getProtocolHandler();
            protocol.setKeepAliveTimeout(0);
        });
        return tomcat;
    }
}

预期是300个请求并发执行,得到300个成功的结果,但多次执行,总是只能成功一百多两百多个,后面就是报的Connection reset 的错误了。 再尝试取消protocol.setKeepAliveTimeout(0); 设置,或者设置为30000 ms, 所有300次请求都能成功。可见原因就是,服务端的SocketTimeOut 时间太短了,客户端还没来得及接收完数据,链接就被断开了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章