You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot项目遇Too many open files异常,排查RestTemplate配置问题

问题分析:RestTemplate导致"Too many open files"错误

问题描述

在基于Spring Boot的生产环境项目中,调用同网络内其他微服务的REST API时出现错误:Too many open files; nested exception is java.net.SocketException: Too many open files。近期为RestTemplate添加超时配置后触发该问题,当前每个请求都会调用指定方法创建RestTemplate实例,而使用单例实例时无此问题,请问该配置是否存在问题?

环境信息:Spring Boot 1.5.8,Java 1.8,Linux操作系统

报错堆栈

Too many open files; nested exception is java.net.SocketException: Too
many open files
java.net.SocketException: Too many open files
     at java.net.Socket.createImpl(Socket.java:460)
     at java.net.Socket.connect(Socket.java:587)
     at sun.security.ssl.SSLSocketImpl.connect(SSLSocketImpl.java:673)
     at sun.security.ssl.BaseSSLSocketImpl.connect(BaseSSLSocketImpl.java:173)
     at sun.net.NetworkClient.doConnect(NetworkClient.java:180)
     at sun.net.www.http.HttpClient.openServer(HttpClient.java:463)
     at sun.net.www.http.HttpClient.openServer(HttpClient.java:558)
     at sun.net.www.protocol.https.HttpsClient.<init>(HttpsClient.java:264)
     at sun.net.www.protocol.https.HttpsClient.New(HttpsClient.java:367)

当前RestTemplate配置代码

public RestTemplate getRestTemplate(int timeoutMs) {
    RestTemplate restTemplate = restTemplateBuilder.build();
    SimpleClientHttpRequestFactory clientHttpRequestFactory = new SimpleClientHttpRequestFactory();
    clientHttpRequestFactory.setConnectTimeout(timeoutMs);
    clientHttpRequestFactory.setReadTimeout(timeoutMs);
    restTemplate.setRequestFactory(clientHttpRequestFactory);
    restTemplate.setInterceptors(Collections.singletonList(appClientInterceptor));
    restTemplate.setErrorHandler(appClientErrorHanlder);
    return restTemplate;
}

问题根源

  • 你的配置存在明显问题:每次请求都创建新的RestTemplate实例,而每个RestTemplate实例会关联独立的SimpleClientHttpRequestFactory,后者底层使用JDK自带的HttpURLConnection,默认情况下HttpURLConnection的连接池是每个实例独立维护的。
  • 频繁创建RestTemplate实例会导致大量未及时释放的Socket连接堆积,超过Linux系统的文件句柄上限,触发"Too many open files"错误。
  • 单例模式下,RestTemplate复用同一个连接池,连接会被合理复用和回收,不会出现句柄耗尽的情况。

解决方案

  • 改为单例RestTemplate实例:
    如果需要不同的超时配置,不要创建新实例,而是通过自定义ClientHttpRequestFactory或者使用拦截器动态调整超时;或者针对不同超时需求创建少量几个单例实例,而非每次请求都新建。示例单例配置(固定超时):

    @Bean
    public RestTemplate restTemplate(@Value("${rest.timeout:5000}") int timeoutMs) {
        SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
        factory.setConnectTimeout(timeoutMs);
        factory.setReadTimeout(timeoutMs);
        RestTemplate restTemplate = new RestTemplate(factory);
        restTemplate.setInterceptors(Collections.singletonList(appClientInterceptor));
        restTemplate.setErrorHandler(appClientErrorHanlder);
        return restTemplate;
    }
    
  • 替换为更高效的请求工厂:
    推荐使用HttpComponentsClientHttpRequestFactory(基于Apache HttpClient),它的连接池管理更成熟,即使不小心创建多个实例,资源泄漏的风险也更低,但仍建议单例使用。示例配置:

    @Bean
    public RestTemplate restTemplate(@Value("${rest.timeout:5000}") int timeoutMs) {
        HttpClient httpClient = HttpClientBuilder.create()
                .setConnectionTimeToLive(timeoutMs, TimeUnit.MILLISECONDS)
                .build();
        HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient);
        factory.setConnectTimeout(timeoutMs);
        factory.setReadTimeout(timeoutMs);
        RestTemplate restTemplate = new RestTemplate(factory);
        restTemplate.setInterceptors(Collections.singletonList(appClientInterceptor));
        restTemplate.setErrorHandler(appClientErrorHanlder);
        return restTemplate;
    }
    
  • 临时应急调整:
    可以临时调高Linux系统的文件句柄限制(修改/etc/security/limits.conf),但这只是治标不治本,无法解决根本的资源泄漏问题。

内容的提问来源于stack exchange,提问作者Prashant Thorat

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 02:05:20