1、Tomcat工做原理javascript
1. TCP的三次握手四次挥手css
三次握手:html
说明:java
类比于A和B打电话:linux
A对B说:你好,我是A,你能听到我说话吗?nginx
B对A说:嗯,我能听到你说话web
A对B说:好,那咱们开始聊天吧redis
在服务器上使用以下命令能看到当前服务器的链接状况sql
netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'数据库
返回结果说明:
LAST_ACK 5 (正在等待处理的请求数)
SYN_RECV 30
ESTABLISHED 1597 (正常数据传输状态)
FIN_WAIT1 51
FIN_WAIT2 504
TIME_WAIT 1057 (处理完毕,等待超时结束的请求数)
四次挥手:
说明:
一样用A和B打电话来讲明:
A对B说:我说完了,我要挂电话了
B对A说:等一下,我还没说完
B继续对A说:我说完了,你能够挂电话了
A对B说:好,我挂电话了
其余参数说明:
CLOSED:无链接是活动的或正在进行
LISTEN:服务器在等待进入呼叫
SYN_RECV:一个链接请求已经到达,等待确认
SYN_SENT:应用已经开始,打开一个链接
ESTABLISHED:正常数据传输状态
FIN_WAIT1:应用说它已经完成
FIN_WAIT2:另外一边已赞成释放
ITMED_WAIT:等待全部分组死掉
CLOSING:两边同时尝试关闭
TIME_WAIT:另外一边已初始化一个释放
LAST_ACK:等待全部分组死掉
2. Tomcat内部结构
上图说明:
•server:指的是整个应用的上下文, 也是最顶层的容器,tomcat中全部的东西都在这个server里边。
•service:指的是一个服务,主要的功能是把connector组件和engine组织起来,使得经过connector组件与整个容器通信的应用可使用engine提供的服务。
•engine:服务引擎,这个能够理解为一个真正的服务器,内部提供了多个虚拟主机对外服务。
•host:虚拟主机,每个虚拟主机至关于一台服务器,而且内部能够部署多个应用,每一个虚拟主机能够绑定一个域名,并指定多个别名。
•context:应用上下文,每个webapp都有一个单独的context,也能够理解为每个context表明一个webapp。
•connector:链接器组件,能够配置多个链接器支持多种协议,如http,APJ 等
组件说明:
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也支持AJP、JServ和JK2链接器。
容器类组件:
•引擎(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所覆盖。
2、优化思路
1. 网络优化
BIO、NIO、NIO二、APR,也就是阻塞与非阻塞
压缩gzip、超时配置,防止close_wait过多。
1.一、非阻塞,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 – 本地链接协议
1.二、启用压缩,消耗CPU,减少网络传输大小
compression="on"
disableUploadTimeout="true"
compressionMinSize="2048"
compressableMimeType="text/html,text/xml,text/plain,text/css,text/javascript,a
pplication/javascript"
URIEncoding="utf-8"
2. 并发优化
最大线程数
最佳并发数。。。
链接数:maxConnections(最大链接数)
处理线程:maxThreads(操做系统容许多少线程,线程多大会引发切换效能)
等候队列:acceptCount(排队数量)指最大链接数已经满了的时候容许多少请求排队
3. 底层优化
JVM优化
多实例(必须的)
操做系统优化
JVM优化:固定堆内存,多线程并发收集,对象预留新生代,大对象进入老年代,启用内联
多实例:多个tomcat实例在一台机上
操做系统优化:网络参数,线程数,关闭IPV6,最大文件数
Linux服务器每进程不容许超过1000个线程,听说六、700线程服务器切换线程就慢下来
命令:ps -eLf | grep java | wc –l 能够查看当前启动的java进程里面有多少个线程
Linux线程栈大小是8M,可使用ulimit –s设置
3、优化实战
1. 优化tomcat.conf配置文件
/etc/tomcat/tomcat.conf文件修改JAVA_OPTS
JAVA_OPTS=“-server –Xmx2048m–Xms2048m –Xmn768m - XX:TargetSurvivorRatio=90 -XX:PetenureSizeThreshold=1000000 - XX:MaxTenuringThreshold=30 –XX:+UseParallelGC
–XX:+UseConcMarkSweepGC –XX:ParallelGCThreads=2"
2. 优化server.conf配置文件
/etc/tomcat/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 6 、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/ja
vascript" URIEncoding="utf-8" keepAliveTimeout="0"
关闭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 "%r" %s %b" />
/>
图示:
3. linux内核优化
3.1 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
3.2 其余的linux配置优化
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
4. 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 时间内一次没被使用,它将被移除。
4、集群优化
当线程数达到250以上,考虑群集部署,集群部署须要考虑的两个问题:Tomcat部署和session共享,Tomcat<4时,可用tomcat内部的集群session共享,不然采用redis方式集群
集群部署原理图:
redis实现session共享的原理
Redis实现seesion共享的步骤以下:
1. 下载如下包放到tomcat的lib目录下
TomcatRedisSessionManager-1.1 .jar
Jredis-2.8.0.jar
Commons-logging-1.2.jar
Commons-pool2-2.4.1.jar
2. 在tomcat里面增长以下配置
<Valve className="tomcat.request.session.redis.RequestSessionHandlerValve"/>
<Manager className="tomcat.request.session.redis.RequestSessionManager"/>
建立一个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
5、压力测试
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/
欢迎工做一到五年的Java工程师朋友们加入Java架构开发:760940986 群内提供免费的Java架构学习资料(里面有高可用、高并发、高性能及分布式、Jvm性能调优、Spring源码,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多个知识点的架构资料)合理利用本身每一分每一秒的时间来学习提高本身,不要再用"没有时间“来掩饰本身思想上的懒惰!趁年轻,使劲拼,给将来的本身一个交代!