tomcat 相关优化
1、tomcat内存优化 (调优内存是最直接的方式)
默认情况下 tomcat的相关内存配置较低,这对于一些大型项目显然是不够用的,这些项目运行就已经耗费了大部分内存空间,何况大规模访问的情况。即使只有一个页面的超小项目,在并发达到一定程度后也会抛出以下类似异常:
严重: Exception invoking periodic operation: java.lang.OutOfMemoryError: Java heap space
严重: Error processing request java.lang.OutOfMemoryError: GC overhead limit exceeded
说明 tomcat已经无力支持访问处理,内部 GC也已经“无能无力”。所以一般情况下我们需要重新配置 tomcat的相关内存大小, Linux下修改 TOMCAT_HOME/bin/catalina.sh,在其中加入,可以放在 CLASSPATH=下面
JAVA_OPTS="-server -XX:PermSize=512M -XX:MaxPermSize=1024m -Xms2048m -Xmx2048m"
windows下修改 TOMCAT_HOME/bin/catalina.bat,在其中加入,可以放在 set CLASSPATH=下面
set JAVA_OPTS=-server -XX:PermSize=512M -XX:MaxPermSize=1024m -Xms2048m -Xmx2048m
参数说明:
-server:启用 JDK的 server 版本;
-Xms: Java虚拟机初始化时堆的最小内存,一般与 Xmx配置为相同值,这样的好处是 GC不必再为扩展内存空间而消耗性能;
-Xmx: Java虚拟机可使用堆的最大内存;
-XX:PermSize: Java虚拟机永久代大小;
-XX:MaxPermSize: Java虚拟机永久代大小最大值;
除了这些参数外您还可以根据具体需要配置其他参数,参数的配置可以参考 JVM参数的配置
2、内存优化后验证方法
设置成功后我们可以利用 JDK自带的工具进行验证,这些工具都在 JAVA_HOME/bin目录下:
jps:用来显示本地的 java进程,以及进程号,进程启动的路径等。
jmap:观察运行中的 JVM 物理内存的占用情况,包括 Heap size , Perm size等。
进入命令行模式后,进入 JAVA_HOME/bin目录下,然后输入 ./jps命令可查看我们启动的 tomcat的 Bootstrap进程号。然后我们利用 jmap工具查看其内存相关配置
[root@localhost bin]# jps
6515 Bootstrap
6531 Jps
[root@localhost bin]# jmap -heap 6515
Attaching to process ID 6515, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.171-b11
using thread-local object allocation.
Mark Sweep Compact GC
Heap Configuration:
MinHeapFreeRatio = 40
MaxHeapFreeRatio = 70
MaxHeapSize = 2147483648 (2048.0MB)
NewSize = 715784192 (682.625MB)
MaxNewSize = 715784192 (682.625MB)
OldSize = 1431699456 (1365.375MB)
NewRatio = 2
SurvivorRatio = 8
MetaspaceSize = 21807104 (20.796875MB)
CompressedClassSpaceSize = 1073741824 (1024.0MB)
MaxMetaspaceSize = 17592186044415 MB
G1HeapRegionSize = 0 (0.0MB)
Heap Usage:
New Generation (Eden + 1 Survivor Space):
capacity = 644218880 (614.375MB)
used = 114531328 (109.2255859375MB)
free = 529687552 (505.1494140625MB)
17.77832527975585% used
Eden Space:
capacity = 572653568 (546.125MB)
used = 114531328 (109.2255859375MB)
free = 458122240 (436.8994140625MB)
20.00010728999771% used
From Space:
capacity = 71565312 (68.25MB)
used = 0 (0.0MB)
free = 71565312 (68.25MB)
0.0% used
To Space:
capacity = 71565312 (68.25MB)
used = 0 (0.0MB)
free = 71565312 (68.25MB)
0.0% used
tenured generation:
capacity = 1431699456 (1365.375MB)
used = 0 (0.0MB)
free = 1431699456 (1365.375MB)
0.0% used
9746 interned Strings occupying 1537792 bytes.
3、tomcat 配置优化
3.1、Connector 优化
Connector是连接器,负责接收客户的请求,以及向客户端回送响应的消息。所以 Connector的优化是重要部分。默认情况下 tomcat只支持 200线程访问,超过这个数量的连接将被等待甚至超时放弃,所以我们需要提高这方面的处理能力。
修改这部分配置需要修改 TOMCAT_HOME/conf/server.xml,打开 server.xml找到 Connector 标签项,默认配置如下:
其中 port代表服务接口; protocol代表协议类型; connectionTimeout代表连接超时时间,单位为毫秒; redirectPort代表安全通信( https)转发端口,一般配置成 443。
可以看到除了这几个基本配置外并无特殊功能,所以我们需要对 Connector 进行扩展。其中 Connector 支持参数属性可以参考 tomcat官方网站( https://tomcat.apache.org/tomcat-8.0-doc/config/http.html),非常多,所以本文就只介绍些常用的。我们将 Connector 配置修改为如下:
1 、port: 代表 tomcat监听端口,也就是网站的访问端口,默认为 8080,可以根据需要改成其他。
2 、protocol: 协议类型,可选类型有四种,分别为 BIO(阻塞型 IO), NIO, NIO2和 APR。
( 1) BIO: BIO(Blocking I/O),顾名思义,即阻塞式 I/O操作,表示 tomcat使用的是传统的 Java I/O操作 (即 java.io包及其子包 )。 tomcat在默认情况下,是以 bio模式运行的。遗憾的是,就一般而言, bio模式是三种运行模式中性能最低的一种。 BIO配置采用默认即可。
( 2) 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"
( 3) APR: APR(Apache Portable Runtime/Apache可移植运行时 ),是 Apache HTTP服务器的支持库。你可以简单地理解为 :tomcat将以 JNI的形式调用 Apache HTTP服务器的核心动态链接库来处理文件读取或网络传输操作,从而大大地提高 tomcat对静态文件的处理性能。 与配置 NIO运行模式一样,也需要将对应的 Connector节点的 protocol属性值改为:
protocol="org.apache.coyote.http11.Http11AprProtocol"
3 、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等待时间组成。
( 2) CPU的执行时间减少,对 QPS有实质的提升, IO时间的减少,对 QPS提升不明显。如果要想明显提升 QPS,优化系统的时候要着重优化 CPU消耗大户。所以想要找出 maxThreads的最优值可并不容易,没有最好只有更好,更好的值只能通过时间来显现,如果你不想考虑那么多,一般情况下设置成 1000即可。
4 、minSpareThreads: 线程的最小运行数目,这些始终保持运行。如果未指定,默认值为 10。
5 、acceptCount: 当所有可能的请求处理线程都在使用时传入连接请求的最大队列长度。如果未指定,默认值为 100。一般是设置的跟 maxThreads一样或一半,此值设置的过大会导致排队的请求超时而未被处理。所以这个值应该是主要根据应用的访问峰值与平均值来权衡配置。
6 、maxConnections: 在任何给定的时间内,服务器将接受和处理的最大连接数。当这个数字已经达到时,服务器将接受但不处理,等待进一步连接。 NIO与 NIO2的默认值为 10000, APR默认值为 8192。
7 、connectionTimeout: 当请求已经被接受,但未被处理,也就是等待中的超时时间。单位为毫秒,默认值为 60000。通常情况下设置为 30000。
8 、maxHttpHeaderSize: 请求和响应的 HTTP头的最大大小,以字节为单位指定。如果没有指定,这个属性被设置为 8192( 8 KB)。
9 、tcpNoDelay: 如果为 true,服务器 socket会设置 TCP_NO_DELAY选项,在大多数情况下可以提高性能。缺省情况下设为 true。
10 、compression: 是否启用 gzip压缩,默认为关闭状态。这个参数的可接受值为“ off”(不使用压缩),“ on”(压缩文本数据),“ force”(在所有的情况下强制压缩)。
11 、compressionMinSize: 如果 compression="on",则启用此项。被压缩前数据的最小值,也就是超过这个值后才被压缩。如果没有指定,这个属性默认为“ 2048”( 2K),单位为 byte。
12 、disableUploadTimeout: 这个标志允许 servlet Container在一个 servlet执行的时候,使用一个不同的,更长的连接超时。最终的结果是给 servlet更长的时间以便完成其执行,或者在数据上载的时候更长的超时时间。如果没有指定,设为 false。
13 、enableLookups: 关闭 DNS反向查询。
14 、URIEncoding: URL编码字符集。
Connector 还有很多其他参数,可以参考 tomcat官网,这里只介绍与性能相关的部分。
3.2、tomcat的IO优化BIO、NIO、APR
通过配置 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"
以下是几种类型 Connector的参数对比:
并不是说 BIO的性能就一定不如 NIO,这几种类型 Connector之间并没有明显的性能区别,它们之间实现流程和原理不同,所以它们的选择是需要根据应用的类型来决定的。
BIO(同步阻塞 IO)更适合处理简单流程,如程序处理较快可以立即返回结果。服务器实现模式为一个连接一个线程,当然可以通过线程池机制改善。 BIO方式适用于连接数目比较小且固定的架构,这种方式对服务器资源要求比较高,并发局限于应用中, JDK1.4以前的唯一选择,但程序直观简单易理解 .
NIO(分为同步非阻塞 IO,异步阻塞 IO)更适合后台需要耗时完成请求的操作,如程序接到了请求后需要比较耗时的处理这已请求,所以无法立即返回结果,这样如果采用 BIO就会占用一个连接,而使用 NIO后就可以将此连接转让给其他请求,直至程序处理完成返回为止。与 BIO最大的区别,可以复用同一个线程处理多个 connection(多路复用 )。 NIO方式适用于连接数目多且连接比较短(轻操作)的架构,比如聊天服务器,并发局限于应用中,编程比较复杂, JDK1.4开始支持 .
Java NIO2(又叫 AIO异步非阻塞 IO),主要与 NIO的区别主要是操作系统的底层区别,可以做个比喻 :比作快递, NIO就是网购后要自己到官网查下快递是否已经到了 (可能是多次 ),然后自己去取快递; AIO就是快递员送货上门了 (不用关注快递进度 )。 AIO方式使用于连接数目多且连接比较长(重操作)的架构,比如相册服务器,充分调用 OS参与并发操作,编程比较复杂, JDK7开始支持 .
APR可以大大提升 tomcat对静态文件的处理性能,同时如果你使用了 HTTPS方式传输的话,也可以提升 SSL的处理性能。 APR是从操作系统级别来解决异步的 IO问题 ,大幅度的提高性能 . (http://apr.apache.org/ ) 。 APR(Apache Portable Runtime)是一 个高可移植库 , 它 是 Apache HTTP Server 2.x的核心 .能更好地和其它本地 web技术集成,总体上让 Java更有效率作为一个高性能 web服务器平台而不是简单作为后台容器。在产品环境中,特别是直接使用 tomcat做 WEB服务器的时候,应该使用 tomcat Native来提高其性能 .如果不配 APR,基本上 300个线程狠快就会用满,以后的请求就只好等待 .但是配上 APR之后,并发的线程数量明显下降,从原来的 300可能会马上下降到只有几十,新的请求会毫无阻塞的进来 .
在局域网环境测,就算是 400个并发,也是一瞬间就处理 /传输完毕,但是在真实的 Internet环境下,页面处理时间只占 0.1%都不到,绝大部分时间都用来页面传输 .如果不用 APR,一个线程同一时间只能处理一个用户,势必会造成阻塞。所以生产环境下用 apr是非常必要的 .
3.3、线程池
Executor代表了一个线程池,可以在 tomcat组件之间共享。使用线程池的好处在于减少了创建销毁线程的相关消耗,而且可以提高线程的使用效率。要想使用线程池,首先需要在 Service标签中配置 Executor,如下:
....
参数说明:
name:线程池名称,用于 Connector中指定。
namePrefix:所创建的每个线程的名称前缀,一个单独的线程名称为 namePrefix+threadNumber。
maxThreads:池中最大线程数。
minSpareThreads:活跃线程数,也就是核心池线程数,这些线程不会被销毁,会一直存在。
maxIdleTime:线程空闲时间,超过该时间后,空闲线程会被销毁,默认值为 6000( 1分钟),单位毫秒。
maxQueueSize:在被执行前最大线程排队数目,默认为 Int的最大值,也就是广义的无限。除非特殊情况,这个值不需要更改,否则会有请求不会被处理的情况发生。
prestartminSpareThreads:启动线程池时是否启动 minSpareThreads部分线程。默认值为 false,即不启动。
threadPriority:线程池中线程优先级,默认值为 5,值从 1到 10。
className:线程池实现类,未指定情况下,默认实现类为 org.apache.catalina.core.StandardThreadExecutor。如果想使用自定义线程池首先需要实现 org.apache.catalina.Executor接口。
线程池配置完成后需要在 Connector中指定:
运维网声明
1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网 享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com