springboot 微服务 根据tomcat maxthread 和 等待用户数量,达到阈值后,通知用户前面还有多少用户等待,请稍后重试

我们在java项目开发中,如何设置服务器最大负载,过了服务器承受范围之后,提示用户稍后重试,避免

服务器无法提供正常服务

如何设置服务器负载比如:最大线程数,等待数量等,请看:spring+tomcat 用户每次发请求,tomcat 站在线程的角度是如何处理用户请求的,spinrg的bean 是共享的吗?

在Spring Boot微服务中,可以通过监控Tomcat线程池状态实现流量控制,当请求数超过阈值时通知用户等待情况。

1. 核心实现类 - Tomcat线程池监控与响应

java 复制代码
import org.apache.tomcat.util.threads.ThreadPoolExecutor;
import org.springframework.boot.web.embedded.tomcat.TomcatWebServer;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicInteger;

@Component
public class RequestThrottlingFilter extends OncePerRequestFilter 
    implements ApplicationListener<ContextRefreshedEvent> {

    // 配置参数(可放入application.properties)
    private static final int MAX_THREADS = 200;       // Tomcat最大线程数
    private static final int QUEUE_CAPACITY = 100;    // 等待队列容量
    private static final int ALERT_THRESHOLD = 80;    // 触发通知的阈值(%)
    
    private ThreadPoolExecutor tomcatThreadPool;
    private final AtomicInteger waitingRequests = new AtomicInteger(0);

    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        // 获取Tomcat线程池实例
        Optional.ofNullable(event.getApplicationContext().getWebServer())
                .filter(ws -> ws instanceof TomcatWebServer)
                .map(ws -> (TomcatWebServer) ws)
                .map(ws -> ws.getTomcat().getConnector().getProtocolHandler().getExecutor())
                .filter(exec -> exec instanceof ThreadPoolExecutor)
                .ifPresent(exec -> tomcatThreadPool = (ThreadPoolExecutor) exec);
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, 
                                   HttpServletResponse response, 
                                   FilterChain filterChain) 
        throws ServletException, IOException {
        
        waitingRequests.incrementAndGet(); // 进入等待计数
        
        try {
            // 检查线程池状态
            if (isSystemOverloaded()) {
                int queuePosition = waitingRequests.get();
                sendBusyResponse(response, queuePosition);
                return;
            }
            
            filterChain.doFilter(request, response);
        } finally {
            waitingRequests.decrementAndGet(); // 完成处理,减少计数
        }
    }

    private boolean isSystemOverloaded() {
        if (tomcatThreadPool == null) return false;
        
        int activeThreads = tomcatThreadPool.getActiveCount();
        int queueSize = tomcatThreadPool.getQueue().size();
        
        // 计算系统负载率
        double loadFactor = (activeThreads + queueSize) * 100.0 / MAX_THREADS;
        
        return loadFactor >= ALERT_THRESHOLD || queueSize >= QUEUE_CAPACITY;
    }

    private void sendBusyResponse(HttpServletResponse response, int queuePosition) 
        throws IOException {
        
        response.setStatus(HttpStatus.TOO_MANY_REQUESTS.value());
        response.setContentType("application/json");
        
        String jsonResponse = String.format(
            "{\"status\": 429, \"message\": \"系统繁忙,当前等待人数:%d,请稍后重试\"}", 
            queuePosition
        );
        
        response.getWriter().write(jsonResponse);
        response.getWriter().flush();
    }
}

2. 配置Tomcat参数(application.yml)

yaml 复制代码
server:
  tomcat:
    max-threads: 200     # 最大工作线程数
    max-connections: 1000 # 最大连接数
    accept-count: 100    # 等待队列长度

3. 注册过滤器(可选,Spring Boot自动注册)

java 复制代码
@Configuration
public class FilterConfig {
    
    @Bean
    public FilterRegistrationBean<RequestThrottlingFilter> throttlingFilter(
        RequestThrottlingFilter filter) {
        
        FilterRegistrationBean<RequestThrottlingFilter> registration = 
            new FilterRegistrationBean<>(filter);
        registration.setOrder(Ordered.HIGHEST_PRECEDENCE); // 最高优先级
        return registration;
    }
}

工作原理解释:

  1. 线程池监控

    • 通过ContextRefreshedEvent获取Tomcat线程池实例
    • 实时监控:activeCount(活跃线程) + queue.size()(等待请求)
  2. 流量控制逻辑

    java 复制代码
    系统负载率 = (活跃线程数 + 等待队列长度) / 最大线程数 * 100%
    触发条件:负载率 ≥ 阈值 或 等待队列满
  3. 用户通知机制

    • 使用AtomicInteger计数器跟踪实时等待人数
    • 返回429状态码(Too Many Requests)
    • 响应示例:{"status":429, "message":"系统繁忙,当前等待人数:85,请稍后重试"}

4. 高级优化建议:

java 复制代码
// 在sendBusyResponse方法中添加重试建议
private void sendBusyResponse(HttpServletResponse response, int queuePosition) 
    throws IOException {
    
    // 计算建议重试时间(按每请求50ms估算)
    long waitTimeMs = queuePosition * 50;
    String suggestTime = waitTimeMs > 1000 ? 
        (waitTimeMs/1000) + "秒后" : "片刻后";

    String jsonResponse = String.format(
        "{\"status\":429, \"message\":\"系统繁忙,您前面还有%d人等待\", " +
        "\"suggestion\":\"建议%s重试\", \"retry_after\":%d}", 
        queuePosition, suggestTime, waitTimeMs
    );
    
    // 添加标准重试头
    response.setHeader("Retry-After", String.valueOf(waitTimeMs/1000));
    response.getWriter().write(jsonResponse);
}

5. 客户端处理建议:

  1. 前端收到429响应时:
    • 显示友好提示:系统繁忙,您前面还有XX人等待
    • 根据retry_after字段设置倒计时重试按钮
    • 使用指数退避策略:首次2秒后重试,失败则4秒、8秒...

注意事项:

  1. 性能影响

    • 使用AtomicInteger计数器无锁竞争,性能损耗可忽略
    • 避免在过滤器中执行阻塞操作
  2. 阈值设置建议

    • 生产环境推荐值:ALERT_THRESHOLD = 75-85
    • 公式:max_threads = (平均响应时间(ms) * QPS) / 1000
  3. 集群环境扩展

    • 需结合Redis分布式计数器
    • 使用Redisson的RAtomicLong替代AtomicInteger

此方案能在不影响核心业务的情况下,当系统压力过大时提供友好的用户提示,有效防止服务雪崩。

相关推荐
悟空码字5 小时前
Spring Boot 整合 MongoDB 最佳实践:CRUD、分页、事务、索引全覆盖
java·spring boot·后端
皮皮林5512 天前
拒绝写重复代码,试试这套开源的 SpringBoot 组件,效率翻倍~
java·spring boot
用户908324602734 天前
Spring AI 1.1.2 + Neo4j:用知识图谱增强 RAG 检索(上篇:图谱构建)
java·spring boot
用户8307196840825 天前
Spring Boot 集成 RabbitMQ :8 个最佳实践,杜绝消息丢失与队列阻塞
spring boot·后端·rabbitmq
Java水解5 天前
Spring Boot 视图层与模板引擎
spring boot·后端
Java水解5 天前
一文搞懂 Spring Boot 默认数据库连接池 HikariCP
spring boot·后端
洋洋技术笔记5 天前
Spring Boot Web MVC配置详解
spring boot·后端
初次攀爬者6 天前
Kafka 基础介绍
spring boot·kafka·消息队列
用户8307196840826 天前
spring ai alibaba + nacos +mcp 实现mcp服务负载均衡调用实战
spring boot·spring·mcp
Java水解6 天前
SpringBoot3全栈开发实战:从入门到精通的完整指南
spring boot·后端