优化tomcat参数

这里以tomcat7的参数配置为例,需要修改conf/server.xml文件,主要是优化连接配置,关闭客户端dns查询。

<Connector port="8080" 
  protocol="org.apache.coyote.http11.Http11NioProtocol" 
  connectionTimeout="20000" 
  redirectPort="8443" 
  maxThreads="500" 
  minSpareThreads="20" 
  acceptCount="100" 
  disableUploadTimeout="true" 
  enableLookups="false" 
  URIEncoding="UTF-8" />
  • port:代表Tomcat监听端口,也就是网站的访问端口,默认为8080,可以根据需要改成其他。

  • protocol:协议类型,可选类型有四种,分别为BIO(阻塞型IO),NIO,NIO2和APR。

    • BIO:BIO(Blocking I/O),顾名思义,即阻塞式I/O操作,表示Tomcat使用的是传统的Java I/O操作(即java.io包及其子包)。Tomcat在默认情况下,是以bio模式运行的。遗憾的是,就一般而言,bio模式是三种运行模式中性能最低的一种。BIO配置采用默认即可。

    • NIO:NIO(New I/O),是Java SE 1.4及后续版本提供的一种新的I/O操作方式(即java.nio包及其子包)。Java nio是一个基于缓冲区、并能提供非阻塞I/O操作的java API,因此nio也被看成是non-blocking I/O的缩写。它拥有比传统I/O操作(bio)更好的并发运行性能。要让Tomcat以nio模式来运行也比较简单,我们只需要protocol类型修改为:

    • //NIO protocol="org.apache.coyote.http11.Http11NioProtocol"

    • //NIO2 protocol="org.apache.coyote.http11.Http11Nio2Protocol"

  • APR:APR(Apache Portable Runtime/Apache可移植运行时),是Apache HTTP服务器的支持库。你可以简单地理解为:Tomcat将以JNI的形式调用 Apache HTTP服务器的核心动态链接库来处理文件读取或网络传输操作,从而大大地提高 Tomcat对静态文件的处理性能。

与配置NIO运行模式一样,也需要将对应的Connector节点的protocol属性改为: protocol="org.apache.coyote.http11.Http11AprProtocol"

  • maxThreads:由该连接器创建的处理请求线程的最大数目,也就是可以处理的同时请求的最大数目。如果未配置默认值为200。如果一个执行器与此连接器关联,则忽略此属性,因为该属性将被忽略,所以该连接器将使用执行器而不是一个内部线程池来执行任务。

maxThreads是一个重要的配置属性,maxThreads配置的合理直接影响了Tomcat的相关性能,所以这里我们重点讨论下。

maxThreads并不是配置的越大越好,事实上你即使配置成999999也是没有用的,因为这个最大值是受操作系统及相关硬件所制约的,并且最大值并不一定是最优值,所以我们追寻的应该是最优值而不是最大值。

QPS(Query Per Second):每秒查询率QPS是对一个特定的查询服务器在规定时间内所处理流量多少的衡量标准。我们常常使用 QPS值来衡量一个服务器的性能。

QPS = 并发数 / 平均响应时间 或者 并发数 = QPS * 平均响应时间

一个系统吞吐量通常由QPS、并发数两个因素决定,每套系统的这两个值都有一个相对极限值,在应用场景访问压力下,只要某一项达到系统最高值,系统的吞吐量就上不去了,如果压力继续增大,系统的吞吐量反而会下降,原因是系统超负荷工作,上下文切换、内存等等其它消耗导致系统性能下降。所谓吞吐量这里可以理解为每秒能处理请求的次数。

所以选择一个合理的 maxThreads值,其实并不是那么容易的事。因为过多的线程只会造成,更多的内存开销,更多的CPU开销,但是对提升QPS确毫无帮助;找到最佳线程数后通过简单的设置,可以让web系统更加稳定,得到最高,最稳定的QPS输出。

我们可以通过以下几种方式来获取 maxThreads的最佳值:

(1)通过线上系统不断使用和用户的不断增长来进行性能测试,观察QPS,响应时间,这种方式会在爆发式增长时系统崩溃,如双12等。

(2)根据公式计算,服务器端最佳线程数量=((线程等待时间+线程cpu时间)/线程cpu时间) * cpu数量,这种方式有时会被误导,因为某些系统处理环节可能会耗时比较长,从而影响公式的结果。

(3)单、多用户压力测试,查看CPU的消耗,然后直接乘以百分比,再进行压测,一般这个值的附近应该就是最佳线程数量,这种方式理想场景比较适用,实际情况会比这个复杂的多。

(4)根据系统的自身情况调整,如硬件限制,系统限制,程序处理能力限制等。

(5)定期修改为不同的 maxThreads值,看服务器响应结果及用户反应。

QPS和线程数的关系

(1)在最佳线程数量之前,QPS和线程是互相递增的关系,线程数量到了最佳线程之后,QPS持平,不在上升,甚至略有下降,同时相应时间持续上升。

(2)同一个系统而言,支持的线程数越多(最佳线程数越多而不是配置的线程数越多),QPS越高。

QPS和响应时间的关系

(1)对于一般的web系统,响应时间一般有CPU执行时间+IO等待时间组成。

  • minSpareThreads:线程的最小运行数目,这些始终保持运行。如果未指定,默认值为10。

  • acceptCount:当所有可能的请求处理线程都在使用时传入连接请求的最大队列长度。如果未指定,默认值为100。一般是设置的跟 maxThreads一样或一半,此值设置的过大会导致排队的请求超时而未被处理。所以这个值应该是主要根据应用的访问峰值与平均值来权衡配置。

  • maxConnections:在任何给定的时间内,服务器将接受和处理的最大连接数。当这个数字已经达到时,服务器将接受但不处理,等待进一步连接。NIO与NIO2的默认值为10000,APR默认值为8192。

  • connectionTimeout:当请求已经被接受,但未被处理,也就是等待中的超时时间。单位为毫秒,默认值为60000。通常情况下设置为30000。

  • maxHttpHeaderSize:请求和响应的HTTP头的最大大小,以字节为单位指定。如果没有指定,这个属性被设置为8192(8 KB)。

  • tcpNoDelay:如果为true,服务器socket会设置TCP_NO_DELAY选项,在大多数情况下可以提高性能。缺省情况下设为true。

  • compression:是否启用gzip压缩,默认为关闭状态。这个参数的可接受值为“off”(不使用压缩),“on”(压缩文本数据),“force”(在所有的情况下强制压缩)。

  • compressionMinSize:如果compression="on",则启用此项。被压缩前数据的最小值,也就是超过这个值后才被压缩。如果没有指定,这个属性默认为“2048”(2K),单位为byte。

  • disableUploadTimeout:这个标志允许servlet Container在一个servlet执行的时候,使用一个不同的,更长的连接超时。最终的结果是给servlet更长的时间以便完成其执行,或者在数据上载的时候更长的超时时间。如果没有指定,设为false。

  • enableLookups:关闭DNS反向查询。

  • URIEncoding:URL编码字符集。

server.xml整体架构

首先我们需要知道server.xml中的xml代码块分类,tomcat官网将其主要分为四类:

  • Top Level Elementsserver块是整个配置文件的根元素,而service块代表与引擎关联的一组连接器(connector)。

  • Connectors :表示外部客户端向特定服务发送请求和接收响应的接口(比如我们之前提到的coyote连接器以及对应的NIO等IO模式都是整个范畴内的概念)。

  • Containers:容器(Container)负责处理传入的请求并创建相应的响应。Engine处理对Service的所有请求,Host处理对特定virtual host的所有请求,而Context处理对特定Web应用程序的所有请求。

  • Nested Components:表示可以嵌套在Container元素内的元素。 注意一些元素可以嵌套在任何Container中,而另一些元素只能嵌套在Context中。

Top Level Elements

Server块

Server块代表的是整个catalina servlet容器。因此,它必须是conf/server.xml配置文件中最外面的单个元素。它的属性代表了整个servlet容器的特征。Tomcat9中默认的配置文件中Server块内嵌的子元素为 ListenerGlobalNamingResourcesService(可以嵌套多个)。具体的每个属性参数我们可以查询官网,下面解释默认的参数配置。

<Server port="8005" shutdown="SHUTDOWN">
    <!--
        port : Tomcat监听的关闭服务器的端口 
        shutdown : 关闭服务器的指令字符串
     -->
    
    <!-- 以日志形式输出服务器、操作系统、JVM的版本信息 -->
  <Listener className="org.apache.catalina.startup.VersionLoggerListener" />

    <!-- 启动和停止APR。如果找不到APR库会输出日志但并不影响tomcat正常启动 -->
  <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="off" />
    <!-- 
        注意这里的SSLEngine默认是打开的(on)
        如果启用了apr作为连接器的协议
        但是只配置了http而没有配置https
        则会报错    
    -->
  
    <!-- 用于避免JRE内存泄漏问题 --> 
  <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
  
    <!-- 用户加载(服务器启动)和销毁(服务器停止)全局命名服务 -->
  <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
  
    <!-- 用于在Context停止时重建Executor池中的线程, 以避免ThreadLocal相关的内
存泄漏 -->
  <Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />

    <!-- GlobalNamingResources中定义了全局命名服务: -->
  <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" />
              <!--这里定义的文件就是我们前面配置manager和host manager的用户的文件-->
  </GlobalNamingResources>
  
  <Service>
    ...
  </Service>
 
 </Server>

Listener

listener可以嵌套在Server、 Engine、Host或 Context中。某些侦听器仅旨在嵌套在特定元素中。这些限制在下面的文档中注明。

Listener的所有实现都 支持以下属性:className:要使用的实现的 Java 类名。这个类必须实现org.apache.catalina.LifecycleListener 接口。

tomcat默认内置了一些Listener如下:

  • VersionLoggerListener(以志形式输出服务器 、操作系统、JVM的版本信息)

版本日志记录生命周期监听器,会在Tomcat 启动时记录 Tomcat、Java 和操作系统信息。

此侦听器只能嵌套在Server 元素中,并且应该是第一个定义的侦听器。

属性

描述

logArgs

如果true是,将记录 Tomcat 启动时传递给 Java 的命令行参数。如果未指定, true将使用默认值。

logEnv

如果true是 ,将记录 Tomcat 启动时的当前环境变量。如果未指定, false将使用默认值。

logProps

如果true,将记录当前的 Java 系统属性。如果未指定, false将使用默认值。

  • AprLifecycleListener (加载(服务器启动) 和 销毁 (服务器停) APR。 如果找不到APR库, 则会输出志, 并不影响 Tomcat启动)

APR 生命周期侦听器检查 APR/本机库是否存在,如果存在则加载该库。有关详细信息,请参阅APR/本地指南

此侦听器只能嵌套在Server 元素中。

  • JreMemoryLeakPreventionListener (避免JRE内存泄漏问题)

JRE 内存泄漏预防侦听器为 Java 运行时环境使用上下文类加载器加载单例的已知位置提供了解决方法,因为如果 Web 应用程序类加载器恰好是当时的上下文类加载器,这将导致内存泄漏. 解决方法是在此侦听器启动时初始化这些单例,因为当时 Tomcat 的公共类加载器是上下文类加载器。它还为可能导致 JAR 文件锁定的已知问题提供了解决方法。

此侦听器只能嵌套在Server 元素中。

属性

描述

appContextProtection

启用保护,以便 sun.awt.AppContext.getAppContext()由 Web 应用程序触发的调用不会导致内存泄漏。

请注意,启用此保护将触发对图形环境的要求,除非 Java 以无头模式启动。默认值为false.

如果在 Java 8 及更高版本上运行,此保护将被禁用,因为 Java 8 及更高版本已修复泄漏。

AWTThreadProtection

启用保护,以便 java.awt.Toolkit.getDefaultToolkit()由 Web 应用程序触发的调用不会导致内存泄漏。

默认为,false因为启动了 AWT 线程。如果在 Java 9 及更高版本上运行,此保护将被禁用,因为 Java 9 及更高版本已修复泄漏。

classesToInitialize

在此侦听器启动期间要加载和初始化的逗号分隔的完全限定类名称列表。这允许预加载已知会引发类加载器泄漏的类,

如果它们在请求处理期间加载。可以引用非 JRE 类,例如 oracle.jdbc.driver.OracleTimeoutThreadPerVM.

默认值为空,但特定的 JRE 类由此侦听器的其他属性管理的其他泄漏保护功能加载。

driverManagerProtection

第一次使用java.sql.DriverManager将触发加载对当前类加载器及其父类可见的 JDBC 驱动程序。

在大多数情况下,Web 应用程序级别的内存泄漏保护可以解决此问题,但在此处触发加载具有较少的副作用。

默认值为true.

forkJoinCommonPoolProtection

启用保护,以便为其创建的线程 ForkJoinPool.commonPool()不会导致内存泄漏。

通过设置 java.util.concurrent.ForkJoinPool.common.threadFactory 系统属性启用保护。

如果在 Tomcat 启动时设置了此属性,则即使显式启用了此保护,Tomcat 也不会覆盖它。默认值为true.

此保护仅在 Java 8 上运行时使用。公共池在早期版本中不存在,并且 Java 9 及更高版本已修复泄漏。

gcDaemonProtection

启用保护,以便 sun.misc.GC.requestLatency(long)由 Web 应用程序触发的调用不会导致内存泄漏。

使用 RMI 可能会触发对该方法的调用。启用此保护的一个副作用是创建了一个名为“GC Daemon”的线程。

该保护使用反射来访问内部 Sun 类,并且可能会在非 Sun JVM 上启动时产生错误。默认值为true.

如果在 Java 9 及更高版本上运行,此保护将被禁用,因为 Java 9 及更高版本已修复泄漏。

ldapPoolProtection

启用保护,以便启动的 PoolCleaner 线程 com.sun.jndi.ldap.LdapPoolManager不会导致内存泄漏。LdapPoolManager如果系统属性 com.sun.jndi.ldap.connect.pool.timeout设置为大于 0 的值,则线程在第一次使用该类时启动。 如果没有此保护,如果 Web 应用程序使用此类,PoolCleaner 线程将被配置为线程的上下文类加载器设置为Web 应用程序类加载器,这反过来会在重新加载时触发内存泄漏。默认为 true. 如果在 Java 9 及更高版本上运行,此保护将被禁用,因为 Java 9 及更高版本已修复泄漏。

securityLoginConfigurationProtection

启用保护,以便 javax.security.auth.login.ConfigurationWeb 应用程序对类的使用不会引起内存泄漏。

此类的第一次访问将触发初始化程序,该初始化程序将保留对上下文类加载器的静态引用。

保护使用系统类加载器加载类,以确保静态初始化程序不会被 Web 应用程序触发。

默认为true.

如果在 Java 8 及更高版本上运行,此保护将被禁用,因为 Java 8 及更高版本已修复泄漏。

securityPolicyProtection

启用保护,以便 javax.security.auth.PolicyWeb 应用程序使用已弃用的类不会导致内存泄漏。

此类的第一次访问将触发静态初始化程序,该初始化程序将保留对上下文类加载器的静态引用。

保护调用getPolicy() 此类的方法以确保静态初始化程序不会被 Web 应用程序触发。默认为true.

注意:底层泄漏已在 Java 7 update 51 及 Java 8 及更高版本中得到修复。因此,如果在 Java 8 及更高版本上运行,则禁用此保护。

tokenPollerProtection

启用保护,以便任何由 初始化的令牌轮询线程 sun.security.pkcs11.SunPKCS11.initToken()都不会导致内存泄漏。

作为 Java 密码体系结构初始化的一部分,线程根据各种条件启动。如果没有保护,这可能会在 Webapp 部署期间在初始化用于生成会话 ID 的 MessageDigest 时发生。

因此,线程将 Webapp 类加载器作为其线程上下文类加载器。启用保护会在 Tomcat 启动期间尽早初始化 JCA。

默认为true. 如果在 Java 9 及更高版本上运行,此保护将被禁用,因为 Java 9 及更高版本已修复泄漏。

urlCacheProtection

启用保护,以便使用 java.netjava.net.URLConnections 从 JAR 文件读取资源不会导致 JAR 文件被锁定。

请注意,启用此保护默认情况下会为通过 java.net.URLConnections 获得的所有资源禁用缓存。

可以根据需要根据具体情况重新启用缓存。默认为true.

xmlParsingProtection

启用保护,以便在 Web 应用程序中解析 XML 文件不会导致内存泄漏。

请注意,内存分析器可能不会显示与此泄漏相关的 GC 根,因此特别难以诊断。

默认为true. 如果在 Java 9 及更高版本上运行,此保护将被禁用,因为 Java 9 及更高版本已修复泄漏。

JreMemoryLeakPreventionListener 示例

//以下是如何配置 classesToInitialize此侦听器的属性的示例。
<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener"
            classesToInitialize="oracle.jdbc.driver.OracleTimeoutThreadPerVM" />
//那么OracleTimeoutThreadPerVM类将在侦听器启动期间而不是在请求处理期间加载和初始化。
  • GlobalResourcesLifecycleListener (加载(服务器启动) 和 销毁(服务器停) 全局命名服务)

Global Resources Lifecycle Listener将server.xml 中定义的 Global JNDI 资源初始化为Global Resources元素的一部分。如果没有此侦听器,将无法使用任何全局资源。

此侦听器只能嵌套在Server 元素中。

  • ThreadLocalLeakPreventionListener (在Context停时重建 Executor 池中的线程, 以避免ThreadLocal 相关的内存泄漏)

在停止Context时触发Executor池中 的线程更新,以避免与线程本地相关的内存泄漏。活动线程在执行完任务后回到池中时会一一更新。更新仅发生在其 属性设置为 的上下文中。renewThreadsWhenStoppingContexttrue

此侦听器只能嵌套在Server 元素中。

  • org.apache.catalina.core.JniLifecycleListener - JNI 库加载监听器

JNI 库加载侦听器通过使用共享类加载器(通常是通用类加载器,但在某些配置中可能会有所不同)加载本机库,使多个 Web 应用程序可以使用本机库

监听器支持两个互斥的属性,所以必须使用其中一个,但不能同时使用:

属性

描述

libraryName

本机库的名称,如在 java.lang.System.loadLibrary()

libraryPath

本机库的绝对路径,定义在 java.lang.System.load()

  • org.apache.catalina.security.SecurityListener - 安全生命周期监听器

Security Lifecycle Listener在 Tomcat 启动时执行多项安全检查,并在检查失败时阻止 Tomcat 启动。默认情况下不启用侦听器。要启用它,请取消注释 $CATALINA_BASE/conf/server.xml 中的侦听器。对于 8.5.30 之前的 Tomcat 版本,如果操作系统支持 umask,那么 $CATALINA_HOME/bin/catalina.sh 中获取 umask 的行也需要取消注释。对于 Tomcat 8.5.30 及更高版本,umask 会自动传递到 Tomcat。

  • org.apache.catalina.startup.UserConfig - 用户配置

UserConfig提供用户 Web 应用程序的功能。用户 Web 应用程序将以波浪字符 ("~") 和用户名开头的请求 URI 映射到服务器上该用户主目录中的目录(通常命名为 public_html)。

有关详细信息,请参阅Host元素上的用户 Web 应用程序 特殊功能。

  • org.apache.catalina.util.SystemPropertyReplacerListener - 系统属性替换

此侦听器使用在摘要器上配置的属性源执行系统属性替换。当${parameter} 在系统属性的值中找到表示的参数时,将调用属性源以尝试替换它。

Service块

Service元素用于创建 Service 实例,默认使用 org.apache.catalina.core.StandardService。 默认情况下,Tomcat9中默认仅指定了Service的名称为Catalina

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

Service 可以内嵌的元素为 : ListenerExecutorConnectorEngine ,详细的参数可以点击这里查看官网

Listener 用于为Service 添加生命周期监听器

Executor 用于配置Service 共享线程池

Connector 用于配置 Service 包含的链接器

Engine 用于配置Service中连接器(connector)对应的Servlet 容器引擎

Executor

executor表示可组件之间Tomcat中共享的线程池。默认情况下,Service并未添加共享线程池配置。executor实现了tomcat中的org.apache.catalina.Executor接口。 如果不配置共享线程池,那么Catalina 各组件在用到线程池时会独立创建。由于executorService元素的嵌套元素。为了使它能够被Connector使用,Executor元素必须出现在server.xml中的Connector元素之前。下面展示的是一个简单的executor的配置,具体的配置参数可以点这里查看官网

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

Connector 用于创建链接器实例。默认情况下,server.xml 配置了两个链接器,一个支 持HTTP协议,一个支持AJP协议。因此大多数情况下,我们并不需要新增链接器配置, 只是根据需要对已有链接器进行优化。

<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000"
redirectPort="8443" />
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
  • port为监听的端口,如果设置为0,Tomcat将会随机选择一个可用的端口号给当前Connector 使用

  • protocol为Connector的协议,这里默认的是HTTP和AJP两种协议,后面可以指定对应协议的不同版本,默认情况下会检测本机是否配置了APR库,如果有并且 useAprConnector设置为true则会默认使用APR模式的IO协议,如果无则会使用NIO模式

  • connectionTimeOut :Connector 接收链接后的等待超时时间,单位为毫秒。 -1表示永不超时

  • redirectPort:当前Connector 不支持SSL请求, 接收到了一个请求, 并且也符合 security-constraint 约束, 需要SSL传输,Catalina自动将请求重定向到指定的端口

  • executor : 指定前面提到的共享线程池的名称,也可以通过maxThreads、minSpareThreads 等属性对该connector进行单独配置对应的内部线程池

  • URIEncoding : 用于指定编码URI的字符编码, Tomcat8.x和Tomcat9.x版本默认的编码为 UTF-8 , Tomcat7.x版本默认为ISO-8859-1

engine

Engine 作为Servlet 引擎的顶级元素,内部可以嵌入: Cluster、Listener、Realm、 Valve和Host。

<Engine name="Catalina" defaultHost="localhost">
    ……
</Engine>
  • name:用于指定Engine 的名称, 默认为Catalina

  • defaultHost:默认使用的虚拟主机名称,当客户端请求访问的host无效时,会跳转到默认的host来处理请求

Host

Host 元素用于配置一个虚拟主机,它支持以下嵌入元素:Alias、Cluster、Listener、 Valve、Realm、Context

如果在Engine下配置Realm,那么此配置将在当前Engine下的所有Host中共享。 同样,如果在Host中配置Realm ,则在当前Host下的所有Context 中共享

Context中的Realm优先级 > Host的Realm优先级 > Engine中的Realm优先级

<Host name="localhost"  appBase="webapps"
      unpackWARs="true" autoDeploy="true">
    <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
           prefix="localhost_access_log" suffix=".txt"
           pattern="%h %l %u %t &quot;%r&quot; %s %b" />
    <Alias>www.example.com</Alias>
    <Alias>www.example2.com</Alias>
</Host>

上面这一段Host的配置文件中还额外添加了Valve配置来实现自定义的日志记录。其中一些参数的详细信息和配置方式可以查看官网的说明
The shorthand pattern
pattern="common" corresponds to the Common Log Format defined by '%h %l %u %t "%r" %s %b'.

  • name: 当前Host通用的网络名称,也就是常用的域名,如果有多个域名对应同一个Host的应用,我们可以设置一个或多个Alias来实现访问

  • appBase:当前Host应用对应的目录,当前Host上部署的Web应用均在该目录下(相对路径和绝对路径均可),默认为webapps

  • unpackWARs:设置为true,Host在启动时会将appBase目录下war包解压为目 录。设置为false,Host将直接从war文件启动

  • autoDeploy: 控制tomcat是否在运行时定期检测并自动部署新增或变更的web应用

Context

Context的完整配置官网文档,Context 用于配置一个Web应用,默认的配置如下。它支持的内嵌元素为:CookieProcessor,Loader,Manager,Realm,Resources,WatchedResource,JarScanner,Valve。

<Host name="localhost"  appBase="webapps"
       unpackWARs="true" autoDeploy="true">
     <Context docBase="myAppDeploy" path="/myApp">
     ....
     </Context>
</Host>
  • docBase:Web应用目录或者War包的部署路径。可以是绝对路径,也可以是相对于该Context所属的Host中的appBase的相对路径。

  • path:Web应用的Context的访问路径。

假设tomcat的安装目录为/home/tomcat9,Host为默认的localhost, 则该web应用访问的根路径为: http://localhost:8080/myApp,对应的部署文件所存放的路径为:/home/tomcat9/webapps/myAppDeploy

BIO、NIO、APR

Tomcat支持的I/O模型如下表(自8.5/9.0 版本起,Tomcat移除了对BIO的支持),在 8.0 之前 , Tomcat 默认采用的I/O方式为 BIO , 之后改为 NIO。 无论 NIO、NIO2 还是 APR, 在性能方面均优于以往的BIO。

IO模型

描述

NIO

同步非阻塞IO,采用java io类库实现

NIO2

异步非阻塞IO,采用jdk7的NIO2类库

APR

采用Apache可移植运行库实现,是C/C++编写

通过配置 protocol的类型可以使用不同的 Connector处理请求。

  • //BIO protocol="HTTP/1.1"

  • //NIO protocol="org.apache.coyote.http11.Http11NioProtocol"

  • //NIO2 protocol="org.apache.coyote.http11.Http11Nio2Protocol"

  • //APR protocol="org.apache.coyote.http11.Http11AprProtocol"

NIO(New I/O APIs、同步非阻塞)

Tomcat中的NIO模型是使用的JAVA的NIO类库,其内部的IO实现是同步的(也就是在用户态和内核态之间的数据交换上是同步机制),采用基于selector实现的异步事件驱动机制(这里的异步指的是selector这个实现模型是使用的异步机制)。而对于Java来说,非阻塞I/O的实现完全是基于操作系统内核的非阻塞I/O,它将操作系统的非阻塞I/O的差异屏蔽并提供统一的API,让我们不必关心操作系统。JDK会帮我们选择非阻塞I/O的实现方式。

这里需要提一下同步异步和阻塞非阻塞的概念:
同步和异步关注的是消息通信机制,同步异步指的是应用程序发起的调用请求获得的返回值是否一起返回,如果一起返回就是同步,否则就是异步,异步可以通过回调函数等方式实现。
阻塞和非阻塞关注的是程序在等待调用结果时的状态,应用程序发起调用请求之后不能干别的事情直到请求处理完成了就是阻塞,否则就是非阻塞。
所以我个人认为,对于阻塞I/O谈同步异步是没有太大意义的,因为此时进程已经阻塞,想要去干别的事情必须得等请求处理完,而请求处理完必然会得到返回值。
上面我们提到得内核基于回调得事件检测方式二就是典型的异步非阻塞I/O模型。

NIO2(New I/O APIs 2、异步非阻塞、AIO)

NIO2和前者相比的最大不同就在于引入了异步通道来实现异步IO操作,因此也叫AIO(Asynchronous I/O)。NIO.2 的异步通道 APIs 提供方便的、平台独立的执行异步操作的标准方法。这使得应用程序开发人员能够以更清晰的方式来编写程序,而不必定义自己的 Java 线程,此外,还可通过使用底层 OS 所支持的异步功能来提高性能。如同其他 Java API 一样,API 可利用的 OS 自有异步功能的数量取决于其对该平台的支持程度。

异步通道提供支持连接、读取、以及写入之类非锁定操作的连接,并提供对已启动操作的控制机制。Java 7 中用于 Java Platform(NIO.2)的 More New I/O APIs,通过在 java.nio.channels 包中增加四个异步通道类,从而增强了 Java 1.4 中的 New I/O APIs(NIO),这些类在风格上与 NIO 通道 API 很相似。他们共享相同的方法与参数结构体,并且大多数对于 NIO 通道类可用的参数,对于新的异步版本仍然可用。主要区别在于新通道可使一些操作异步执行。

异步通道 API 提供两种对已启动异步操作的监测与控制机制。第一种是通过返回一个 java.util.concurrent.Future 对象来实现,它将会建模一个挂起操作,并可用于查询其状态以及获取结果。第二种是通过传递给操作一个新类的对象,java.nio.channels.CompletionHandler,来完成,它会定义在操作完毕后所执行的处理程序方法。每个异步通道类为每个操作定义 API 副本,这样可采用任一机制。

用的不多,Tomcat,Netty等都使用的是NIO, 因为AIO每个channel都需要预先分配一些缓存。连接量起来后,占用缓存太多,不是太成熟。

文章作者: 刘同学
本文链接:
版权声明: 本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 刘同学的小站
中间件 Tomcat
喜欢就支持一下吧