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

在Tomcat上部署WebFlux,如何提前处理并发请求的文件句柄限制?

提前处理文件句柄耗尽的Spring配置方案

一、限制Tomcat最大连接数

文件句柄耗尽核心原因是Tomcat的Socket连接占用过多句柄,直接在Spring Boot中配置Tomcat连接参数,将最大连接数设为略低于OS文件句柄上限(比如你指定的200),让Tomcat提前拒绝新连接,而非等OS阻断。

在application.properties中添加配置:

# Tomcat最大并发连接数,设为低于OS句柄上限的值
server.tomcat.max-connections=180
# Tomcat工作线程最大数,根据业务场景调整
server.tomcat.threads.max=100
# 连接等待队列长度,超过max-connections后请求进入队列,队列满则拒绝
server.tomcat.accept-count=20

当连接数达到180+20=200时,Tomcat会直接返回503 Service Unavailable给客户端,替代OS强制关闭连接的模糊报错。

二、WebClient客户端侧限流

你的客户端一次性发起10万并行请求,既会压垮服务端,也会消耗客户端自身文件句柄。用Flux的flatMap控制并发请求数:

Flux.range(0, 100000)
    .flatMap(i -> webClient.get()
            .uri("http://example/controller")
            .retrieve()
            .bodyToMono(String.class),
        // 控制同时发起的请求数,比如设为50
        50)
    .subscribe();

通过限制并发数,避免短时间内创建过多Socket连接。

三、自定义句柄监控与前置拦截

如果需要主动感知句柄使用情况,可自定义监控指标+全局过滤器,在达到阈值时提前拒绝请求:

  1. 自定义Endpoint暴露文件句柄信息:
@Component
@Endpoint(id = "file-handle")
public class FileHandleEndpoint {

    @ReadOperation
    public Map<String, Object> getFileHandleInfo() {
        Map<String, Object> info = new HashMap<>();
        long used = getCurrentUsedHandles();
        long max = getMaxHandles();
        info.put("used", used);
        info.put("max", max);
        // 设为上限的80%作为告警阈值
        info.put("threshold", (long) (max * 0.8));
        return info;
    }

    private long getCurrentUsedHandles() {
        try {
            com.sun.management.OperatingSystemMXBean osBean = 
                (com.sun.management.OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean();
            return osBean.getOpenFileDescriptorCount();
        } catch (Exception e) {
            return -1;
        }
    }

    private long getMaxHandles() {
        try {
            com.sun.management.OperatingSystemMXBean osBean = 
                (com.sun.management.OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean();
            return osBean.getMaxFileDescriptorCount();
        } catch (Exception e) {
            return -1;
        }
    }
}
  1. 全局过滤器拦截超出阈值的请求:
@Component
public class FileHandleLimitFilter implements WebFilter {

    private final FileHandleEndpoint fileHandleEndpoint;

    public FileHandleLimitFilter(FileHandleEndpoint fileHandleEndpoint) {
        this.fileHandleEndpoint = fileHandleEndpoint;
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
        Map<String, Object> info = fileHandleEndpoint.getFileHandleInfo();
        long used = (long) info.get("used");
        long threshold = (long) info.get("threshold");
        
        if (used != -1 && used >= threshold) {
            exchange.getResponse().setStatusCode(HttpStatus.SERVICE_UNAVAILABLE);
            return exchange.getResponse().setComplete();
        }
        return chain.filter(exchange);
    }
}

当文件句柄使用量达到上限的80%时,服务端直接返回503,避免触发OS的硬限制。

四、临时调整OS句柄上限(可选)

测试场景下可临时提升MacOS的文件句柄上限:

# 当前会话临时设置上限为10240
ulimit -n 10240

注:永久修改需调整系统配置文件,具体操作依MacOS版本而定,属于辅助方案,核心仍需在Spring层面做限流控制。


内容的提问来源于stack exchange,提问作者Stefano Maglione

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 14:40:30