SpringBoot默认的内嵌容器是Tomcat,也就是我们的程序实际上是运行在Tomcat里的。所以与其说SpringBoot可以处理多少请求,到不如说Tomcat可以处理多少请求。

关于Tomcat的默认配置,都在spring-configuration-metadata.json文件中,对应的配置类则是org.springframework.boot.autoconfigure.web.ServerProperties。

内嵌Tomcat配置

和处理请求数量相关的参数有四个:

server:
tomcat:
threads:
# 最少线程数,默认大小是10。该参数相当于长期工,如果并发请求的数量达不到10,就会依次使用这几个线程去处理请求。
min-spare: 10
# 最多线程数,默认大小是200。该参数相当于临时工,如果并发请求的数量在10到200之间,就会使用这些临时工线程进行处理。
max: 15
# 最大连接数,默认大小是8192。表示Tomcat可以处理的最大请求数量,超过8192的请求就会被放入到等待队列。
max-connections: 30
# 最大等待数,默认大小是100。
accept-count: 10

再来写一个简单的接口:

@GetMapping("/test")
public Response test1(HttpServletRequest request) throws Exception {
log.info("ip:{},线程:{}", request.getRemoteAddr(), Thread.currentThread().getName());
Thread.sleep(500);
return Response.buildSuccess();
}

如果并发请求数量低于server.tomcat.threads.max,则会被立即处理,超过的部分会先进行等待,如果数量超过max-connections与accept-count之和,则多余的部分则会被直接丢弃。

如何提升 Spring Boot 吞吐量?

  1. 增加内嵌 Tomcat 的最大连接数
  2. 异步执行
  3. 使用 @ComponentScan() 定位扫包
    • 使用 @ComponentScan() 定位扫包比 @SpringBootApplication 扫包更快。
  4. 默认 Tomcat 容器改为 Undertow
    • 默认 Tomcat 容器改为 Undertow(Jboss 下的服务器,Tomcat 吞吐量 5000,Undertow 吞吐量 8000)
  5. 使用 BufferedWriter 进行缓冲
  6. Deferred 方式实现异步调用
  7. 异步调用可以使用 AsyncHandlerInterceptor 进行拦截

延伸:并发问题是如何产生的?

到目前为止,就已经搞明白了SpringBoot可以同时处理多少请求的问题。但是在这里我还想基于上面的例子再延伸一下,就是为什么并发场景下会出现一些值和我们预期的不一样?

Spring容器中的Bean默认是单例的,也就是说,处理请求的Controller、Service实例就只有一份。

在并发场景下,将cookSum定义为全局变量,是所有线程共享的,当一个线程读到了cookSum=29,同时另两个线程也读到是29,三个线程都加1后写回,最终cookSum都变成了30。

private int cookSum = 0;

@GetMapping("/test")
public Response test1(HttpServletRequest request) throws Exception {
cookSum += 1;
log.info("做了{}道菜", cookSum);
Thread.sleep(500);
return Response.buildSuccess();
}

如何处理并发问题?

通常我们说的并发:指的是多个线程操作相同的资源,如何保护线程安全,合理的使用资源。

对于一些用户请求,在某些情况下是可能重复发送的,如果是查询类操作并无大碍,但其中有些是涉及写入操作的,一旦重复了,可能会导致很严重的后果,例如交易的接口如果重复请求可能会重复下单。

重复请求的场景有可能是:

  1. 黑客拦截了请求,重放
  2. 前端/客户端因为某些原因请求重复发送了,或者用户在很短的时间内重复点击了。
  3. 网关重发
  4. 网络通信异常或者后端响应慢

    ...

解决方案:

  1. 利用唯一请求编号去重(每次请求,服务端返回客户端一个唯一编号,客户端拿着这个唯一编号去请求)
  2. 业务参数做一个摘要去重(用用户ID、请求URL、请求参数等算一个key,然后MD5(key)来作唯一参数)
  3. 让前端来限制,点击之后,在一定时间内不能再次点击。
  4. 请求去重工具类,Java实现

如何保证并发的安全?

Controller默认是单例的,单例是不安全的,会导致属性重复使用。

  1. 不要在controller中定义成员变量。
  2. 万一必须要定义一个非静态成员变量时候,则通过注解@Scope(“prototype”),将其设置为多例模式。
  3. 在Controller中使用ThreadLocal变量

如何处理高并发问题?

高并发就是通过严谨的设计来保证系统能够同时并行处理很多的请求。

也就是说系统能够在某一时间段内提供很多请求,但是不会影响系统的性能。

通常我们说的高并发:指的是系统运行过程中,短时间内遇到大量的操作请求的情况。如12306的抢票等,这时候,系统会执行大量的操作(数据库操作,资源请求等),如何处理高并发场景?

在提升系统性能方面我们一直关注的是系统的查询性能,通过数据库的分布式改造,各类缓存的原理和使用技巧。究其原因在于我们遇到的大部分场景都是读多写少,尤其是在一个系统的初级阶段。

高并发(写)请求的场景,其中《秒杀抢购》就是最典型的场景。

提供以下两种解决方案:

  • 使用锁的方式,比如分布式锁,也可以利用redis本身操作原子性的特点
  • 写入消息队列,在消息队列中做减库存的操作,做异步校验

在用户下单的时候,用了redis的原子性减库存,如果不支付,一般可以设置一个定时器,定时器时间一到,就把库存加上,同时定义订单失败。

比如1000件商品,系统生成1000个令牌,拿到令牌的用户可以进入消息队列,其他未拿到令牌的直接返回已抢完。

1、一般对于并发处理都需要加锁,否则会导致共享变量不可见问题,尽量将锁的力度变小。

2、如果确认不能或不想加锁,则做串行化处理,解决方案就是消息队列。

高并发量网站解决方案

  1. 尽量使用缓存,包括用户缓存,信息缓存等,多花点内存来做缓存,可以大量减少与数据库的交互,提高性能。
  2. 用jprofiler等工具找出性能瓶颈,减少额外的开销。
  3. 优化数据库查询语句,减少直接使用hibernate等工具的直接生成语句(仅耗时较长的查询做优化)。
  4. 优化数据库结构,多做索引,提高查询效率。
  5. 统计的功能尽量做缓存,或按每天一统计或定时统计相关报表,避免需要时进行统计的功能。
  6. 能使用静态页面的地方尽量使用,减少容器的解析(尽量将动态内容生成静态html来显示)。
  7. 解决以上问题后,使用服务器集群来解决单台的瓶颈问题。

高并发的的瓶颈在哪里?

  1. 可能是服务器网络带宽不够(可以增加网络带宽,DNS域名解析分发多台服务器。)
  2. 可能web线程连接数不够(负载均衡,前置代理服务器nginx、apache等等)
  3. 可能数据库连接查询上不去(数据库查询优化,读写分离,分表等等)

如果有高访问,高并发的需求,就尽量别用java来做。

java不适合做这种方面的工作,它在web上的用途更多是用来做行业性软件开发,对讲求效率方面的网站性工作不太适合。如果非要用java做的话可以考虑以下几个思路:

  1. 调优;
  2. 采用集群模式布署;
  3. 写好网站的程序;
  4. 不要做实时性要求比较高的工作,降低对严谨性方面的要求。

SpringBoot能同时处理多少请求的更多相关文章

  1. SpringBoot学习笔记(七):SpringBoot使用AOP统一处理请求日志、SpringBoot定时任务@Scheduled、SpringBoot异步调用Async、自定义参数

    SpringBoot使用AOP统一处理请求日志 这里就提到了我们Spring当中的AOP,也就是面向切面编程,今天我们使用AOP去对我们的所有请求进行一个统一处理.首先在pom.xml中引入我们需要的 ...

  2. SpringBoot 拦截器获取http请求参数

    SpringBoot 拦截器获取http请求参数-- 所有骚操作基础 目录 SpringBoot 拦截器获取http请求参数-- 所有骚操作基础 获取http请求参数是一种刚需 定义拦截器获取请求 为 ...

  3. Springboot 配置 ssl 实现HTTPS 请求 & Tomcat配置SSL支持https请求

    SSL(Secure Sockets Layer 安全套接层),及其继任者传输层安全(Transport Layer Security,TLS)是为网络通信提供安全及数据完整性的一种安全协议.TLS与 ...

  4. SpringBoot设置支持跨域请求

    跨域:现代浏览器出全的考虑,在http/https请求时必须遵守同源策略,否则即使跨域的http/https 请求,默认情况下是被禁止的,ip(域名)不同.或者端口不同.协议不同(比如http.htt ...

  5. SpringBoot 基于web应用开发(请求参数获取,静态资源,webjars)

    SpringBoot 基于web应用开发 一.Lombok使用 1.导入依赖库 <dependency>    <groupId>org.projectlombok</g ...

  6. Springboot跨域 ajax jsonp请求

    SpringBoot配置: <dependency> <groupId>org.springframework.boot</groupId> <artifac ...

  7. springboot——发送put、delete请求

    在springmvc中我们要发送put和delete请求,需要先配置一个过滤器HiddenHttpMethodFilter,而springboot中,已经帮我们自动配置了,所以我们可以不用配置这个过滤 ...

  8. SpringBoot项目启动后再请求远程接口的实现方式

    场景 有一个SpringBoot项目需要在启动后请求另一个远程服务拿取配置,而不是加载过程中去请求,可能会出现类没有实例化的场景,因此需要实现项目完全启动后再进行请求的场景. 解决 一般会有两种实现方 ...

  9. springboot Aop 统一处理Web请求日志

    1.增加依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId> ...

  10. springboot 接收post和get请求

    接收post请求: @RequestMapping(value = "/api/v1/create_info", method = RequestMethod.POST) publ ...

随机推荐

  1. 一种利用光电容积描记(PPG)信号和深度学习模型对高血压分类的新方法

    具体的软硬件实现点击 http://mcu-ai.com/ MCU-AI技术网页_MCU-AI 据世界心脏联合会统计,截至 2022 年,全球有 13 亿人被诊断患有高血压,每年约有 1000 万人死 ...

  2. 5GC 关键技术之 MEC 边缘计算

    目录 文章目录 目录 前文列表 MEC 边缘计算 ETSI MEC 标准化参考模型 MEC 架构设计原则 MEC 分层架构 MEC 系统架构 MEC 软件架构 MEC in NFV 融合架构 ETSI ...

  3. 降本提效 | AIRIOT设备运维管理解决方案

      传统运维多是使用在本地化系统,以人工运维和独立系统执行运维工作,重点关注的是设施运行,存在以下几个问题:   1.信息孤岛:本地化系统的接口不同,功能单一独立,各个系统之间的数据无法对接.交互,形 ...

  4. jpype-python调用java的方法

    环境准备: 部署环境准备: sed -i.ori '$a export JAVA_HOME=/opt/jdk\nexport PATH=$JAVA_HOME/bin:$JAVA_HOME/jre/bi ...

  5. springboot使controller异步调用

    调用controller方法,遇到操作时间很长的情况下,不希望前端一直等待操作,而希望前端立马接收到操作启动的反馈,而真正的操作在后端执行,需要用到异步调用的方法.实现步骤如下: 一.配置异步支持: ...

  6. ENVI自动地理配准:GCP地面控制点的自动产生

      本文介绍基于ENVI软件,利用"Image Registration Workflow"工具实现栅格遥感影像自动寻找地面控制点从而实现地理配准的方法.   在ENVI手动地理配 ...

  7. NOIP模拟75

    前言 先吐槽一下出题人,T2 牛马数据连棵树都不是.. T3 描述不清楚.. T1 如何优雅的送分 解题思路 我考场上还真以为是个送分题,然而... 莫比乌斯反演... 对于一个数字 n 有 \(2^ ...

  8. 【论文笔记】R-CNN系列之论文理解

    [深度学习]总目录 RCNN全称region with CNN features,即用CNN提取出Region Proposals中的featues.RCNN系列论文(R-CNN,Fast R-CNN ...

  9. bash: _get_comp_words_by_ref: command not found 报错

    没有安装补全的包 错误信息 bash: _get_comp_words_by_ref: command not found 表明你的 shell 中可能存在补全功能的问题. 通常,这种错误发生在你的系 ...

  10. jquery中封装了三种ajax请求方式

          // jQuery中封装了3种 ajax 请求方式         // 1, get请求方式         // 2, post请求方式         // 3, 综合请求方式    ...