关于tomcat性能优化
前言
关于 Tomcat 性能调优,一直以来就是运维面试的一个重要话题。今天我们就简单聊聊 Tomcat 如何进行性能优化? 首先声明,我不会去说 Tomcat 是什么,内部结构,原理什么的。我不懂......我只是会说一些我在工作当中的一些参数以及自己所了解的方法,主要还是和大家沟通、交流。
一、关于选型
简单说明,关于Openjdk 和 Oracle jdk的选择,我个人比较倾向于使用Oracle jdk,虽然它很流氓但是我觉得东西还是靠谱;其次是在版本上的选择,建议选择最新稳定版进行在生产环境使用,以此来获得更高效的性能;
一、JVM相关参数优化
export JAVA_OPTS=""-Dfile.encoding=UTF-8 -server -Xms1400M -Xmx1400M -Xss512k
-XX:+AggressiveOpts
-XX:+UseBiasedLocking -XX:PermSize=128M -XX:MaxPermSize=256M
-XX:+DisableExplicitGC -XX:MaxTenuringThreshold=30 -XX:+UseConcMarkSweepGC
-XX:+UseParNewGC -XX:+CMSParallelRemarkEnabled -XX:ReservedCodeCacheSize=32m
-XX:+UseCMSCompactAtFullCollection -XX:LargePageSizeInBytes=128m
-XX:+UseFastAccessorMethods -XX:+UseCMSInitiatingOccupancyOnly
-Djava.awt.headless=true"
提示:在java 8中永久代已被移除,如果你是java8的环境,需要你去掉"-XX:PermSize=128M -XX:MaxPermSize=256M"参数,并且"-XX:MaxTenuringThreshold=31"参数值只能设置在0-15,否则会提示相关错误;
配置说明:
- Tomcat 默认是以 java -client 的方式运行,server 意味着是已真正的生产环境来运行,这样可以获得更高的并发、更高效的垃圾回收能力;
- Xms、Xmx表示JVM 最小内存初始值和最大内存初始值,建议设置为相同参数,以减少CPU对内存资源的调度,避免CPU高速运转进行的垃圾回收;
- Xmn设置年轻代大小为512m。整个堆大小=年轻代大小 + 年老代大小 + 持久代大小。持久代一般固定大小为64m,所以增大年轻代后,将会减小年老代大小。此值对系统性能影响较大,Sun官方推荐配置为整个堆的3/8;
- -Xss是指设定每个线程的堆栈大小。这个就要依据你的程序,看一个线程 大约需要占用多少内存,可能会有多少线程同时运行等。一般不易设置超过1M,要不然容易出现out ofmemory;
- -XX:+AggressiveOpts作用如其名(aggressive),启用这个参数,则每当JDK版本升级时,你的JVM都会使用最新加入的优化技术;
- -XX:+UseBiasedLocking启用一个优化了的线程锁,我们知道在我们的appserver,每个http请求就是一个线程,有的请求短有的请求长,就会有请求排队的现象,甚至还会出现线程阻塞,这个优化了的线程锁使得你的appserver内对线程处理自动进行最优调配;
- -XX:PermSize=128M -XX:MaxPermSize=256M JVM使用-XX:PermSize设置非堆内存初始值,默认是物理内存的1/64;在数据量的很大的文件导出时,一定要把这两个值设置上,否则会出现内存溢出的错误。由XX:MaxPermSize设置最大非堆内存的大小,默认是物理内存的1/4。那么,如果是物理内存4GB,那么64分之一就是64MB,这就是PermSize默认值,也就是永生代内存初始大小;四分之一是1024MB,这就是MaxPermSize默认大小;
- -XX:+DisableExplicitGC在程序代码中不允许有显示的调用”System.gc()”。调用System.gc()付出的代价就是系统响应时间严重降低,就和我在关于Xms,Xmx里的解释的原理一样;
- -XX:+UseParNewGC 对年轻代采用多线程并行回收。
- -XX:+UseConcMarkSweepGC 即CMS gc,这一特性只有jdk1.5即后续版本才具有的功能,它使用的是gc估算触发和heap占用触发。我们知道频频繁的GC会造面JVM的大起大落从而影响到系统的效率,因此使用了CMS GC后可以在GC次数增多的情况下,每次GC的响应时间却很短,比如说使用了CMS GC后经过jprofiler的观察,GC被触发次数非常多,而每次GC耗时仅为几毫秒;
- -XX:+CMSParallelRemarkEnabled在使用UseParNewGC 的情况下, 尽量减少mark的时间;
- -XX:+UseCMSCompactAtFullCollection在使用concurrent gc 的情况下, 防止 memoryfragmention, 对live object 进行整理, 使 memory 碎片减少;
- -XX:LargePageSizeInBytes指定 Java heap的分页页面大小;
- -XX:CMSInitiatingOccupancyFraction=70CMSInitiatingOccupancyFraction,这个参数设置有很大技巧,基本上满足(Xmx-Xmn)*(100- CMSInitiatingOccupancyFraction)/100>=Xmn就 不会出现promotion failed。在我的应用中Xmx是6000,Xmn是512,那么Xmx-Xmn是5488兆,也就是年老代有5488 兆,CMSInitiatingOccupancyFraction=90说明年老代到90%满的时候开始执行对年老代的并发垃圾回收(CMS),这时还 剩10%的空间是5488*10%=548兆,所以即使Xmn(也就是年轻代共512兆)里所有对象都搬到年老代里,548兆的空间也足够了,所以只要满 足上面的公式,就不会出现垃圾回收时的promotion failed,因此这个参数的设置必须与Xmn关联在一起;
Tomcat Connector(Tomcat连接器)有bio、nio、apr三种运行模式,简单介绍(抄百度的,有本事来打我):
- 1. bio(blocking I/O),即阻塞式I/O操作,表示Tomcat使用的是传统的Java I/O操作(即java.io包 及其子包)。Tomcat在默认情况下(敲黑板,主要是在tomcat7或以下的版本),就是以bio模式运行的。遗憾的是,就一般而言,bio模式是三种运行模式中性能最低的一种。
特性:一个线程处理一个请求。缺点:并发量高时,线程数较多,浪费资源。
- 2. 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)更好的并发运行性能。nio目前存在nio以及nio2模式,因此到了Tomcat8.5和Tomcat9.0,则去掉了对BIO的支持。tomcat 8默认以 nio 启动,其他版本自己百度怎么修改为 nio,在启动的时候观察日志:
12-Dec-2017 14:17:46.429 信息 [main] org.apache.coyote.AbstractProtocol.init Initializing ProtocolHandler ["http-nio-8080"]
12-Dec-2017 14:17:46.445 信息 [main] org.apache.tomcat.util.net.NioSelectorPool.getSharedSelector Using a shared selector for servlet write/read
12-Dec-2017 14:17:46.473 信息 [main] org.apache.coyote.AbstractProtocol.init Initializing ProtocolHandler ["ajp-nio-8009"]
12-Dec-2017 14:17:46.474 信息 [main] org.apache.tomcat.util.net.NioSelectorPool.getSharedSelector Using a shared selector for servlet write/read
12-Dec-2017 14:17:46.476 信息 [main] org.apache.catalina.startup.Catalina.load Initialization processed in 1031 ms
特性:利用Java的异步IO处理,可以通过少量的线程处理大量的请求。
- 3. apr(Apache Portable Runtime/Apache可移植运行时),是Apache HTTP服务器的支持库。在tomcat中,又被称为 tomcat native,从操作系统层面解决io阻塞问题。是一个利用 APR 来提升Tomcat性能的本地API。怎么配置?自己查!生产环境,强烈推荐。
3.2 tomcat server.xml配置优化
线程池参数配置:
<?xml version="1.0" encoding="UTF-8"?>
<Service name="Catalina"> <!--The connectors can use a shared executor, you can define one or more named thread pools-->
<!--
<Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
maxThreads="150" minSpareThreads="4"/>
-->
<Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
maxThreads="1000"
minSpareThreads="100"
maxIdleTime="60000"
prestartminSpareThreads = "true"
maxQueueSize = "100"
className="org.apache.catalina.core.StandardThreadExecutor" />
- URIEncoding="UTF-8" 使得tomcat可以解析含有中文名的文件的url;
- minSpareThreads 最小备用线程数,tomcat启动时的初始化的线程数。
- enableLookups 消除DNS查询对性能的影响我们可以关闭DNS查询。
- connectionTimeout为网络连接超时时间毫秒数。
- maxThreads Tomcat使用线程来处理接收的每个请求。这个值表示Tomcat可创建的最大的线程数,即最大并发数。建议值为500-1000,具体根据服务器性能以及压测数据结果测试;
- acceptCount是当线程数达到maxThreads后,后续请求会被放入一个等待队列,这个acceptCount是这个队列的大小,如果这个队列也满了,就直接refuse connection。
- maxProcessors与minProcessors在 Java中线程是程序运行时的路径,是在一个程序中与其它控制线程无关的、能够独立运行的代码段。它们共享相同的地址空间。多线程帮助程序员写出CPU最 大利用率的高效程序,使空闲时间保持最低,从而接受更多的请求。
提示:网上很多混淆了,异步servlet和非阻塞connector,一个是Executor,一个是connector,两者的工作阶段不同。
连接器配置:
<Connector executor="tomcatThreadPool" URIEncoding="utf-8"
port="8080" protocol="org.apache.coyote.http11.Http11Nio2Protocol"
enableLookups="false"
maxConnections="2000"
useURIValidationHack="false"
keepAliveTimeout="60000"
connectionTimeout="20000"
maxThreads="1000"
minSpareThreads="100"
maxSpareThreads="2000"
minProcessors="100"
maxProcessors="1000"
tcpNoDelay="true"
redirectPort="8443" />
- maxThreads="X" 表示最多同时处理X个连接;
- minSpareThreads="X" 初始化X个连接;
- maxSpareThreads="X" 表示如果最多可以有X个线程,一旦超过X个,则会关闭不在需要的线程;
- acceptCount="X" 当同时连接的人数达到maxThreads时,还可以排队,队列大小为X.超过X就不处理;
提示:Tomcat 中可以同时接收的连接数为maxConnections+acceptCount 。上面这些参数需要手动开启,默认值配置都较低,无法发挥最佳性能。可以去你们生产环境看看,是不是很多没有做优化呢;
四、关于性能分析
4.1 常见工具
- 1 jmx 端口获取监控信息(比如,zabbix);
- 2 jps/jstat/jmap等命令进行调试;
- 3 java agent方式获取以及代码植入以探针的方式监控(开源PinPoint);
4.2 其他
查看tomcat连接数:
netstat –nat | grep 8080
查看 tomcat 线程数:
# 查看进程ID
ps -ef |grep java # 查看线程
ps -o nlwp 3598
提示:通过使用该方式可以查看到该进程有多少线程,但并没有排除处于idle状态的线程。所以,要想获取当前进程running的线程数,还需要执行如下命令。
ps -eLo pid,stat | grep 3598 | grep running | wc -l
其中ps -eLo pid,stat可以找出所有线程,并打印其所在的进程号和线程当前的状态;两个grep命令分别筛选进程号和线程状态;wc统计个数。SL表示空闲状态。
关于tomcat性能优化的更多相关文章
- tomcat 性能优化
tomcat 性能优化tomcat默认参数是为开发环境制定,而非适合生产环境,尤其是内存和线程的配置,默认都很低,容易成为性能瓶颈. tomcat内存优化linux修改TOMCAT_HOME/bin/ ...
- Tomcat性能优化(转载)
出处:微信订阅号GitChat精品课程 — Tomcat性能优化 Tomcat 简单介绍 Sun 公司创建了第一个 Servlet 容器,即 Java Web Server,但 JWS 只是为了演示 ...
- tomcat 性能优化(内存优化 线程优化)
转自:http://blog.sina.com.cn/s/blog_4b5bc01101014s81.html tomcat 性能优化 linux修改TOMCAT_HOME/bin/catalina. ...
- Tomcat性能优化之(一) 启动GZIP压缩
Tomcat性能优化之(一) 启动GZIP压缩 1:设置TOMCAT启用GZIP压缩,通过浏览器HTTP访问对应的资源会根据配置进行压缩. <Connector port="8080& ...
- JVM虚拟机详解+Tomcat性能优化
1.JVM(java virtual mechinal) ()JVM有完善的硬件架构,如处理器.堆栈.寄存器当,还具有相应的指令系统. ()JVM的主要工作时解释自己的指令集(即字节码),并映射到本地 ...
- tomcat性能优化梳理
tomcat性能优化 Tomcat本身优化 Tomcat内存优化 启动时告诉JVM我要一块大内存(调优内存是最直接的方式) 我们可以在 tomcat 的启动脚本 catalina.sh 中设置 jav ...
- 闲谈Tomcat性能优化
Tomcat在各位JavaWeb从业者常常就是默认的开发环境,但是Tomcat的默认配置作为生产环境,尤其是内存和线程的配置,默认都很低,容易成为性能瓶颈. 幸好Tomcat还有很多的提升空间.下文介 ...
- tomcat 性能优化(转)
tomcat nginx默许的post大小限制 tomcat nginx默认的post大小限制执行大文件上传,或者,大数据量提交时,当提交的数据大小超过一定限制时,发现后台从request取值的代码r ...
- Tomcat性能优化及JVM内存工作原理
Java性能优化原则:代码运算性能.内存回收.应用配置(影响Java程序主要原因是垃圾回收,下面会重点介绍这方面) 代码层优化:避免过多循环嵌套.调用和复杂逻辑. Tomcat调优主要内容如下: 1. ...
- Tomcat性能优化及常用命令整理
1汤姆猫性能优化 1.1连接参数 1.1.1默认连接配置 默认连接器采用阻塞式 IO,默认最大线程数为200,配置如下: <Connector port="8080" pro ...
随机推荐
- Mac下MySQL与MySQLWorkbench的安装
通过查阅各种各样的资料,去安装这些东东.最后经过一番周折终于安装完成.下面是对安装过程和遇到的问题做个简单记录. 一. 下载MySQL和MySQL Workbench http://dev.mysql ...
- 离线安装IDEA插件
1.idea插件官网http://plugins.jetbrains.com/idea 搜索并下载对应的插件的zip包 2.打开软件进行离线安装 IDEA-->Setting-->Plug ...
- 2017-2018-2 20155303『网络对抗技术』Exp9:Web安全基础
2017-2018-2 『网络对抗技术』Exp9:Web安全基础 --------CONTENTS-------- 一.基础问题回答 1.SQL注入攻击原理,如何防御? 2.XSS攻击的原理,如何防御 ...
- Dubbo本地存根
在远程调用服务提供者的实现之前,如果需要做一些参数验证.缓存.判断.小功能等等,满足要求再调用服务提供者的远程服务,则我们可以通过编写一个本地存根来实现这种功能. (1).在公共项目中或服务消费者项目 ...
- 【转】Python基础语法
[转]Python基础语法 学习一门编程语言,通常是学习该语言的以下几个部分的内容: 基础语法:如,变量的声明与调用.基本输出语句.代码块语法.注释等: 数据类型:通常都为 数字.字符串.布尔值.数组 ...
- 简述JavaScript全局对象
全局对象是JavaScript中非常重要的一类对象,它作为程序顶层(程序最顶端,不包括在任何函数之内)的上下文存在,JavaScript中的全局属性.全局函数都是通过全局对象来提供给程序的,比如 全局 ...
- 《Joint Face Detection and Alignment using Multi-task Cascaded Convolutional Networks》
<Joint Face Detection and Alignment using Multi-task Cascaded Convolutional Networks> 论文主要的三个贡 ...
- C# 清理消息管道的消息
using System;using System.Collections.Generic;using System.Linq;using System.Messaging;using System. ...
- 【转】snprintf()函数使用方法
众所周知,sprintf不能检查目标字符串的长度,可能造成众多安全问题,所以都会推荐使用snprintf. 注:sprintf()函数:int sprintf( char *buffer, const ...
- mybatis二级缓存应用及与ehcache整合
mybaits的二级缓存是mapper范围级别,除了在SqlMapConfig.xml设置二级缓存的总开关,还要在具体的mapper.xml中开启二级缓存. 1.开启mybatis的二级缓存 在核心配 ...