最近项目中使用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 时间太短了,客户端还没来得及接收完数据,链接就被断开了。