栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

Tomcat整体架构+启动流程+各种线程 随手小记

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Tomcat整体架构+启动流程+各种线程 随手小记

最近学了一下tomcat启动流程,顺便把里面的各种线程/优化点梳理了一下。因为tomcat架构确实繁杂,也不想大费周章一点点写了,就当给自己的笔记,也就大概自己能看懂了,啊哈哈。

tomcat启动流程图

自己整理了一下uml时序图。主要还是要了解tomcat整体架构,如下图,重点在于了解:

  • connector 负责接收http请求,这时候tomcat还是一个http服务器。
  • Engine,host,context,wrapper 则是负责servlet容器启动,启动后http请求会根据路由规则转发到指定的servlet处理,也就是业务处理都在这一块。


然后自己也画了一份比较精简但核心都有的uml时序图(保存后放大看)。

tomcat里的各种线程

在tomcat的世界里,并不是一条主线程走到黑的,tomcat分了很多线程各司其职,稍微了解整理下各个线程的作用也很重要。

  • 通用线程池 tomcatThreadPool:隶属于service组件下。本来是服务于service底下如果有多个connectors,就会共享一个处理servlet具体工作的通用work线程池,默认被注释掉了。
server.xml


  • StartStopExecutor:host,context,wrapper的启动线程。从engine开始就是tomcat容器的启动,engine下级的host,context,wrapper都不是按次序去启动的,而是丢给 StartStopExecutor 异步执行。
Containerbase::startInternal

  // Start our child containers, if any
 Container children[] = findChildren();
 List> results = new ArrayList<>();
 for (Container child : children) {
     results.add(startStopExecutor.submit(new StartChild(child)));
 }
  • ContainerBackgroundProcessor线程: 用于定时监控项目或者class文件替换时进行热加载热部署。
Containerbase::startInternal

backgroundProcessorFuture = Container.getService(this).getServer().getUtilityExecutor()
        .scheduleWithFixedDelay(new ContainerBackgroundProcessor(),
                backgroundProcessorDelay, backgroundProcessorDelay,
                TimeUnit.SECONDS);
  • acceptor线程: 熟悉http三次握手的,应该知道accept queue,也就是客户端建立连接后应用程序会从这个队列拿取socket连接。然后才有后面的一系列处理流程。acceptor线程就是负责拿取准备好的socket连接的。
NioEndpoint::startInternal

protected void startAcceptorThread() {
    acceptor = new Acceptor<>(this);
    String threadName = getName() + "-Acceptor";
    acceptor.setThreadName(threadName);
    Thread t = new Thread(acceptor, threadName);
    t.setPriority(getAcceptorThreadPriority());
    t.setDaemon(getDaemon());
    t.start();
}
  • Poller线程:Poller线程实际接着Acceptor线程进行处理,这里面有NIO的知识,Poller线程拿到的socket连接放入events队列,通过Selector多路复用器监听 OP_READ 事件,然后遍历key,将 OP_READ 的任务转交给工作线程(exec线程),tomcat10 里poller线程就启动一个了。
NioEndpoint::startInternal

// Start poller thread
poller = new Poller();
Thread pollerThread = new Thread(poller, getName() + "-Poller");
pollerThread.setPriority(threadPriority);
pollerThread.setDaemon(true);
pollerThread.start();
  • work线程:前面说了如果service底下全局的通用线程池 tomcatThreadPool没有的话,每个connector会自己创建一个work线程池。
NioEndpoint::startInternal

// Create worker collection
if (getExecutor() == null) {
    createExecutor();
}
  • AsyncTimeout线程:该线程就是检测异步servlet请求时,触发超时,并将该请求再转发到work线程池处理。
 @Override
    public void start() throws Exception {
        if (getLog().isInfoEnabled()) {
            getLog().info(sm.getString("abstractProtocolHandler.start", getName()));
            logPortOffset();
        }

        endpoint.start();
        monitorFuture = getUtilityExecutor().scheduleWithFixedDelay(
                () -> {
                    if (!isPaused()) {
                        startAsyncTimeout();
                    }
                }, 0, 60, TimeUnit.SECONDS);
    }
tomcat里的参数调优

tomcat调优看起来很高深,但是一些简单的调优项还是可以立即理解学习的,特别是了解了tomcat的整体架构后,对参数的调优也不会只限于死记硬背。

  • acceptCount 和 maxConnections:这两个属于 Connector 的配置项,要放在一起讲。acceptCount 是前面说的 http 三次握手里accept queue 的队列长度,maxConnections 是 tomcat 所能接受的最大连接数。两个属性放一起说就是 – 当连接数达到 maxConnections 时,accept queue 能提供的队列的最大长度。看代码可以知道 maxConnections 会先把第一道关,控制一个连接总量,多出来的连接会阻塞。然后第二道关是 accept queue,accept queue满了之后就会出现连接拒绝或连接超时等情况,一开始我觉得只要控制好 accept queue 的长度就够了,maxConnections有点多余,但是整理下觉得不是这样,maxConnections会让多余的线程阻塞,如果全部由 accept queue 控制并发,会发生很多连接拒绝的情况。下面是官方文档会两个参数的说明。
acceptCount:
The maximum length of the operating system provided queue for incoming connection requests when maxConnections has been reached. The operating system may ignore this setting and use a different size for the queue. When this queue is full, the operating system may actively refuse additional connections or those connections may time out. The default value is 100.

maxConnections:
The maximum number of connections that the server will accept and process at any given time. When this number has been reached, the server will accept, but not process, one further connection. This additional connection be blocked until the number of connections being processed falls below maxConnections at which point the server will start accepting and processing new connections again. Note that once the limit has been reached, the operating system may still accept connections based on the acceptCount setting. The default value is 8192.
For NIO/NIO2 only, setting the value to -1, will disable the maxConnections feature and connections will not be counted.
  • maxThreads:最大work线程数。也是属于 Connector 的配置项,这个就好理解了,acceptor 接收到 socket 连接后就要进行业务处理,也就交给work线程池。
maxThreads:	
The maximum number of request processing threads to be created by this Connector, which therefore determines the maximum number of simultaneous requests that can be handled. If not specified, this attribute is set to 200. If an executor is associated with this connector, this attribute is ignored as the connector will execute tasks using the executor rather than an internal thread pool. Note that if an executor is configured any value set for this attribute will be recorded correctly but it will be reported (e.g. via JMX) as -1 to make clear that it is not used.
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/613434.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号