Tomcat学习笔记

本文基于tomcat 8.5.50

1. Tomcat 系统架构与原理剖析

1.1 浏览器访问服务器流程

Tomcat学习笔记_第1张图片

1.2 Tomcat 处理请求大致过程

Tomcat学习笔记_第2张图片

  • Http 服务器接收用户发送的请求,然后再交给 Servlet 容器处理,Servlet 容器再调用具体的业务处理类
  • Servlet 容器避免了 Tomcat 与具体的业务处理类耦合

1.3 Tomcat Servlet 容器处理流程

Tomcat学习笔记_第3张图片

  1. Http 服务器接收到 Request 请求后,用 ServletRequest 对象封装请求信息
  2. 然后进一步调用 Servlet 容器某个具体的 Servlet
  3. Servlet 容器通过 url 和 Servlet 的映射关系定位到具体的 Servlet
  4. 如果 Servlet 没有被加载,那么先用反射机制创建这个 Servlet 并调用 init 方法完成初始化
  5. 继续调用这个 Servlet 的 Service 方法,用 ServletResponse 对象封装处理结果
  6. 把 ServletResponse 对象返回给 Http 服务器,Http 服务器再把 Response 返回给客户端

1.4 Tomcat 总体架构

Tomcat 设计了两个核心组件来完成两大核心功能

  • 连接器(Connector):负责对外交流,处理 Socket 连接,负责网络字节流与 Request 和 Response 对象的转换
  • 容器(Container):负责内部处理,加载和管理 Servlet ,处理具体的 Request 请求

Tomcat学习笔记_第4张图片

1.5 Tomcat 连接器 - Coyote

Coyote 将 Socket 输入转换封装为 Request 对象,进一步封装为 ServletRequest 对象交给 Catalina 容器处理,处理请求完成后,Catalina 通过 Coyote 提供的 Response 对象将结果写入输出流。Coyote 避免了 Catalina 与具体的请求协议和 IO 操作方式耦合。

Coyote 内部组件及处理流程
Tomcat学习笔记_第5张图片

  • Endpoint

    Endpoint 是 Coyote 的通信端点,用来实现 TCP / IP 协议,是具体 Socket 接收和发送处理器

  • Processor

    Processor 是 Coyote 的协议处理接口,用来实现 HTTP 协议,接收来自 Endpoint 的 Socket,读取字节流解析成 Tomcat Request 和 Response 对象,并通过 Adapter 将请求提交到容器处理

  • ProtocolHanlder

    ProtocolHanlder 是 Coyote 的协议接口,通过 Endpoint 和 Processor 实现对具体协议的处理能力,Tomcat 根据应用层协议和传输层I/O模型的组合提供了6个实现类

  • Adapter

    CoyoteAdatpter 负责将 Tomcat Request 转换成标准的 ServletRequest,再调用容器

1.6 Tomcat 容器 - Catalina

Catalina 是 Tomcat 的核心,其他模块是通过 conf/server.xml 引入的,Catalina 结构如下

Tomcat学习笔记_第6张图片

  • Catalina

    负责解析 Tomcat 的配置文件(server.xml),以此来创建服务器Server组件并进行管理。

  • Server

    服务器表示整个 Catalina Servlet 容器以及其他组件,负责组装并启动 Servlet 引擎和 Tomcat 连接器。Server 通过实现 Lifecycle 接口,提供了一种优雅的启动和关闭整个系统的方式。

  • Service

    服务是 Server 内部组件,一个 Server 包含多个 Service。Service 将多个 Connector 绑定到一个 Container。

  • Container

    容器负责处理用户的servlet请求,并返回对象给web用户的模块。Container 组件下包含了 Engine、Host、Context 和 Wrapper 4种组件,组件之间是父子关系。

  • Engine

    表示整个 Catalina 的 Servlet 引擎,用来管理多个虚拟站点。一个 Service 最多只能有一个Engine,一个 Engine 可以包含多个 Host。

  • Host

    代表一个虚拟主机(站点),可以包含多个 Context。

  • Context

    表示一个 Web 应用程序,可以包含多个 Wrapper。

  • Wrapper

    Wrapper 表示一个 Servlet,是容器的最底层,没有子容器。

2. Tomcat 服务器核心配置

2.1 Server 标签


<Server port="8005" shutdown="SHUTDOWN">
  
  <Listener className="org.apache.catalina.startup.VersionLoggerListener" />
  
  <Listener className="org.apache.catalina.security.SecurityListener" />
  
  <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
  
  <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
  
  <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
  
  <Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />

  
  <GlobalNamingResources>
    <Resource name="UserDatabase" auth="Container"
              type="org.apache.catalina.UserDatabase"
              description="User database that can be updated and saved"
              factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
              pathname="conf/tomcat-users.xml" />
  GlobalNamingResources>

   
  <Service name="Catalina">
      ...
  Service>
Server>

2.2 Service 标签



<Service name="Catalina">
    
    
    
    
    
    
    <Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />
    
    <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
    
    <Engine name="Catalina" defaultHost="localhost">
        ...
    Engine>
Service>

2.3 Executor 标签


<Executor name="commonThreadPool"
	namePrefix="thread-exec-"
	maxThreads="200"
	minSpareThreads="100"
	maxIdleTime="60000"
	maxQueueSize="Integer.MAX_VALUE"
	prestartminSpareThreads="false"
	threadPriority="5"
	className="org.apache.catalina.core.StandardThreadExecutor"/>

2.4 Connector 标签



<Connector port="8080" 
           protocol="HTTP/1.1" 
           connectionTimeout="20000" 
           redirectPort="8443" />

<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />

<Connector port="8080" 
           protocol="HTTP/1.1"
		   executor="commonThreadPool"
		   maxThreads="1000"
		   minSpareThreads="100"
		   acceptCount="1000"
		   maxConnections="1000"
		   connectionTimeout="20000"
		   compression="on"
		   compressionMinSize="2048"
		   disableUploadTimeout="true"
		   redirectPort="8443"
		   URIEncoding="UTF-8" />

2.5 Engine、Host、Context 标签


<Engine name="Catalina" defaultHost="localhost">
    
	<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true">
        
        <Context docBase="/project_path" path="/hello">Context>
        
        <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
               prefix="localhost_access_log" suffix=".txt"
               pattern="%h %l %u %t "%r" %s %b" />
    Host>
Engine>

3. 手写 mini Tomcat

1)提供服务,接收请求(Socket通信)
2)请求信息封装成Request对象(Response对象)
3)客户端请求资源,资源分为静态资源(html)和动态资源(Servlet)
4)资源返回给客户端浏览器

4. Tomcat 核心流程

管理生命周期的接口类 Lifecycle

4.1 启动流程

通过 startup.sh 调用 catalina.sh 脚本,再调用 Bootstrapmain 方法启动

Tomcat学习笔记_第7张图片

查看 main 方法,有3行代码需要关注

  • bootstrap.init(); // 初始化,主要是创建一个 Catalina 实例
  • daemon.load(args); // 初始化一系列子容器
  • daemon.start(); // 启动一系列子容器

从 daemon.load(args) 开始初始化容器到绑定 0.0.0.0:8080 的堆栈

Tomcat学习笔记_第8张图片

从daemon.start() 开始启动一系列子容器到创建一个Acceptor线程的堆栈

Tomcat学习笔记_第9张图片

4.2 请求流程

  • 大致流程

Tomcat学习笔记_第10张图片

  • 详细流程

Tomcat学习笔记_第11张图片

  • Mapper组件

Tomcat学习笔记_第12张图片

部署到tomcat 跟踪调用

  • 新建一个web项目web-demo,配置servlet
  • 编译后将out文件夹下面的web-demo拷贝到源码项目的source/webapps下
  • 启动源码项目,访问http://localhost:8080/web-app/hello
  • 在NioEndpoint 的 startAcceptorThreads 方法上面的Poller线程类打断点
  • org.apache.tomcat.util.net.NioEndpoint.Poller#processKey

5. Tomcat 类加载机制

5.1 JVM 类加载机制

Tomcat学习笔记_第13张图片

类加载器 作用
引导启动类加载器 BootstrapClassLoader c++编写,加载java核⼼库 java.*,⽐如rt.jar中的类,构造ExtClassLoader和AppClassLoader
扩展类加载器 ExtClassLoader java编写,加载扩展库 JAVA_HOME/lib/ext⽬录下的jar中的类,如classpath中的jre ,javax.*或者java.ext.dir指定位置中的类
系统类加载器 SystemClassLoader
AppClassLoader
默认的类加载器,搜索环境变量 classpath 中指明的路径

当 JVM 运⾏过程中,⽤户⾃定义了类加载器去加载某些类时,会按照下⾯的步骤(⽗类委托机制)

  1. ⽤户⾃⼰的类加载器,把加载请求传给⽗加载器,⽗加载器再传给其⽗加载器,⼀直到加载器
    树的顶层
  2. 最顶层的类加载器⾸先针对其特定的位置加载,如果加载不到就转交给⼦类
  3. 如果⼀直到底层的类加载都没有加载到,那么就会抛出异常 ClassNotFoundExceptio

5.2 双亲委派机制

  • 含义:当某个类加载器需要加载某个.class⽂件时,它⾸先把这个任务委托给他的上级类加载器,递归这个操
    作,如果上级的类加载器没有加载,⾃⼰才会去加载这个类。(先向上找父加载器,然后自顶向下尝试加载)
  • 作用:
    • 防止重复加载class,委托过程中只要加载了就不会访问下一个加载器
    • 保证核心 class 不能被篡改(委托不会篡改 class,即使篡改也不会加载,即使加载也不是同一个 class)

5.3 Tomcat 类加载机制

Tomcat学习笔记_第14张图片

  • 引导类加载器 和 扩展类加载器 的作⽤不变
  • 系统类加载器正常情况下加载的是 CLASSPATH 下的类,但是 Tomcat 的启动脚本并未使⽤该变量,⽽是加载tomcat启动的类,⽐如bootstrap.jar,通常在catalina.bat或者catalina.sh中指定。位于CATALINA_HOME/bin下
  • Common 通⽤类加载器加载Tomcat使⽤以及应⽤通⽤的⼀些类,位于CATALINA_HOME/lib下,⽐如servlet-api.jar
  • Catalina ClassLoader ⽤于加载服务器内部可⻅类,这些类应⽤程序不能访问
  • Shared ClassLoader ⽤于加载应⽤程序共享类,这些类服务器不会依赖
  • Webapp ClassLoader,每个应⽤程序都会有⼀个独⼀⽆⼆的Webapp ClassLoader,他⽤来加载本应⽤程序 /WEB-INF/classes 和 /WEB-INF/lib 下的类。

tomcat 8.5 默认改变了严格的双亲委派机制

  • ⾸先从 Bootstrap Classloader加载指定的类
  • 如果未加载到,则从 /WEB-INF/classes加载
  • 如果未加载到,则从 /WEB-INF/lib/*.jar 加载
  • 如果未加载到,则依次从 System、Common、Shared 加载(在这最后⼀步,遵从双亲委派机制

6. Tomcat 对 HTTPS 的支持

6.1 HTTPS 与 HTTP 的主要区别

  • 需要证书:使用 https 需要到 CA 申请 SSL 证书
  • 默认端口不同:https 默认使用 8443 端口,而 http 默认使用 8080 端口
  • 数据加密:https 是具有 SSL 加密的安全传输协议,对数据的传输进行加密,相当于 http 的升级版
  • 可认证:https 是由 http + SSL协议构建的可进行加密传输和身份认证的网络协议,而http 是无状态不安全的

6.2 HTTPS 工作原理

Tomcat学习笔记_第15张图片

6.3 Tomcat 配置 HTTPS

  1. 使用 JDK 的 keytool 生成免费的秘钥库文件(证书)

    keytool -genkey -alias lagou -keyalg RSA -keystore lagou.keystore

  2. 在 conf/server.xml 添加 SSLHostConfig

    <Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
               maxThreads="150" schema="https" secure="true" SSLEnabled="true">
        <SSLHostConfig>
            <Certificate
            certificateKeystoreFile="${TOMCAT_HOME}/conf/lagou.keystore"
                         certificateKeystorePassword="yourpassword" type="RSA"/>
        SSLHostConfig>
    Connector>
    
  3. 使⽤ https 协议访问 8443 端⼝(https://localhost:8443)

7. Tomcat 性能优化策略

系统性能指标:

  • 响应时间 TR:执行某个操作的耗时

  • 吞吐量 TPS:系统在给定时间内能够支持的事务数量

7.1 JVM 虚拟机优化

  • JVM 内存参数

    参数 作用 建议
    -server 启动Server,以服务端模式运行 建议开启服务端模式
    -Xms 最小堆内存 建议与-Xmx相同
    -Xmx 最大堆内存 建议设置为可用内存的80%
    -XX:MetaspaceSize 元空间初始值
    -XX:MaxMetaspaceSize 元空间最大初始值 默认无限
    -XX:NewRatio 年轻代和老年代大小比值,取整,默认为2 不需要修改
    -XX:SurvivorRatio Eden区和Servivor去大小比值,取整,默认为8 不需要修改

    示例

    JAVA_OPTS="-server -Xms2048m -Xmx2048m -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m"
    

    使用内存映射工具查看 Tomcat 中 JVM 的内存配置:jhsdb jmap --heap --pid xxxx

    Tomcat学习笔记_第16张图片

  • 垃圾回收策略

    垃圾回收性能指标:

    • 吞吐量:工作时间(排除GC时间)占总时间的百分比
    • 暂停时间:由垃圾回收导致的应用程序停止响应次数/时间

    垃圾收集器

    收集器 说明
    串行回收器 Serial Collector 单线程执行垃圾回收工作,回收时工作进程会暂停
    并行回收器 Parallel Collector 多线程执行垃圾回收工作,回收时工作进程任然暂停
    并发标记清除收集器 CMS 适用于愿意缩短垃圾回收暂停时间并且负担得起与垃圾回收共享处理器资源的应用(CPU要好一些)
    G1 收集器 适用于大容量内存的多核服务器,满足GC停顿时间要求的同时,还具备高吞吐量

    垃圾回收器参数

    参数 作用
    -XX:+UserConcMarkSweepGC 启动CMS垃圾回收器,启用后,-XX:+UseParNewGC自动启用
    -XX:+UserG1GC 启动G1垃圾回收器
  • 通过 ${JAVA_HOME}/bin/jconsole.exe 查看 JVM 信息

7.2 Tomcat 自身配置的优化

  • 使用线程池:在 Connector 标签中通过 executor 属性使用公共的线程池
  • 修改 Connector 连接参数:maxConnections、maxThreads、acceptCount
  • 禁用AJP:注释默认的支持AJP的 Connector
  • 调整 IO 模式:Tomcat 8之前的版本默认使用BIO,可以修改 protocol 为 Http11NioProtocol
  • 动静分离:Tomcat 处理动态资源,Nginx 处理静态资源

你可能感兴趣的:(Web服务器,tomcat)