一个 SpringBoot 项目能处理多少请求

news/2024/3/29 10:32:02/文章来源:https://blog.csdn.net/zlpzlpzyd/article/details/131992445

首先,这个问题有坑,因为 spring boot 不处理请求,只是把现有的开源组件打包后进行了版本适配、预定义了一些开源组件的配置通过代码的方式进行自动装配进行简化开发。这是 spring boot 的价值。

如果我是面试官,我不会问这种问题。因为在实际开发中我们遇到的都是具体的问题,能用一句话讲清楚就尽量不用两句话讲清楚,聚焦问题点。

真正处理 http 请求的是 web 容器,一般请求是 servlet 规范的实现,比如 tomcat、undertow、jetty 等。spring boot 项目在启动的时候在启动 web 容器时会加载 spring ioc 容器执行 bean 的初始化操作。

明确了问题接下来就好说了。

下面以 spring boot 2.7.10,因为下面的部分会关系到源码,如果自己去看的话,可能会有无法对应的问题,减少误会和学习成本。

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency>

如果不指定的话上述依赖默认引入 tomcat。

测试代码如下

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;import java.lang.invoke.MethodHandles;
import java.util.concurrent.TimeUnit;/*** @author Rike* @date 2023/7/21*/
@RestController
public class TestController {private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());@GetMapping(value = "test")public void test(int num) throws InterruptedException {logger.info("{}接收到请求,num={}", Thread.currentThread().getName(), num);TimeUnit.HOURS.sleep(1L);}
}

/*** @author Rike* @date 2023/7/28*/
public class MainTest {public static void main(String[] args) {for (int i = 0; i < 1500; i++) {int finalNo = i;new Thread(() -> {new RestTemplate().getForObject("http://localhost:8080/test?num="+finalNo, Object.class);}).start();}Thread.yield();}
}

统计“接受到请求”关键字在日志中出现的次数,为 200 次。

这个结果怎么来的?

最终请求到了 tomcat,所以需要在 tomcat 层次分析问题。

查看线程 dump 信息

org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run

在 getTask() 中可以看到线程池的核心参数

corePoolSize,核心线程数,值为 10
maximumPoolSize,最大线程数,值为 200

Tomcat 可以同时间处理 200 个请求,而它的线程池核心线程数只有 10,最大线程数是 200。
这说明,前面这个测试用例,把队列给塞满了,从而导致 Tomcat 线程池启用了最大线程数。

查看一下队列的长度是多少

其中 workQueue 的实现类是 org.apache.tomcat.util.threads.TaskQueue ,继承了 juc 的 LinkedBlockingQueue。

查看构造器在哪里被调用

 通过代码跟踪,得知在 org.apache.catalina.core.StandardThreadExecutor 中
maxQueueSize 线程池的队列最大值,默认为 Integer.MAX_VALUE。

目前已知的是核心线程数,值为 10。这 10 个线程的工作流程是符合预测的。
但是第 11 个任务过来的时候,本应该进入队列去排队。
现在看起来,是直接启用最大线程数了。

接下来查看一下 org.apache.tomcat.util.threads.ThreadPoolExecutor 的源码

标号为1的地方,就是判断当前工作线程数是否小于核心线程数,小于则直接调用 addWorker(),创建线程。
标号为2的地方主要是调用了 offer(),看看队列里面是否还能继续添加任务。
如果不能继续添加,说明队列满了,则来到标号为3的地方,看看是否能执行 addWorker(),创建非核心线程,即启用最大线程数。

主要就是去看 workQueue.offer(command) 这个逻辑。
如果返回 true 则表示加入到队列,返回 false 则表示启用最大线程数。
这个 workQueue 是 TaskQueue。

看一下org.apache.Tomcat.util.threads.TaskQueue#offer

标号为1的地方,判断了 parent 是否为 null,如果是则直接调用父类的 offer 方法。说明要启用这个逻辑,我们的 parent 不能为 null。

在 org.apache.catalina.core.StandardThreadExecutor 中进行了 parent 的设置,当前 ThreadPoolExecutor 为 org.apache.tomcat.util.threads.ThreadPoolExecutor。即 parent 是 tomcat 的线程池。

标号2表明当前线程池的线程数已经是配置的最大线程数了,那就调用 offer 方法,把当前请求放到到队列里面去。
标号为3的地方,是判断已经提交到线程池里面待执行或者正在执行的任务个数,是否比当前线程池的线程数还少。
如果是,则说明当前线程池有空闲线程可以执行任务,则把任务放到队列里面去,就会被空闲线程给取走执行。

然后,关键的来了,标号为4的地方。

如果当前线程池的线程数比线程池配置的最大线程数还少,则返回 false。

如果 offer() 返回 false,会出现什么情况?

是不是直接开始到上图中标号为3的地方,去尝试添加非核心线程了?
也就是启用最大线程数这个配置了。

这里可以得知,java自带的线程池和tomcat线程池使用机制不一样

JDK 的线程池,是先使用核心线程数配置,接着使用队列长度,最后再使用最大线程配置。
Tomcat 的线程池,就是先使用核心线程数配置,再使用最大线程配置,最后才使用队列长度。

面试官的原问题就是:一个 SpringBoot 项目能同时处理多少请求?

一个未进行任何特殊配置,全部采用默认设置的 SpringBoot 项目,这个项目同一时刻最多能同时处理多少请求,取决于我们使用的 web 容器,而 SpringBoot 默认使用的是 Tomcat。


Tomcat 的默认核心线程数是 10,最大线程数 200,队列长度是无限长。但是由于其运行机制和 JDK 线程池不一样,在核心线程数满了之后,会直接启用最大线程数。所以,在默认的配置下,同一时刻,可以处理 200 个请求。


在实际使用过程中,应该基于服务实际情况和服务器配置等相关消息,对该参数进行评估设置。

那么其他什么都不动,如果我仅仅加入 server.tomcat.max-connections=10 这个配置呢,那么这个时候最多能处理多少个请求?

重新提交 1000 个任务过来,在控制台输出的确实是 10 个。

那么 max-connections 这个参数它怎么也能控制请求个数呢?
为什么在前面的分析过程中我们并没有注意到这个参数呢?

因为 spring boot 设置的默认值是 8192,比最大线程数 200 大,这个参数并没有限制到我们,所以我们没有关注到它。
当我们把它调整为 10 的时候,小于最大线程数 200,它就开始变成限制项了。

还有这样的一个参数,默认是 100

server.tomcat.accept-count=100

server.tomcat.max-connections

最大连接数,达到最大值时,操作系统仍然接收属性acceptCount指定的连接


server.tomcat.accept-count

所有请求线程在使用时,连接请求队列最大长度

实践验证一下

发送请求数为1500
max-connections
指定为1000
max
指定为1000
max-connections
取默认值(8192)
正常,但是只处理了200个请求
max取默认值
(200)
正常接收,请求端报连接拒绝异常,获取所有请求中的1000个进行处理

server.tomcat.max-connections 与 server.tomcat.threads.max 的关系

server.tomcat.max-connections > server.tomcat.threads.max,只会处理 server.tomcat.threads.max 大小的请求,其他的会被拒绝。
打印的日志线程的id是指 server.tomcat.threads.max 里的。

server.tomcat.max-connections 类似一个大门,决定了同一时刻有多少请求能被处理,但是最终处理的不是它,而是 server.tomcat.threads.max 控制。
可以理解为大门和小门的关系。

参数 server.tomcat.threads.max 经过调整后(大于默认值),发现只有对应的核心线程数量对应的请求,由此考虑到进了队列的数据未处理。

tomcat 相关配置如下

org.apache.tomcat.util.threads.ThreadPoolExecutor
tomcat的线程池在juc的ThreadPoolExecutor基础上进行了处理命名为自己的线程池,

对应的核心线程数、最大线程数、阻塞队列大小

org.apache.tomcat.util.net.AbstractEndpoint 中
minSpareThreads 核心线程数,默认值为 10
maxThreads 最大线程数,默认值为 200
maxConnections 最大连接数,默认值为 8192
acceptCount
允许服务器开发人员指定 acceptCount(backlog)应该用于服务器套接字。默认情况下,此值是100。

org.apache.catalina.core.StandardThreadExecutor 中
maxQueueSize 线程池的队列最大值,默认为 Integer.MAX_VALUE
org.apache.tomcat.util.threads.TaskQueue 继承了 juc 的 LinkedBlockingQueue

参考链接

https://mp.weixin.qq.com/s/OTs2KAZ6DSbzH_WC0AWCSw

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_337375.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

带wiringPi库的交叉编译 ---宿主机x86Ubuntu,目标机ARMv8 aarch64(香橙派)

带wiringPi库的交叉编译如何进行 先交叉编译wiringPi库&#xff0c;编译出的库适合香橙派&#xff0c;这时候交叉编译可执行程序的平台和链接库的格式也是正确的&#xff0c;然后通过-I和-L来指定链接的wiringPi库的头文件和库的位置&#xff0c;但是现在还没有学习过&#xf…

如何有效地使用ChatGPT写小说讲故事?

​构思故事情节&#xff0c;虽有趣但耗时&#xff0c;容易陷入写作瓶颈。ChatGPT可提供灵感&#xff0c;帮你解决写作难题。要写出引人入胜的故事&#xff0c;关键在于抓住八个要素——主题、人物、视角、背景、情节、语气、冲突和解决办法。 直接给出故事模板&#xff0c;你可…

算法39:Excel 表列序号

一、需求 给你一个字符串 columnTitle &#xff0c;表示 Excel 表格中的列名称。返回 该列名称对应的列序号 。 例如&#xff1a; A -> 1 B -> 2 C -> 3 … Z -> 26 AA -> 27 AB -> 28 … 示例 1&#xff1a; 输入: columnTitle “A” 输出: 1 示例 2&…

【小梦C嘎嘎——启航篇】类和对象(上篇)

【小梦C嘎嘎——启航篇】类和对象&#xff08;上篇&#xff09;&#x1f60e; 前言&#x1f64c;什么是面向过程&#xff1f;什么是面向对象&#xff1f;什么是类和对象类中的访问权限属性类的大小计算this 指针构造函数析构函数 总结撒花&#x1f49e; &#x1f60e;博客昵称&…

this is incompatible with sql_mode=only_full_group_by

查看配置 select global.sql_mode 在sql命令行中输入select sql_mode 能够看到sql_mode配置,如果有ONLY_FULL_GROUP_BY&#xff0c;则需要修改 在mysql5.7.5后&#xff0c;ONLY_FULL_GROUP_BY是默认选项&#xff0c;所以就会导致group by的问题 set sql_mode‘复制去掉ONLY_F…

大数据-Spark批处理实用广播Broadcast构建一个全局缓存Cache

1、broadcast广播 在Spark中&#xff0c;broadcast是一种优化技术&#xff0c;它可以将一个只读变量缓存到每个节点上&#xff0c;以便在执行任务时使用。这样可以避免在每个任务中重复传输数据。 2、构建缓存 import org.apache.spark.sql.SparkSession import org.apache.s…

WIZnet W5500-EVB-Pico 静态IP配置教程(二)

W5500是一款高性价比的 以太网芯片&#xff0c;其全球独一无二的全硬件TCP、IP协议栈专利技术&#xff0c;解决了嵌入式以太网的接入问题&#xff0c;简单易用&#xff0c;安全稳定&#xff0c;是物联网设备的首选解决方案。WIZnet提供完善的配套资料以及实时周到的技术支持服务…

解决mysqld服务启动失败

原因如下&#xff1a; 1、进程占用 首先查看下mysql进程: ps -aux | grep mysql有进程号占用了&#xff0c;kill 这个进程号 再重启服务 2、所有者和所属组为mysql 查看/usr/local/MySQL/data/mysqld.pid所有者和所属组是否为mysql 原来是权限有问题&#xff0c…

TPlink云路由器界面端口映射设置方法?快解析内网穿透能实现吗?

有很多网友在问&#xff1a;TPlink路由器端口映射怎么设置&#xff1f;因为不懂端口映射的原理&#xff0c;所以无从下手&#xff0c;下面小编就给大家分享TPlink云路由器界面端口映射设置方法&#xff0c;帮助大家快速入门TP路由器端口映射设置方法。 1.登录路由器管理界面&a…

MySQL中锁的简介——表级锁-元数据锁、意向锁

1.元数据锁 查看元数据锁 select object_type,object_scheme,object_name,lock_type,lock_duration from perfomance_scheme.metadata_locks;2.意向锁 线程A开启事务后在执行update更新语句时候&#xff0c;会给数据加上行锁&#xff0c;加上行锁以后&#xff0c;会对整张表加…

回归预测 | MATLAB实现WOA-ELM鲸鱼算法优化极限学习机多输入单输出回归预测

回归预测 | MATLAB实现WOA-ELM鲸鱼算法优化极限学习机多输入单输出回归预测 目录 回归预测 | MATLAB实现WOA-ELM鲸鱼算法优化极限学习机多输入单输出回归预测效果一览基本介绍程序设计参考资料 效果一览 基本介绍 Matlab实现WOA-ELM鲸鱼算法优化极限学习机多输入回归预测&#…

35.图片幻灯片

图片幻灯片 html部分 <div class"carousel"><div class"image-container"><img src"./static/20180529205331_yhGyf.jpeg" alt"" srcset""><img src"./static/20190214214253_hsjqw.webp"…

【已解决】电脑连上网线但无法上网

文章目录 案例情况解决方案必要的解决方法简要概括详细步骤1、打开控制面板2、打开更改适配器设置3、 找Internet协议版本44、修改配置 可能有用的解决方法 问题解决原理Internet 协议版本 4&#xff08;TCP/IPv4&#xff09;确保IP地址和DNS服务器设置为自动获取 案例情况 网…

基于正交滤波器组的语音DPCM编解码算法matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 matlab2022a 3.部分核心程序 ...........................................................g0zeros(1,lenH); g1zeros(1,l…

基于51单片机和proteus的加热洗手器系统设计

此系统是基于51单片机和proteus的仿真设计&#xff0c;功能如下&#xff1a; 1. 检测到人手后开启出水及加热。 2. LED指示加热出水及系统运行状态。 功能框图如下&#xff1a; Proteus仿真界面如下&#xff1a; 下面就各个模块逐一介绍&#xff0c; 模拟人手检测模块 通过…

MongoDB的安装(详细教程)

文章目录 前言一、概述二、下载三、安装与启动四、连接1. Shell 命令连接1. Compass-图形化界面客户端 前言 MongoDB 是一个基于分布式文件存储的数据库&#xff0c;主要用于为 web 应用提供可扩展的高性能数据存储解决方案。 以下内容是如何在 windows 下安装 MongoDB 的教程…

github Recv failure: Connection reset by peer

Recv failure: Connection reset by peer 背景处理ping一下github网页访问一下github项目git配置git ssh配置再次尝试拉取 疑惑点待研究参考 背景 晚上敲着代码准备提交&#xff0c;执行git pull&#xff0c;报错Recv failure: Connection reset by peer。看着这报错我陷入了沉…

EMO:重新思考高效的基于注意力的移动块模型

文章目录 摘要1、介绍2、方法论:归纳法和演绎法2.1、通用效率模型标准2.2、元移动块2.3、微设计:倒置残余移动块2.4、面向密集预测的EMO宏观设计 3、实验3.1、图像分类3.2、下游任务3.3、额外的消融和解释分析 4、相关工作5、结束语及未来工作 摘要 论文链接&#xff1a;https…

Linux安装MySQL 8.1.0

MySQL是一个流行的开源关系型数据库管理系统&#xff0c;本教程将向您展示如何在Linux系统上安装MySQL 8.1.0版本。请按照以下步骤进行操作&#xff1a; 1. 下载MySQL安装包 首先&#xff0c;从MySQL官方网站或镜像站点下载MySQL 8.1.0的压缩包mysql-8.1.0-linux-glibc2.28-x…

机器学习:提取问题答案

模型BERT 任务&#xff1a;提取问题和答案 问题的起始位置和结束位置。 数据集 数据集 DRCDODSQA 先分词&#xff0c;然后tokenize 文章长度是不同的&#xff0c;bert的token的长度有限制&#xff0c;一般是512&#xff0c; self-attention的计算量是 O ( n 2 ) O(n^2) O(n…