性能优化(Tomcat优化)

工做原理

WEB应用服务器javascript

netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'css

返回结果通常以下:
LAST_ACK 5 (正在等待处理的请求数)
SYN_RECV 30
ESTABLISHED 1597 (正常数据传输状态)
FIN_WAIT1 51
FIN_WAIT2 504
TIME_WAIT 1057 (处理完毕,等待超时结束的请求数)html

其余参数说明:
CLOSED:无链接是活动的或正在进行
LISTEN:服务器在等待进入呼叫
SYN_RECV:一个链接请求已经到达,等待确认
SYN_SENT:应用已经开始,打开一个链接
ESTABLISHED:正常数据传输状态
FIN_WAIT1:应用说它已经完成
FIN_WAIT2:另外一边已赞成释放
ITMED_WAIT:等待全部分组死掉
CLOSING:两边同时尝试关闭
TIME_WAIT:另外一边已初始化一个释放
LAST_ACK:等待全部分组死掉java

Tomcat内部结构linux

server:指的是整个应用的上下文,也是最顶层的容器,tomcat中全部的东西都在这个server里边。
service:指的是一个服务,主要的功能是把connector组件和engine组织起来,使得经过connector组件与整个容器通信的应用可使用engine提供的服
务。
engine:服务引擎,这个能够理解为一个真正的服务器,内部提供了多个虚拟主机对外服务。
host:虚拟主机,每个虚拟主机至关于一台服务器,而且内部能够部署多个应用,每一个虚拟主机能够绑定一个域名,并指定多个别名。
context:应用上下文,每个webapp都有一个单独的context,也能够理解为每个context表明一个webapp。
connector:链接器组件,能够配置多个链接器支持多种协议,如http,APJ等。nginx

性能的定义及表现web

顶级组件:位于配置层次的顶级,而且彼此间有着严格的对应关系。Server
服务类组件:位于Server的下一级。Service
链接器组件:链接客户端(能够是浏览器或Web服务器)请求至Servlet容器。http,https,ajp
容器类组件:包含一组其它组件。Engine,Host,Context
被嵌套的组件:位于一个容器当中,但不能包含其它组件。valve,loger,realm,loder,manager,…
集群类组件: listen,cluster,…redis

Tomcat常见组件:数据库

服务器(server):Tomcat的一个实例,一般一个JVM只能包含一个Tomcat实例;所以,一台物理服务器上能够在启动多个JVM的状况下在每个JVM中启动一个Tomcat实例,每一个实例分属于一个独立的管理端口。这是一个顶级组件。
服务(service):一个服务组件一般包含一个引擎和与此引擎相关联的一个或多个链接器。给服务命名能够方便管理员在日志文件中识别不一样服务产生的日志。一个server能够包含多个service组件,但一般情下只为一个service指派一个server。链接器类组件:
链接器(connectors):负责链接客户端(能够是浏览器或Web服务器)请求至Servlet容器内的Web应用程序,一般指的是接收客户发来请求的位置及服务器端分配的端口。默认端口一般是HTTP协议的8080,管理员也能够根据本身的须要改变此端口。还能够支持HTTPS ,默认HTTPS端口为8443。同时也支持AJP,即(A)一个引擎能够配置多个链接器,但这些链接器必须使用不一样的端口。默认的链接器是基于HTTP/1.1的Coyote。同时,Tomcat也支持AJPJServ和JK2链接器。apache

容器类组件:
引擎(Engine):引擎通是指处理请求的Servlet引擎组件,即Catalina Servlet引擎,它检查每个请求的HTTP首部信息以辨别此请求应该发往哪一个host或context,并将请求处理后的结果返回的相应的客户端。严格意义上来讲,容器没必要非得经过引擎来实现,它也能够是只是一个容器。若是Tomcat被配置成为独立服务器,默认引擎就是已经定义好的引擎。而若是Tomcat被配置为Apache Web服务器的提供Servlet功能的后端,默认引擎将被忽略,由于Web服务器自身就能肯定将用户请求发往何处。一个引擎能够包含多个host组件。
主机(Host):主机组件相似于Apache中的虚拟主机,但在Tomcat中只支持基于FQDN的“虚拟主机”。一个引擎至少要包含一个主机组件。
上下文(Context):Context组件是最内层次的组件,它表示Web应用程序自己。配置一个Context最主要的是指定Web应用程序的根目录,以便Servlet容器可以将用户请求发往正确的位置。Context组件也可包含自定义的错误页,以实如今用户访问发生错误时提供友好的提示信息。被嵌套类(nested)组件:这类组件一般包含于容器类组件中以提供具备管理功能的服务,它们不能包含其它组件,但有些却能够由不一样层次的容器各自配置。
阀门(Valve):用来拦截请求并在将其转至目标以前进行某种处理操做,相似于Servlet规范中定义的过滤器。Valve能够定义在任何容器类的组件中。Valve常被用来记录客户端请求、客户端IP地址和服务器等信息,这种处理技术一般被称做请求转储(request dumping)。请求转储valve记录请求客户端请求数据包中的HTTP首部信息和cookie信息文件中,响应转储valve则记录响应数据包首部信息和cookie信息至文件中。
日志记录器(Logger):用于记录组件内部的状态信息,可被用于除Context以外的任何容器中。日志记录的功能可被继承,所以,一个引擎级别的Logger将会记录引擎内部全部组件相关的信息,除非某内部组件定义了本身的Logger组件。
领域(Realm):用于用户的认证和受权;在配置一个应用程序时,管理员能够为每一个资源或资源组定义角色及权限,而这些访问控制功能的生效须要经过Realm来实现。Realm的认证能够基于文本文件、数据库表、LDAP服务等来实现。Realm的效用会遍布整个引擎或顶级容器,所以,一个容器内的全部应用程序将共享用户资源。同时,Realm能够被其所在组件的子组件继承,也能够被子组件中定义的Realm所覆盖。

优化思路

全局优化思考

非阻塞、传输

网络优化

一、非阻塞,Tomcat8已经取消BIO
四种请求链接模型
HTTP/1.1
org.apache.coyote.http11.Http11Protocol 阻塞模式的链接协议
org.apache.coyote.http11.Http11NioProtocol 非阻塞模式的链接协议
org.apache.coyote.http11.Http11Nio2Protocol 非阻塞模式的链接协议
org.apache.coyote.http11.Http11AprProtocol – 本地链接协议
二、启用压缩,消耗CPU,减少网络传输大小
compression="on"
disableUploadTimeout="true"
compressionMinSize="2048"
compressableMimeType="text/html,text/xml,text/plain,text/css,text/javascript,a
pplication/javascript"
URIEncoding="utf-8

并发优化

链接数:maxConnections(排队数量)
处理线程:maxThreads(操做系统容许多少线程,线程多大会引发切换效能)
等候队列:acceptCount

底层优化

JVM优化:固定堆内存,多线程并发收集,对象预留新生代,大对象进入老年代,启用内联
多实例:多个tomcat实例在一台机上
操做系统优化:网络参数,线程数,关闭IPV6,最大文件数
Linux服务器每进程不容许超过1000个线程,听说六、700线程服务器切换线程就慢下来
查询命令:ps -eLf | grep java | wc –l
Linux线程栈大小是8M,ulimit –s设置

主体优化

示例

tomcat.conf配置

JAVA_OPTS=“-server –Xmx2048M –Xms2048M –Xmn768m -
XX:TargetSurvivorRatio=90 -XX:PetenureSizeThreshold=1000000 -
XX:MaxTenuringThreshold=30 –XX:+UseParallelGC
–XX:+UseConcMarkSweepGC –XX:ParallelGCThreads=2”

server.conf配置

<Executor name="tomcatThreadPool" namePrefix="catalina-exec-" maxThreads="500" 
//最大并发数,默认设置 200,通常建议在 500 ~ 800,根据硬件设施和业务来判断
minSpareThreads="100" //Tomcat 初始化时建立的线程数,默认设置 25
prestartminSpareThreads = "true"//在 Tomcat 初始化的时候就初始化 minSpareThreads 的参数值,
若是不等于 true,minSpareThreads 的值就无效
maxQueueSize = "100"//最大的等待队列数,超过则拒绝请求 />
<Connector executor="tomcatThreadPool" port="8080"
protocol="org.apache.coyote.http11.Http11Nio2Protocol" 
//Tomcat 8 设置 nio2 更好,Tomcat 六、7设置nio更好:org.apache.coyote.http11.Http11NioProtocol
connectionTimeout="20000"
minSpareThreads="100" maxSpareThreads="1000"最大处理链接数线程  
minProcessors="100“同时处理请求的最小数
maxProcessors=“1000” 同时处理请求的最大数
maxConnections="1000" redirectPort="8443"
enableLookups="false" //禁用DNS查询
acceptCount="100" 
//指定当全部可使用的处理请求的线程数都被使用时,能够放处处理队列中的请求数,超过这个数的请求将不予处理,默认设置 100
maxPostSize="10485760" //以 FORM URL 参数方式的 POST 提交方式,限制提交最大的大小,默认是2097152(2兆),它使用的单位是字节。10485760 为 10M。若是要禁用限制,则能够设置为 -1。
compression="on" disableUploadTimeout="true" compressionMinSize="2048"
acceptorThreadCount="2" //用于接收链接的线程的数量,默认值是1。通常这个指须要改动的时候是由于该服务器是一个多核CPU,若是是多核 CPU 通常配置为 2.
compressableMimeType="text/html,text/xml,text/plain,text/css,text/javascript,application/javascript" URIEncoding="utf-8"  keepAliveTimeout ="0"
/>

server.conf

关闭shutdown端口:<Server port="-1" shutdown="SHUTDOWN">
关闭ajp链接:注释<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
取消访问日志Valve阀门:

<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" />

ulimit优化 

linux  默认值 open files  和 max user processes  为 1024

#ulimit -n
1024
#ulimit –u
1024

问题描述: 说明 server 只容许同时打开 1024 个文件,处理1024 个用户进程
使用ulimit -a 能够查看当前系统的全部限制值,使用ulimit -n 能够查看当前的最大打开文件数。
新装的linux 默认只有1024 ,看成负载较大的服务器时,很容易遇到error: too many open files 。
解决方法:
使用 ulimit –n 65535 可即时修改,但重启后就无效了。有以下三种修改方式:
 在/etc/security/limits.conf 最后增长:
* soft nofile 65535
* hard nofile 65535
* soft nproc 65535
* hard nproc 65535    

内核优化

net.ipv4.tcp_syncookies = 1 开启SYN Cookies。当出现SYN等待队列溢出时,启用cookies来处理,可防范少许SYN攻击;
net.ipv4.tcp_tw_reuse = 1 开启重用。容许将TIME-WAIT sockets从新用于新的TCP链接,默认为0
net.ipv4.tcp_tw_recycle = 1 开启TCP链接中TIME-WAIT sockets的快速回收,默认为0,表示关闭。
net.ipv4.tcp_fin_timeout = 30 若是套接字由本端要求关闭,它决定了它保持在FIN-WAIT-2状态的时间。
net.ipv4.tcp_keepalive_time = 1200 当keepalive起用的时候,TCP发送keepalive消息的频度。缺省是2小时
net.ipv4.tcp_keepalive_intvl = 30
net.ipv4.tcp_keepalive_probes = 3 probe 3次(每次30秒)不成功,内核才完全放弃。
tcp_keepalive_time = 7200 seconds (2 hours)
tcp_keepalive_probes = 9
tcp_keepalive_intvl = 75 seconds
net.ipv4.ip_local_port_range = 1024 65000 
用于向外链接的端口范围。缺省状况下很小:32768到61000,改成1024到65000。
net.ipv4.tcp_max_syn_backlog = 8192 
SYN队列的长度,默认为1024,加大队列长度为8192,能够容纳更多等待链接的网络链接数。
net.ipv4.netdev_max_backlog = 1000 表示进入包的最大设备队列,默认300,改大
net.core.tcp_max_tw_buckets = 5000 
系统同时保持TIME_WAIT套接字的最大数量,若是超过这个数字,TIME_WAIT套接字将马上被清除并打印警告信息。默认为180000,改成 5000。
另外能够参考优化内核配置:
/proc/sys/net/core/wmem_max 最大socket写buffer,可参考的优化值:873200
/proc/sys/net/core/rmem_max 最大socket读buffer,可参考的优化值:873200
/proc/sys/net/ipv4/tcp_wmem TCP写buffer,可参考的优化值: 8192 436600 873200
/proc/sys/net/ipv4/tcp_rmem TCP读buffer,可参考的优化值: 32768 436600 873200
/proc/sys/net/ipv4/tcp_mem
一样有3个值,意思是:配置单位为页,不是字节
net.ipv4.tcp_mem[0]:低于此值,TCP没有内存压力. 786432
net.ipv4.tcp_mem[1]:在此值下,进入内存压力阶段. 1048576
net.ipv4.tcp_mem[2]:高于此值,TCP拒绝分配socket. 1572864
/proc/sys/net/core/somaxconn 256
listen()的默认参数,挂起请求的最大数量.默认是128.对繁忙的服务器,增长该值有助于网络性能.
/proc/sys/net/core/optmem_max socket buffer的最大初始化值,默认10K.
/proc/sys/net/ipv4/tcp_retries2 TCP失败重传次数,默认值15.减小到5,以尽早释放内核资源.
net.core.somaxconn = 32768 
socket监听(listen)的backlog上限,是socket的监听队列。好比nginx 定义NGX_LISTEN_BACKLOG默认到511

nginx优化

1. worker_processes 8;    nginx 进程数,建议按照cpu 数目来指定,通常为它的倍数 (如,2个四核的cpu计为8)。
2. worker_cpu_affinity 00000001 00000010 00000100 00001000 00010000 00100000 01000000 10000000;
为每一个进程分配cpu,上例中将8 个进程分配到8 个cpu,固然能够写多个,或者将一个进程分配到多个cpu。
3. worker_rlimit_nofile 65535;
这个指令是指当一个nginx 进程打开的最多文件描述符数目,理论值应该是最多打开文件数(ulimit -n)与nginx 进程数相除,可是nginx 分配请求并非那么均匀,因此最好与ulimit -n 的值保持一致。

查看linux系统文件描述符的方法:
[root@web001 ~]# sysctl -a | grep fs.file
fs.file-max = 789972
fs.file-nr = 510 0 789972

4. use epoll; 使用epoll 的I/O 模型
5. worker_connections 65535;
每一个进程容许的最多链接数, 理论上每台nginx 服务器的最大链接数为worker_processes*worker_connections。
6. keepalive_timeout 60;keepalive 超时时间。
7. client_header_buffer_size 4k;
客户端请求头部的缓冲区大小,这个能够根据你的系统分页大小来设置,通常一个请求头的大小不会超过1k,不过因为通常系统分页都要大于1k,因此这里设置为分页大小。

分页大小能够用命令getconf PAGESIZE 取得。
[root@web001 ~]# getconf PAGESIZE
4096
但也有client_header_buffer_size超过4k的状况,可是client_header_buffer_size该值必须设置为 “ 系统分页大小 ” 的整倍数。

8. open_file_cache max=65535 inactive=60s;
这个将为打开文件指定缓存,默认是没有启用的,max 指定缓存数量,建议和打开文件数一致,inactive 是指通过多长时间文件没被请求后删除缓存。
9. open_file_cache_valid 80s;这个是指多长时间检查一次缓存的有效信息。
10. open_file_cache_min_uses 1;open_file_cache 
指令中的inactive 参数时间内文件的最少使用次数,若是超过这个数字,文件描述符一直是在缓存中打开的,如上例,若是有一个文件在inactive 时间内一次没被使用,它将被移除。

 

集群优化

当线程数达到250以上,考虑群集部署
集群部署须要考虑的两个问题
Tomcat部署,session共享
Tomcat<4时,可用tomcat内部的集群session共享
不然采用redis方式集群

 

Redis session共享

1.tomcat  server.xml配置

<Valve className="tomcat.request.session.redis.RequestSessionHandlerValve"/>
<Manager className="tomcat.request.session.redis.RequestSessionManager"/>

2.jar包
TomcatRedisSessionManager-1.1 .jar
Jredis-2.8.0.jar
Commons-logging-1.2.jar
Commons-pool2-2.4.1.ja

3.安装redis和配置

redis-data-cache.properties,放在conf.d目录
redis.hosts=127.0.0.1:6379
redis.cluster.enabled=false
#- redis database (default 0)
#redis.database=0
#- redis connection timeout (default 2000)
#redis.timeout=2000

 

Ab测试

吞吐率(Requests per second):总请求数 / 处理完成这些请求数所花费的时间
并发链接数(The number of concurrent users,Concurrency Level):一个用户可能同时会产生多个会话,也即链接数
用户平均请求等待时间(Time per request):处理完成全部请求数所花费的时间/ (总请求数 / 并发用户数)服务器平均请求等待时间(Time per request: across all concurrent requests)
计 算 公 式 : 处 理 完 成 所 有 请 求 数 所 花 费 的 时 间 / 总 请 求 数

命令:

ab –n 1000 –c 100 url/
若是只用到一个Cookie,那么只需键入命令:
ab -n 100 -C key=value http://test.com/
若是须要多个Cookie,就直接设Header:
ab -n 100 -H “Cookie: Key1=Value1; Key2=Value2” http://test.com/

 

Jmeter测试