復現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 時間太短了,客戶端還沒來得及接收完數據,鏈接就被斷開了。

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