“Tomcat最大支持多少个请求”

本文分析了SpringBoot默认内嵌Tomcat时,其并发处理能力,包括最大线程数、QPS计算以及线程池的工作原理,特别提到了自定义等待队列的请求处理策略。
该文章已生成可运行项目,

前置说明

这里的Tomcat,指的是默认SpringBoot内嵌Tomcat(不修改任何配置)。

对于“Tomcat默认可以处理多少个请求”的解读,按照时间颗粒度不同,有两种理解角度,一种是并行处理,另一种是并发处理(QPS)

  • 并行处理
    Tomcat的请求处理线程池,默认设置的“最大线程数”(默认maximumPoolSize为200),即Tomcat支持并行处理的请求数。
    org.apache.tomcat.util.net.AbstractEndpoint
    在这里插入图片描述

  • 并发处理(QPS)
    单位时间1s内,基于Tomcat最大线程数(200),能接受处理的请求数。
    假如一个请求响应时间(RT)为200ms,则默认Tomcat的理想QPS为1000。

源码走读

SpringBoot启动

Tomcat容器的启动位于上下文刷新的finishRefresh()方法中。

执行栈帧
在这里插入图片描述

finishRefresh()方法
在这里插入图片描述
在这里插入图片描述

WebServer接口为服务容器根接口,SpringBoot默认容器为Tomcat。
在这里插入图片描述

Tomcat容器启动

执行堆栈
在这里插入图片描述

直接跟踪到线程池创建部分
在这里插入图片描述

    public void createExecutor() {
        internalExecutor = true;
        // 创建自定义等待队列
        TaskQueue taskqueue = new TaskQueue();
        // 创建 线程生成工程
        TaskThreadFactory tf = new TaskThreadFactory(getName() + "-exec-", daemon, getThreadPriority());
        // 创建请求处理线程池
        executor = new ThreadPoolExecutor(getMinSpareThreads(), getMaxThreads(), 60, TimeUnit.SECONDS,taskqueue, tf);
        // 保存线程池到队列属性中
        taskqueue.setParent( (ThreadPoolExecutor) executor);
    }

这便是Tomcat请求处理线程池的创建,debug该线程池的属性
在这里插入图片描述
可以看得出来,线程池核心线程数为10,最大线程数为200。
对于该线程池的等待队列,是Tomcat自定义的TaskQueue(上面的org.apache.tomcat.util.net.AbstractEndpoint#createExecutor方法中创建)。

自定义等待队列TaskQueue中有一个属性parent,通过重写队列的org.apache.tomcat.util.threads.TaskQueue#offer方法,实现请求拒绝策略。

public class TaskQueue extends LinkedBlockingQueue<Runnable> {

    private volatile ThreadPoolExecutor parent = null;

    @Override
    public boolean offer(Runnable o) {
      	//we can't do any checks
      	// 如果未设置线程池,则直接入队
        if (parent==null) return super.offer(o);
        //we are maxed out on threads, simply queue the object
        // 如果线程数 == 最大线程数,则直接入队
        if (parent.getPoolSize() == parent.getMaximumPoolSize()) return super.offer(o);
        //we have idle threads, just add it to the queue
        // 如果已提交任务数(提交但未完成) <= 线程数,直接入队
        if (parent.getSubmittedCount()<=(parent.getPoolSize())) return super.offer(o);
        //if we have less threads than maximum force creation of a new thread
        // -----------------------------------------------------------------
        // 如果线程数 < 最大线程数,不入队,返回false,强制创建新的工作线程
        // -----------------------------------------------------------------
        if (parent.getPoolSize()<parent.getMaximumPoolSize()) return false;
        //if we reached here, we need to add it to the queue
        // 以上条件不符合,则直接入队
        return super.offer(o);
    }
}

这里可以看到,Tomcat的请求线程池的任务提交和常规的线程池任务提交有一定区别,
常规线程池的等待队列,基本只负责按照队列属性进行入队,直接返回入队成功或者失败。
而Tomcat的线程池任务等待队列,在常规线程池任务提交逻辑上,加入了线程池本身的运行状态作为入队的判断条件,最主要的一个差别是:
Tomcat中,如果线程数小于最大核心线程数,不管等待队列是否可以入队,会直接创建新的工作线程执行任务。
常规线程池的做法是,等待队列满了才会创建新的工作线程去执行任务。

Tomcat线程池处理请求

public abstract class AbstractEndpoint<S> {
    public boolean processSocket(SocketWrapperBase<S> socketWrapper,
            SocketEvent event, boolean dispatch) {
        try {
            if (socketWrapper == null) {
                return false;
            }
            // 获取缓存中的socket任务
            SocketProcessorBase<S> sc = processorCache.pop();
            if (sc == null) {
            	// 缓存为空,则创建(拉取)新的socket任务
                sc = createSocketProcessor(socketWrapper, event);
            } else {
            	// 缓存不为空,则重置socket事件
                sc.reset(socketWrapper, event);
            }
            // 获取线程池
            Executor executor = getExecutor();
            if (dispatch && executor != null) {
            	// 提交任务
                executor.execute(sc);
            } else {
                sc.run();
            }
        } catch (RejectedExecutionException ree) {
            getLog().warn(sm.getString("endpoint.executor.fail", socketWrapper) , ree);
            return false;
        } catch (Throwable t) {
            ExceptionUtils.handleThrowable(t);
            // This means we got an OOM or similar creating a thread, or that
            // the pool and its queue are full
            getLog().error(sm.getString("endpoint.process.fail"), t);
            return false;
        }
        return true;
    }

}

SocketProcessorBase为Socket处理任务基础抽象类。
在这里插入图片描述
通过继承该类,实现doRun()抽象方法,实现不同的线程模型。

debug可知,Tomcat默认使用的线程模型为NIO。
在这里插入图片描述
官网线程模型
链接:https://tomcat.apache.org/tomcat-8.0-doc/config/http.html
在这里插入图片描述
注意,这里的阻塞非阻塞,是针对请求的读取和响应,而非请求本身的逻辑(Controller方法)。

总结

Tomcat默认最大并行处理数为200,并发处理数 QPS = 200 * (1000ms / 平均RT)。

本文章已经生成可运行项目
内容概要:本文围绕可变桨叶四旋翼无人机的规范控制与点对点运动模拟展开,重点研究优化推力分配策略在翻转动作中的应用与性能比较。通过Matlab代码实现,构建了四旋翼动力学模型,并设计了多种控制算法以实现精确的姿态调整与轨迹跟踪。研究对比了不同推力分配方案在执行高机动性翻转动作时的稳定性、能耗效率与响应速度,旨在提升无人机在复杂飞行任务中的动态性能与控制精度。该仿真研究为无人机飞控系统的设计与优化提供了理论依据和技术支持。; 适合人群:具备一定自动控制理论基础和Matlab编程能力,从事无人机控制、飞行器动力学或机器人系统研究的科研人员及研究生。; 使用场景及目标:① 实现四旋翼无人机在三维空间中的精确点对点运动控制;② 对比分析不同推力分配策略在执行翻转等高难度动作时的控制效果与能耗表现,优化飞行性能;③ 为无人机自主飞行、特技飞行及复杂环境下的机动控制提供算法验证平台。; 阅读建议:此资源以Matlab仿真为核心,建议读者结合相关控制理论知识,深入理解代码实现细节,重点关注动力学建模、控制律设计与推力分配模块。在学习过程中,应动手调试参数,复现文中翻转动作的仿真结果,并尝试拓展至其他复杂飞行任务,以加深对无人机控制机理的理解。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值