首页 > 其他分享 >Springboot Tomcat 架构及参数优化

Springboot Tomcat 架构及参数优化

时间:2024-05-24 15:45:05浏览次数:23  
标签:架构 Springboot Tomcat 1.3 -- flow3 线程 class

1. Springboot Tomcat 架构及参数优化

1.1. 版本说明

构件 版本
spring-boot 2.7.18
tomcat-embed-core 9.0.83

1.2. SpringBoot Tomcat 架构分析

1.2.1. Tomcat 核心组件类图

classDiagram direction LR class Tomcat { #Server server +void start() +void stop() } class Connector { #ProtocolHandler protocolHandler } class Container { <<Interface>> } class Engine { <<Interface>> } class StandardEngine class Host { <<Interface>> } class StandardHost class Lifecycle { <<Interface>> void start() void stop() } class Server { <<Interface>> } class StandardServer { -Service[] services } class Service { <<Interface>> } class StandardService { #Connector[] connectors -Engine engine } class AbstractHttp11JsseProtocol~S~ class AbstractHttp11Protocol~S~ class AbstractProtocol~S~ { -AbstractEndpoint endpoint } class Http11NioProtocol class Http11Nio2Protocol class ProtocolHandler { <<Interface>> void start() void stop() } class AbstractEndpoint~S, U~ { -Executor executor -LimitLatch connectionLimitLatch -Handler~S~ handler +void bind() #U serverSocketAccept() +void createExecutor() +boolean processSocket(SocketWrapperBase~S~> socketWrapper, SocketEvent event, boolean dispatch) +void start() +void stop() } class AbstractJsseEndpoint~S, U~ class Nio2Endpoint class NioEndpoint { -ServerSocketChannel serverSock } class Executor { <<Interface>> } class ThreadPoolExecutor note for ThreadPoolExecutor "Tomcat 线程池在 AbstractEndpoint 创建,server.tomcat.threads.max、\n server.tomcat.threads.min-spare 参数作用于此,\n 用于指定最大、最小线程数,线程池其他参数默认值为:\n 是否守护线程:是;\n 线程优先级:5;\n 空闲线程存活时间:60 秒;\n 任务队列为:TaskQueue,容量为 Integer.MAX_VALUE" class VirtualThreadExecutor class LimitLatch { -AtomicLong count -long limit +long countDown() +void countUpOrAwait() } note for LimitLatch "LimitLatch 用于限制连接数量,基于 AQS 实现,\n server.tomcat.max-connections 参数作用于此,\n 接受一个连接前判断是否达到最大连接数 limit,\n 否则自旋等待直至成功并 count 加 1;\n 关闭连接后 count 减 1" class Handler { <<Interface>> } class ConnectionHandler~S~ class Poller note for Poller "Poller 线程不停从已连接的 socket 读取事件,\n 最终封装成 SocketProcessorBase 交给 ThreadPoolExecutor 处理" class Acceptor note for Acceptor "Acceptor 线程不停接收新的客户端连接,\n 直至达到 server.tomcat.max-connections" class SocketProcessor class SocketProcessorBase~S~ note for SocketProcessorBase "SocketProcessorBase 线程将请求经过层层传递最终给到\n DispatcherServlet,DispatcherServlet 再分派到对应的\n Spring Controller 中处理具体的业务逻辑" class Runnable { <<Interface>> } Tomcat "1" *--> "1" Host Tomcat "1" *--> "1" Server Host --|> Container StandardHost ..|> Host StandardServer ..|> Server StandardServer "1" *--> "n" Service Server --|> Lifecycle Service --|> Lifecycle StandardService ..|> Service StandardService "1" *--> "1" Engine StandardService "1" *--> "n" Connector StandardEngine ..|> Engine Engine --|> Container Container --|> Lifecycle Connector ..|> Lifecycle Connector "1" *--> "1" ProtocolHandler Http11NioProtocol --|> AbstractHttp11JsseProtocol Http11Nio2Protocol --|> AbstractHttp11JsseProtocol AbstractHttp11JsseProtocol --|> AbstractHttp11Protocol AbstractHttp11Protocol --|> AbstractProtocol AbstractProtocol ..|> ProtocolHandler AbstractProtocol "1" *--> "1" AbstractEndpoint AbstractJsseEndpoint --|> AbstractEndpoint Nio2Endpoint --|> AbstractJsseEndpoint NioEndpoint --|> AbstractJsseEndpoint AbstractEndpoint "1" *--> "1" Executor AbstractEndpoint "1" *--> "1" LimitLatch AbstractEndpoint "1" *--> "1" Handler AbstractEndpoint ..> SocketProcessorBase ThreadPoolExecutor ..|> Executor VirtualThreadExecutor ..|> Executor ConnectionHandler ..|> Handler Poller ..|> Runnable Acceptor ..|> Runnable Poller ..> AbstractEndpoint Acceptor ..> AbstractEndpoint SocketProcessor --|> SocketProcessorBase~S~ SocketProcessorBase~S~ ..|> Runnable

1.2.2. Tomcat 核心组件架构图

C4Component title Tomcat 核心组件架构图 Container_Boundary(Tomcat, "Tomcat") { Container_Boundary(Server, "Server") { Container_Boundary(Service, "Service") { Container_Boundary(Connector, "Connector") { Container_Boundary(Http11NioProtocol, "Http11NioProtocol") { Container_Boundary(NioEndpoint, "NioEndpoint") { Component(LimitLatch, "LimitLatch", "限流") Component(Acceptor, "Acceptor", "接收 socket 连接") Component(Poller, "Poller", "监听 socket 事件") Container_Boundary(ThreadPoolExecutor, "ThreadPoolExecutor") { Component(SocketProcessor, "SocketProcessor", "处理请求") } } } } } Container_Boundary(Engine, "Engine") { Component(Host, "Host", "") } } }

1.3. SpringBoot Tomcat 工作流程

1.3.1. SpringBoot 初始化 Tomcat 流程

flowchart TD flow1("SpringApplication#run(Class<?> primarySource, String... args)") --> flow2("SpringApplication#run(Class<?>[] primarySources, String[] args)") flow2 --> flow3("SpringApplication#run(String... args)") flow3 --> flow4("SpringApplication#refreshContext(ConfigurableApplicationContext context)") flow4 --> flow5("SpringApplication#refresh(ConfigurableApplicationContext applicationContext)") flow5 --> flow6("ServletWebServerApplicationContext#refresh()") flow6 --> flow7("AbstractApplicationContext#refresh()") flow7 --> flow8("ServletWebServerApplicationContext#onRefresh()") flow8 --> flow9("ServletWebServerApplicationContext#createWebServer()") subgraph flow10["TomcatServletWebServerFactory#getWebServer(ServletContextInitializer... initializers)"] direction LR flow10_1("Tomcat#Tomcat()") flow10_1 --> flow10_2("Tomcat#start()") end flow9 --> flow10

1.3.2. Tomcat 启动流程

flowchart TD flow1["Tomcat#start()"] flow2["StandardServer#start()"] flow3["StandardService#start()"] flow4["StandardEngine#start()"] flow5["Connector#start()"] flow6["Http11NioProtocol#start()"] subgraph flow7["NioEndpoint#start()"] flow8["NioEndpoint#bind() \n 初始化 ServerSocketChannel,绑定端口"] flow9["NioEndpoint#createExecutor() \n 创建工作线程池"] flow10["NioEndpoint#initializeConnectionLatch() \n 初始化限流组件"] flow11["Poller#Poller() \n 启动 socket 事件监听线程"] flow12["Acceptor#Acceptor() \n 启动 socket 连接线程"] end flow1 --> flow2 flow2 --> flow3 flow3 --> flow4 flow3 --> flow5 flow5 --> flow6 flow6 --> flow7 flow7 --> flow8 flow8 --> flow9 flow9 --> flow10 flow10 --> flow11 flow11 --> flow12

1.3.2.1. 初始化 ServerSocketChannel

核心源码:

serverSock = ServerSocketChannel.open();
InetSocketAddress addr = new InetSocketAddress(getAddress(), getPortWithOffset());
serverSock.bind(addr, getAcceptCount());
  1. 打开 ServerSocketChannel。
  2. 绑定端口,指定 backlog

其中端口由 server.port 配置参数指定,backlog 由 server.tomcat.accept-count 配置参数指定,默认值为 100,客户端与服务端完成 TCP 三次握手之后,连接放入等待队列中,ServerSocketChannel 调用 accept() 方法从队列中取出连接。因此,当 Tomcat 达到 max-connections 指定的最大连接数后,还能继续接收 accept-count 数量的连接。

1.3.2.2. 初始化工作线程池

核心源码:

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);
  1. TaskQueue 任务队列继承自 LinkedBlockingQueue,这里无法指定容量,默认容量为 Integer.MAX_VALUE,即无限大。预计未来将支持指定容量,详见 github issues
  2. TaskThreadFactory 线程工厂指定了线程名称前缀为 http-nio-端口-;线程为守护线程;线程优先级为默认值:5。
  3. 线程池核心线程数由 server.tomcat.threads.min-spare 配置参数指定,默认值为 10;线程池最大线程数由 server.tomcat.threads.max 配置参数指定,默认值为 200;空闲线程存活时间 60 秒。

TaskQueue 重写了 offer 方法,使得 Tomcat 线程池与 JDK 线程池创建线程的时机不一样,具体表现为:

  1. 如果线程池里的线程数量等于最大线程数,说明无法再创建新线程,任务加入队列中,等待空闲线程处理。
  2. 如果已提交的任务数小于等于线程池里的线程数量,说明有空闲线程,任务加入队列中,由空闲线程处理。
  3. 如果线程池里的线程数量小于最大线程数,任务无法加入队列,强制线程池新建线程去处理。
  4. 如果以上都不是,任务加入队列,等待空闲线程处理。

核心源码:

@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.getPoolSizeNoLock() == parent.getMaximumPoolSize()) {
        return super.offer(o);
    }
    //we have idle threads, just add it to the queue
    if (parent.getSubmittedCount() <= parent.getPoolSizeNoLock()) {
        return super.offer(o);
    }
    //if we have less threads than maximum force creation of a new thread
    if (parent.getPoolSizeNoLock() < parent.getMaximumPoolSize()) {
        return false;
    }
    //if we reached here, we need to add it to the queue
    return super.offer(o);
}

1.3.2.3. 初始化限流组件 LimitLatch

核心源码:

protected LimitLatch initializeConnectionLatch() {
    if (maxConnections==-1) {
        return null;
    }
    if (connectionLimitLatch==null) {
        connectionLimitLatch = new LimitLatch(getMaxConnections());
    }
    return connectionLimitLatch;
}

最大连接数由 server.tomcat.max-connections 配置参数指定,默认值为 8192,表示同一时间 Tomcat 能够接受的最大连接数量。接受一个新连接 LimitLatch 计数加 1,处理完请求断开连接,LimitLatch 计数减 1。

1.3.3. Acceptor 线程工作流程

flowchart TD flow1["线程启动"] flow2{"停止?"} flow3["尝试 LimitLatch 计数加 1"] flow4{"成功?"} flow6["SocketChannel socket = endpoint.serverSocketAccept() \n 接收新连接"] flow7["SocketChannel 封装为 NioSocketWrapper"] flow8["NioSocketWrapper 封装为 PollerEvent"] flow9["PollerEvent 注册到 Poller 的 SynchronizedQueue 队列,Poller 线程处理队列里的事件"] flow1 --> flow2 flow2 --> |no|flow3 flow3 --> flow4 flow4 --> |no \n 自旋-等待-重试|flow3 flow4 --> |yes|flow6 flow6 --> flow7 flow7 --> flow8 flow8 --> flow9 flow9 --> flow2

1.3.4. Poller 线程工作流程

flowchart TD flow1["线程启动"] flow2{"while(true)"} flow3["Poller#events() \n 处理 SynchronizedQueue 队列里的 PollerEvent 事件"] flow4["Selector#selectedKeys() \n 监听 socket 事件"] flow5["Poller#processKey(SelectionKey sk, NioSocketWrapper socketWrapper) \n 处理监听到的事件"] flow6["AbstractEndpoint#processSocket(SocketWrapperBase socketWrapper, SocketEvent event, boolean dispatch) \n 封装 SocketProcessor 多线程任务,提交到线程池处理"] flow1 --> flow2 flow2 --> |yes|flow3 flow3 --> flow4 flow4 --> flow5 flow5 --> flow6 flow6 --> flow2

SocketProcessor 线程处理请求工作流程

flowchart TD flow1["SocketProcessor#doRun()"] flow2["ConnectionHandler#process(SocketWrapperBase socket, SocketEvent status)"] flow3["Http11Processor#process(SocketWrapperBase socketWrapper, SocketEvent status)"] flow4["CoyoteAdapter#service(Request req, Response res)"] subgraph subgraph1["Connector"] subgraph subgraph1_1["Service"] subgraph subgraph1_1_1["Engine"] subgraph subgraph1_1_1_1["Pipeline"] flow5["StandardEngineValve#invoke(Request request, Response response)"] end end end end subgraph subgraph2["Host"] subgraph subgraph 2_1["Pipeline"] flow6["StandardHostValve#invoke(Request request, Response response)"] end end subgraph subgraph3["Context"] subgraph subgraph 3_1["Pipeline"] flow7["StandardContextValve#invoke(Request request, Response response)"] end end subgraph subgraph4["Wrapper"] subgraph subgraph 4_1["Pipeline"] flow8["StandardWrapperValve#invoke(Request request, Response response)"] end end flow9["FilterChain#doFilter(ServletRequest request, ServletResponse response)"] flow10["DispatcherServlet#service(ServletRequest req, ServletResponse res)"] flow11["RequestMappingHandlerAdapter#handle(HttpServletRequest request, HttpServletResponse response, Object handler)"] flow12["ServletInvocableHandlerMethod#(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs)"] flow13["Controller 层,处理具体业务"] flow1 -->|NioSocketWrapper| flow2 flow2 -->|NioSocketWrapper| flow3 flow3 -->|Request, Response| flow4 flow4 -->|Request, Response| flow5 flow5 -->|Request, Response| flow6 flow6 -->|Request, Response| flow7 flow7 -->|Request, Response| flow8 flow8 -->|ServletRequest, ServletResponse| flow9 flow9 -->|ServletRequest, ServletResponse| flow10 flow10 -->|ServletRequest, ServletResponse, HandlerMethod| flow11 flow11 --> flow12 flow12 --> flow13

1.4. 配置参数优化

服务器配置:

CPU 核心 内存
4 核 8G
server:
  tomcat:
    threads:
      max: 1000
      min-spare: 200
    accept-count: 1000
    max-connections: 10000

标签:架构,Springboot,Tomcat,1.3,--,flow3,线程,class
From: https://www.cnblogs.com/jason207010/p/18211045

相关文章

  • springboot集成kafka解决集群模式下分组ID不同问题
    背景:在集群模式下,每个实例需要分组ID不同,共同消费某个topic,集群下的实例是动态扩展的,无法确认实例的个数,每次项目启动的时候,需要动态的给定kakfa的分组ID,但是分组ID整体是一样的,不能改变。方式1:CURRENT_INSTANCE_GROUP_ID=KafkaConstant.SSE_GROUP.concat(String.valueOf(Sys......
  • 京东面试:SpringBoot同时可以处理多少请求?
    SpringBoot作为Java开发中必备的框架,它为开发者提供了高效且易用的开发工具,所以和它相关的面试题自然也很重要,咱们今天就来看这道经典的面试题:SpringBoot同时可以处理多少个请求?准确的来说,SpringBoot同时可以处理多少个请求,并不取决于SpringBoot框架本身,而是取决于其内......
  • 重构MQ处理架构:MVEL表达式和责任链设计模式应用实践
    重构MQ处理架构:MVEL表达式和责任链设计模式应用实践https://mp.weixin.qq.com/s/_UZhfi1BiGNHQAHWhGus8Q 3.责任链设计模式【3.1定义】责任链模式(ChainofResponsibility)又名职责链模式,是一种行为设计模式,它允许你构建一个由多个对象组成的链,每个对象都有机会处理请求,或者......
  • 麒麟系统下springboot程序开机自启动
    1、编写脚本放置到/etc/systemed/system目录下例如display.service[Unit]Description=display#Documentation=http://www.baidu.com#Requires=network.targetAfter=network.targetelasticsearch.serviceredis.servicemysql.server.service[Service]Type=forkingEn......
  • JAVA计算机毕业设计基于SpringBoot的疫苗接种管理系统(附源码+springboot+开题+论文)
    本系统(程序+源码)带文档lw万字以上 文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景随着全球范围内新冠疫情的爆发和持续,疫苗接种成为了防控疫情的重要手段。然而,疫苗接种的管理涉及到众多的环节和人员,如何有效地管理和跟踪接种者的接......
  • JAVA计算机毕业设计基于SpringBoot的窈窕之求食单平台的设计与实现(附源码+springboot+
    本系统(程序+源码)带文档lw万字以上 文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景随着生活节奏的加快和人们健康饮食意识的提升,越来越多的消费者开始关注菜谱的选择和制作。然而,市场上缺乏一个统一的、便捷的在线平台,用于提供丰富的......
  • 基于SpringBoot+Vue的在线教育平台
    !!!有需要的小伙伴可以通过文章末尾名片咨询我哦!!! ......
  • 基于SpringBoot+Vue的在线拍卖系统
    !!!有需要的小伙伴可以通过文章末尾名片咨询我哦!!! ......
  • 基于SpringBoot+Vue的学科竞赛管理系统
    初衷在后台收到很多私信是咨询毕业设计怎么做的?有没有好的毕业设计参考?能感觉到现在的毕业生和当时的我有着同样的问题,但是当时的我没有被骗,因为现在很多人是被骗的,还没有出学校还是社会经验少,容易相信别人。所以为了大家少踩坑,我推荐一批可以运行的毕业设计和相关资料......
  • 尝试Vue微前端架构的实现
    引言随着前端应用的日益复杂化,单一SPA(单页面应用)模式已难以满足大型企业级项目的需求。微前端(MicroFrontend)作为一种新兴的架构理念,旨在将微服务的思想应用于前端开发,允许不同团队独立开发、部署和维护其应用模块,从而提高开发效率与系统的可维护性。在Vue生态系统中,实现......