SpringBoot内嵌Tomcat并发容量问题

未来属于那些相信梦想,并愿意为之付诸行动的人

并发容量问题

      • 发现并发容器问题
      • 深入SpringBoot底层了解原因
          • 默认内嵌Tomcat配置
      • 定制化内嵌Tomcat开发
          • 关于KeepAlive
          • 配置
      • 容器问题优化
          • 单Web容器上限
          • Mysql数据库QPS容量问题

在做一个关于秒杀系统的模块,进行Jmeter压测性能的时候发现tomcat并发上不去,深入原因找到可供优化的地方,力求最大性能。

发现并发容器问题

SpringBoot内嵌Tomcat并发容量问题_第1张图片

在这里插入图片描述

对单接口进行6000线程压测,每个线程请求5次,线程在5秒内创建完毕,当进行一半的时候,已经出现了请求响应时间过大及其错误率达到了43%。这个并发容量对于配置比较好点的服务器相对来说有点弱。

深入SpringBoot底层了解原因

在SpringBoot官方文档中提到了关于元数据的配置
SpringBoot内嵌Tomcat并发容量问题_第2张图片
SpringBoot内嵌Tomcat并发容量问题_第3张图片
可以看到,关于我们最常用的设置项目的端口的默认配置就在其中。

默认内嵌Tomcat配置
  1. server.tomcat.accept-count:等待队列长度,当可分配的线程数全部用完之后,后续的请求将进入等待队列等待,等待队列满后则拒绝处理,默认100。
  2. server.tomcat.max-connections:最大可被连接数,默认10000
  3. server.tomcat.max-threads:最大工作线程数,默认200,
  4. server.tomcat.min-spare-threads:最小工作线程数,初始化分配线程数,默认10
  • 默认配置下,连接超过10000后会出现拒绝连接情况
  • 默认配置下,触发的请求超过200+100后拒绝处理(最大工作线程数+等待队列长度)

这些元数据Spring当然提供了外部配置功能

#更改内嵌tomcat参数
server.port=8080
server.tomcat.accept-count=1000
server.tomcat.max-threads=400
server.tomcat.min-spare-threads=100

SpringBoot内嵌Tomcat并发容量问题_第4张图片

定制化内嵌Tomcat开发

SpringBoot内嵌Tomcat并发容量问题_第5张图片

关于KeepAlive

在使用Jmeter的Http请求中默认是开启KeepAlive的

Http的KeepAlive请求为当我们的客户端向我们的服务器发送Http请求的时候,若带上了KeepAlive的请求头,则表明我们的Http客户端希望跟服务端之间建立一个KeepAlive的连接,这个连接对应的用处就是说,向我们的服务端发送完对应的响应之后,我们的服务端不要立马断开连接,而是等待尝试复用连接。

此解决方案是用来解决Http的一个响应,无状态,每次都要断开连接,新建连接所带来的一个耗时问题。

但如果说我们每个网页请求打开之后都跟服务端保持一个长连接,那我们服务端的连接数很快就会被用完了,因此再最早的Http1.0的时候是没有设计KeepAlive的请求的,但是现在的Http1.1加上KeepAlive请求,目的就是越来越多的移动端的设备,甚至于一些很复杂的网页交互,需要在用户浏览的过程当中,频繁的向服务端发送请求,因此,建立一个KeepAlive连接,并非为了压测的目的,而是真正的在应用场景上是有一些性能的好处的,无论是客户端还是服务端,在做一些网络通信的交互上面,无需每次都新建连接,断开连接,耗费Tcp/Ip建连的时间,而仅仅只需要发送数据即可。

但是这样的设计也会带来一些问题,如果说我们的服务端对KeepAlive的操作没有做任何限制
1.连接不做任何操作,不做任何响应,那这条连接对服务端来说就是一条费连接
2.有一些攻击者恶意利用KeepAlive连接向我们的服务端发送DDOS的攻击,那服务端对应的连接只会成为攻击者攻击的后门,因此,为了安全,我们需要定制化Tomcat开发

配置
  1. KeepAliveTimeOut:多少毫秒后客户端不响应则断开KeepAlive
  2. maxKeepAliveRequests:多少次请求后KeepAlive断开失效

在SpringBoot官方文档中提到了对内嵌容器的配置
SpringBoot内嵌Tomcat并发容量问题_第6张图片

//当spring容器内没有TomcatEmbeddedServletContainerFactory这个bean时,会把bean加载进spring容器
@Configuration
public class WebServerConfiguration implements WebServerFactoryCustomizer<ConfigurableWebServerFactory> {
     
    @Override
    public void customize(ConfigurableWebServerFactory factory) {
     
        //使用对应工厂类提供给我们的接口定制化我们的tomcat connector
        ((TomcatServletWebServerFactory)factory).addConnectorCustomizers(new TomcatConnectorCustomizer() {
     
            @Override
            public void customize(Connector connector) {
     
                Http11NioProtocol protocol= (Http11NioProtocol) connector.getProtocolHandler();
                //定制KeepAliveTimeout,设置30秒内没有请求则服务器自动断开keepalive连接
                protocol.setKeepAliveTimeout(30000);
                //当客户端发送超过10000个请求则自动断开keepalive连接
                protocol.setMaxKeepAliveRequests(10000);
            }
        });
    }
}

容器问题优化

响应时间变长,TPS上不去

单Web容器上限

线程数量

4核CPU 8G内存单进程调用线程数800-1000,1000以上后即花费巨大的时间在CPU调度上

等待队列长度

队列做缓冲池用,但也不能无限长,消耗内存,出队入队也耗CPU

Mysql数据库QPS容量问题

主键查询:千万级别数据 = 1-10毫秒
唯一索引查询:千万级别数据 = 10-100毫秒
非唯一索引查询:千万级别数据 = 100-1000毫秒
无索引:百万条数据 = 1000毫秒+

文章持续更新,可以微信搜索「 绅堂Style 」第一时间阅读,回复【资料】有我准备的面试题笔记。
GitHub https://github.com/dtt11111/Nodes 有总结面试完整考点、资料以及我的系列文章。欢迎Star。
在这里插入图片描述

你可能感兴趣的:(JAVA,Spring,SpringBoot,java,spring,sql,linux,服务器)