程序员必须练就的「性能调优」组合拳【2】
性能调优系列前序文章索引:
程序员必须掌握的性能调优:老兵哥结合个人经历解释了程序员往架构师方向发展时为什么要跨越性能调优这一关,以及介绍了从 X、Y、Z 三个维度优化性能的思路。
从 X 维度优化系统的性能:老兵哥分享了从 X 维度优化系统性能的思路,包括让客户端分计算存储任务、优化交互设计等,主要是作为引子拓宽我们性能调优的思路。
程序员在转型架构师的过程中需要建立流程化、结构化、系统化的思维方式,而性能调优是非常难得的契机,它既给了我们压力,也给了我们动力,跨越它就是突破自己的过程。
X 维度,即业务维度,技术始终是服务业务的,任何技术问题的原点就是业务需求。在启动技术层面的性能优化之前,我们有必要先审视一下业务流程是否合理,交互设计上有没有可以优化的空间等。
Y 维度,待业务维度优化完毕,接下来就是审视技术在实现当前业务流程或交互设计的全链路上有没有可优化的地方,即 HTTP 请求处理全流程,从浏览器到应用容器,再到 Spring、Hibernate、数据库等。
Z 维度,除了沿着 HTTP 请求的横向链路,我们还要审视支持应用系统的纵向技术栈,从上到下包括 JVM、操作系统和硬件等,这是整套应用系统运行的环境,许多性能问题都跟运行环境存在关系。
Y 维度,就是从业务 HTTP 请求的横向处理流程来看,HTTP 请求会穿越网络、计算机、应用容器(Tomcat)、Spring、ORM(Hibernate)、数据库等节点,在这个流程中每个节点都有许多可以可优化的地方,今天老兵哥先谈谈如何通过优化应用容器(Tomcat)来优化系统性能。
建议在阅读本文内容前,先参考下面这个系列的文章了解 Web 应用是怎样处理 HTTP 请求的:
2. 应用容器 Tomcat
2.1 启动参数
操作系统选型,尽可能选择 64 位操作系统,在 64 位系统上 JVM 内存最高可以设置为 3800MB 左右,在 32 位系统上 JVM 内存最高可以设置为 1500MB 左右。另外,我们可以根据系统物理内存大小合理设置下列五个启动参数(在文件 catalina.sh、catalina.bat 中):
-server -Xms300m -Xmx300m -XX:PermSize=100m -XX:MaxPermSize=100m
通常,参数取值符合规则:-Xms=-Xmx,-XX:PermSize=-XX:MaxPermSize。上述参数经过验证,可以稳定运行在各种操作系统平台和 JDK 版本上,通过调参尽可能地压榨服务器性能。具体场景下的参数取值需要具体分析,基本原则就是不要超过空闲物理内存的 80% 即可。如果没有特殊理由,不要设置上述五个参数之外的 JVM 参数,一者无法保证操作系统平台的可移植性,二者过度干涉内存管理会导致无法预料的后果。
非服务方式启动的 TOMCAT 调参方式如下:
在 Linux/Unix 系统上,修改 tomcat_home/bin/catalina.sh,添加以下内容:
JAVA_HOME=/export/home/jdk1.6.0_16 JAVA_OPTS="-server -Xms300m -Xmx300m -XX:PermSize=100m -XX:MaxPermSize=100m -Dcom.sun.management.jmxremote"
在 Windows 系统上,修改 tomcat_home/bin/catalina.bat,添加以下内容:
set JAVA_HOME=C:\Program Files\Java\jdk1.6.0_16 set JAVA_OPTS=-server -Xms300m -Xmx300m -XX:PermSize=100m -XX:MaxPermSize=100m -Dcom.sun.management.jmxremote
两者区别:Linux/Unix 不需要 set,但有”“;Windows 需要set,但不能有”“。服务方式启动的 TOMCAT 调参方式如下,仅限于 Windows 系统:
在 JAVA 选项卡中,设置 JAVA OPTIONS,添加以下三个参数,每行一个,不能并列:
-XX:PermSize=256m -XX:MaxPermSize=256m -Dcom.sun.management.jmxremote
设置 Initial memory pool 为 1000MB。
设置 Maximum menory pool 为 1000MB。
不要设置 thread stack size。
2.2 使用 NIO 的 http1.1 超文本传输协议
Java 的 IO 操作集中在 java.io 这个包当中,基于阻塞 API(即 BIO,Block IO)。对许多应用来说,这样的 API 使用很方便,但某些对性能要求较高的应用,尤其是服务器端应用,往往需要一个更高效的方式来处理 IO。从 JDK1.4 起,NIO API 作为一个基于缓冲区,并能提供非阻塞 IO 操作的 API(即 NIO,non-blocking IO)被引入。BIO 与 NIO 之间最为重要的不同,就是采用 BIO 往往要引入多线程,每个连接分配一个单独的线程;NIO 是使用单线程或者只使用少量线程,所有连接共用一个线程。具体更改方法如下:
打开 Tomcat 的配置文件:$TOMCAT_HOME/conf/server.xml
找到:<Connector port="8080" protocol="http1.1" ...
改为:<Connector port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol"...
2.3 调整线程数
Tomcat 可以采用线程池来提升响应速度,默认创建 5 个线程,最大线程数是 200。如果业务并发量较大,则可以对下列几个参数做些调整,最大线程数可以用“同时在线人数 * 用户每秒操作次数 * 平均操作时间”公式计算:
maxThreads:Tomcat 可创建的最大线程数。
acceptCount:如果当前可用线程数为 0,则将请求放入处理队列中。这个值限定了请求队列的大小,超过这个数值的请求将不予处理。
connectionTimeout:网络连接超时时间,单位毫秒。
minSpareThreads:如果当前没有空闲线程,且没有超过 maxThreads,一次性创建的空闲线程数量。Tomcat 初始化时创建的线程数量也由此值设置。
maxSpareThreads:一旦创建的线程超过此数值,Tomcat会关闭不再需要的线程。
2.4 使用 APR 来增强性能
Tomcat 可以采用 APR(Apache Portable Runtime)提供超强的可伸缩性和性能,更好地集成本地服务器技术。APR 是一个高可移植库,它是 Apache HTTP Server 2.x 的核心。APR 有很多用途,包括访问高级 IO 功能(例如:sendfile、epoll、open SSL 等)、OS 级别的功能(随机数生成、系统状态等)、本地进程管理(共享内存、NT 管道、UNIX socket 等),这些功能使 Tomcat 作为 WEB 应用服务器,能更好地与其它本地 Web 技术集成,让 Tomcat 也可以担当更高性能的前端 Web 应用服务器,而不是仅仅是后端 Java EE 应用服务器。APR 的具体安装步骤如下(下载地址:http://apr.apache.org):
安装 apr 及 apr-util:
> tar zxvf apr-1.3.8.tar.gz > cd apr-1.3.8 > ./configure —prefix=/usr/lib/apr > make > make install > tar zxvf apr-util-1.3.9.tar.gz > cd apr-util-1.3.9 > ./configure —with-apr=/usr/lib/apr > make > make install
安装 tomcat-native.tar.gz,此文件在目录 $TOMCAT_HOME/bin 下:
> tar zxvf tomcat-native.tar.gz > cd tomcat-native-1.1.16-src/jni/native > ./configure —with-apr=/usr/lib/apr > make > make install
在 Tomcat 的启动文件($TOMCAt_HOME/bin/catalina.sh)中加入环境变量:
CATALINA_OPTS=-Djava.library.path=/usr/local/apr/lib
或在操作系统的环境变量(/etc/profile)中添加:
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/apr/lib
重新启动计算机或使用命令 source /etc/profile 使其即时生效。
查看启动日志($TOMCAT_HOME/logs/catalina…….log),如出现如下信息表示APR启动成功:
启动时发现日志中有: Sep 30, 2019 4:32:55 PM org.apache.coyote.http11.Http11AprProtocol start INFO: Starting Coyote HTTP/1.1 on http-8080 Sep 30, 2019 4:32:55 PM org.apache.coyote.ajp.AjpAprProtocol start INFO: Starting Coyote AJP/1.3 on ajp-8009
停止时发现日志中有: Sep 30, 2019 4:27:06 PM org.apache.coyote.http11.Http11AprProtocol destroy INFO: Stopping Coyote HTTP/1.1 on http-8080 Sep 30, 2019 4:27:06 PM org.apache.coyote.ajp.AjpAprProtocol destroy INFO: Stopping Coyote AJP/1.3 on ajp-8009
2.5 集成Web服务器处理静态内容
作为一个 Jsp/Servlet 容器,Tomcat 本身对静态 HTML 文件的处理速度要远逊于 Apache 等 Web 服务器。通过与此类 Web 服务器集成,Tomcat 仅仅处理动态资源请求,静态资源请求则交给 Web 服务器处理,这样可以显著地降低系统负载,从而提高整体响应的速度。