tomcat
参考:Tomcat的3个参数acceptCount、maxConnections、maxThreads
Tomcat 的核心组件
Tomcat 由 2 大核心组件组成:Connector、Container
Tomcat 处理请求的过程
-
客户端与服务端完成三次握手建立了连接,连接信息会存放在 ServerSocket 连接请求的队列中(队列长度为 acceptCount)
-
如果提交到线程池的任务数没有超过 maxConnections,那么就 ServerSocket.accept() 返回 socket 对象,封装为任务提交到线程池;
-
若队列已满,任何再来的请求将会收到 connection refused 错误,直到有可用的资源来处理它们
当任务被处理完后,则销毁任务以及任务中的 socket 对象,该连接被释放
Connector 的 protocol(协议)
Connector 在处理 HTTP 请求时,会使用不同的 protocol。不同的 Tomcat 版本支持的 protocol 不同,其中最典型的 protocol 包括BIO、NIO 和 APR(Tomcat7 中支持这 3 种,Tomcat8 增加了对 NIO2 的支持,而到了 Tomcat8.5 和 Tomcat9.0,则去掉了对 BIO 的支持)。
-
APR(Apache Portable Runtime):是 Apache 可移植运行库,利用本地库可以实现高可扩展性、高性能;
Apr 是在 Tomcat 上运行高并发应用的首选模式,但需要安装 apr、apr–utils、tomcat–native 等包。
BIO
在 BIO 实现的 Connector 中,处理请求的主要实体是 JIoEndpoint 对象。
JIoEndpoint 维护了 Acceptor 和 Worker:
- Acceptor 接收 socket,然后从 Worker 线程池中找出空闲的线程处理 socket,如果 worker 线程池没有空闲线程,则 Acceptor 将阻塞。
- Worker 是 Tomcat 自带的线程池,如果通过配置了其他线程池,原理与 Worker 类似。
NIO
在 NIO 实现的 Connector 中,处理请求的主要实体是 NIoEndpoint 对象。
NIoEndpoint 中除了包含 Acceptor 和 Worker 外,还使用了 Poller,处理流程如下图所示:
- Acceptor 接收 socket 后,不是直接使用 Worker 中的线程处理请求,而是先将请求发送给了 Poller,而 Poller 是实现 NIO 的关键。Acceptor 向 Poller 发送请求通过队列实现,使用了典型的生产者–消费者模式。
- 在 Poller 中,维护了一个 Selector 对象;当 Poller 从队列中取出 socket 后,注册到该 Selector 中;然后通过遍历 Selector,找出其中可读的 socket,并使用 Worker 中的线程处理相应请求。
- 与 BIO 类似,Worker 也可以被自定义的线程池代替。
在 NIoEndpoint 处理请求的过程中,无论是 Acceptor 接收 socket,还是线程处理请求,使用的仍然是阻塞方式;但在 ”读取socket并交给Worker中的线程” 的这个过程中,使用非阻塞的 NIO 实现,这是 NIO 模式与 BIO 模式的最主要区别(其他区别对性能影响较小,暂时略去不提)。而这个区别,在并发量较大的情形下可以带来 Tomcat 效率的显著提升。
影响并发的 tomcat 参数
-
maxConnections :Tomcat 在任意时刻接收和处理的最大连接数(可以提交给线程池的最大任务数)
当 Tomcat 接收的连接数达到 maxConnections 时,Acceptor 线程不会读取 accept 队列中的连接(socket);这时 accept 队列中的线程会一直阻塞着,直到 Tomcat 接收的连接数小于 maxConnections。
-
acceptCount :允许的最大并发连接数(瞬时连接、瞬时并发数),为 ServerSocket 连接请求的队列长度,默认值为 100
-
maxProcessors(maxThreads ):线程池最大连接线程数。默认值为 200
线程数小于此数时,每次来任务若有空闲线程,使用空闲线程处理,如果没有空闲线程则新建线程处理
如果该 Connector 绑定了 Executor,这个值会被忽略,因为该 Connector 将使用绑定的 Executor,而不是内置的线程池来执行任务。
注:
-
minSpareThreads :线程池最小空闲线程数(多余的空闲线程都将杀死)。默认值为 25
线程数小于此数时,每次来任务都新建线程处理
-
disableUploadTimeout :禁用上传超时,主要用于大数据上传时,允许 Servlet 容器正在执行使用一个较长的连接超时值,以使 Servlet 有较长的时间来完成它的执行,默认值为 false
-
enableLookups :是否反查域名,取值为:true 或 false
若为 true,则可以通过调用 request.getRemoteHost() 进行 DNS 查询来得到远程客户端的实际主机名
补充说明:
-
maxThreads 和 acceptCount 属性对 tomcat 能同时处理的请求数和请求响应时间有直接的影响。
无论 acceptCount 值为多少,maxThreads 直接决定了实际可同时处理的请求数。
-
然而,不管是可立即处理请求还是需要放入等待区,都需要 tomcat 先接受该请求(即接受客户端的连接请求,建立socketchannel),那么 tomcat 同时可建立的连接数(maxConnections 属性值)也会影响可同时处理的请求数。
如何设置 acceptCount 、maxConnections、maxThreads 的值:
-
maxConnections 的设置与 Tomcat 的运行模式有关
如果 tomcat 使用的是 BIO,那么 maxConnections 的值应该与 maxThreads 一致(默认值为 maxThreads)
如果 tomcat使用的是 NIO,maxConnections 值应该远大于 maxThreads(默认值为 10000)
-
Tomcat 能够接收的连接数 = maxThreads + acceptCount
- 在线用户数 = 连接数 + 静态用户数(已登录,但连接已断开,只是在浏览静态数据)(有session对象,没有socket对象)
- 连接数 = 已接受连接数 + 瞬时并发数(acceptCount:在连接队列里等待的socket对象数)
- 已接受连接数 = 线程数(RUNNABLE状态)(正在处理)+ 任务队列中的任务数(已接受,待处理)
影响并发的其他限制因素
-
Tomcat 的运行模式
-
BIO(阻塞式的 Socket 通信)模式
Tomcat8 以下版本,默认的 HTTP 实现是采用 BIO 模式,每个请求都需要创建一个线程处理
-
NIO模式(非阻塞式的 Socket 通信)
Tomcat8 以上版本,默认使用的就是 NIO 模式,在性能上高于阻塞式的,每个请求也不需要创建一个线程进行处理,并发能力比前者高。
-
APR 模式(全称 Apache Portable Runtime)
是 Tomcat 生产环境运行的首选方式。但必须要安装 APR 和 Native,直接启动就支持 APR。
APR 是从操作系统级别解决异步 IO 问题。APR 的本质就是使用 JNI 技术调用操作系统底层的 IO 接口,所以需要提前安装所需要的依赖。
如果操作系统未安装 APR 或者 APR 路径未指到 Tomcat 默认可识别的路径,则 APR 模式无法启动,自动切换启动 NIO 模式。
-
-
Tomcat 是运行在 JVM 上的,所以对 JVM 的调优也是非常有必要的
-
并发能力还与应用的逻辑密切相关,如果逻辑很复杂需要大量的计算,那并发能力势必会下降。
如果每个请求都含有很多的数据库操作(或其他中间件的连接),那么对于数据库的性能要求也是非常高的。
拓展
tomcat 服务器 server.xml 文件
<Server port="8005" shutdown="SHUTDOWN">
<!-- 属性说明
port: 指定一个端口,这个端口负责监听关闭Tomcat的请求
shutdown: 向以上端口发送的关闭服务器的命令字符串
-->
<Listener className="org.apache.catalina.core.AprLifecycleListener" />
<Listener className="org.apache.catalina.mbeans.ServerLifecycleListener" />
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
<Listener className="org.apache.catalina.storeconfig.StoreConfigLifecycleListener"/>
<GlobalNamingResources>
<Environment name="simpleValue" type="java.lang.Integer" value="30"/>
<Resource name="UserDatabase" auth="Container" type="org.apache.catalina.UserDatabase"
description="User database that can be updated and saved"
factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
pathname="conf/tomcat-users.xml" />
</GlobalNamingResources>
<!-- 每个Service元素只能有一个Engine元素。元素处理在同一个<Service>中所有<Connector>元素接收到的客户请求 -->
<Service name="Catalina">
<!-- 属性说明 name: Service的名称 -->
<!-- Connector元素: 由Connector接口定义。<Connector>元素代表与客户程序实际交互的给件, 它负责接收客户请求,以及向客户返回响应结果 -->
<Connector port="8080" maxHttpHeaderSize="8192" maxThreads="150" acceptCount="100"
minSpareThreads="25" maxSpareThreads="75"
connectionTimeout="20000" disableUploadTimeout="true"
enableLookups="false" redirectPort="8443" />
<Connector port="8009" enableLookups="false" redirectPort="8443" protocol="AJP/1.3" />
<!--属性说明
port: 服务器连接器的端口号,该连接器将在指定端口侦听来自客户端的请求
maxThreads: 设定在监听端口的线程的最大数目,这个值也决定了服务器可以同时响应客户请求的最大数目,默认值为200
acceptCount: 当所有可以使用的处理请求的线程都被用光时,可以放到处理队列中的请求数
超过这个数的请求将不予处理,而返回Connection refused错误
minProcessors: 服务器启动时创建的处理请求的线程数,每个请求由一个线程负责
maxProcessors: 最多可以创建的处理请求的线程数
minSpareThreads: 最小备用线程
maxSpareThreads: 最大备用线程
connectionTimeout: 等待超时的时间数(以毫秒为单位)
disableUploadTimeout: 禁用上传超时,主要用于大数据上传时
enableLookups: 如果为true,则可以通过调用request.getRemoteHost()进行DNS查询来得到远程客户端的实际主机名;
若为false则不进行DNS查询,而是返回其ip地址
redirectPort: 服务器正在处理http请求时收到了一个SSL传输请求后重定向的端口号
debug: 日志等级
protocol: 必须设定为AJP/1.3协议
address: 如果服务器有两个以上IP地址,该属性可以设定端口监听的IP地址,默认情况下,端口会监听服务器上所有IP地址
-->
<Engine name="Catalina" defaultHost="localhost">
<!-- 属性说明
name: 对应$CATALINA_HOME/config/Catalina中的Catalina
defaultHost: 缺省的处理请求的虚拟主机名
对应Host元素中的name属性,也就是$CATALINA_HOME/config/Catalina/localhost中的localhost
它至少与其中的一个Host元素的name属性值是一样的
debug: 日志等级
-->
<Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase"/>
<!-- 由Host接口定义。一个Engine元素可以包含多个<Host>元素,每个<Host>的元素定义了一个虚拟主机。它包含了一个或多个Web应用 -->
<Host name="localhost" appBase="webapps" autoDeploy="true" unpackWARs="true"
xmlValidation="false" xmlNamespaceAware="false">
<!-- 属性说明
name: 虚拟主机名。即 $CATALINA_HOME/config/Catalina/localhost中的localhost
appBase: 默认的应用路径,此路径相对于$CATALINA_HOME/ (web应用的基本目录) 。
在autoDeploy为true的情况下,可自动部署应用此路径
autoDeploy: 默认为true,表示如果有新的WEB应用放入appBase并且Tomcat在运行的情况下,自动载入应用
debug: 是日志的调试等级
unpackWARs: 如果为true,在Web应用为*.war时,tomcat会自动将WAR文件解压;
否则不解压,直接从WAR文件中运行应用程序
-->
<Context path="/demm" docBase="E:\projects\demm\WebRoot" debug="0" reloadable="true" >
</Context>
<!-- 属性说明
path: 访问应用的上下文路由URI
如果http://localhost/是应用的根目录,访问此应用接口的url前缀为http://localhost/demm
docBase: WEB应用的目录。即 web应用的文件存放路径或者是WAR文件存放路径
注意:此目录必须符合Java WEB应用的规范
debug: 日志等级
reloadable: 是否在程序有改动时自动重新载入。如果为true,则Tomcat将支持热部署,但会影响性能。
即可以自动检测web应用的/WEB-INF/lib和/WEB-INF/classes目录的变化,自动装载新的JSP和Servlet。
可以在不重起Tomcat的情况下改变web应用。
-->
</Host>
</Engine>
</Service>
</Server>
注:
- tomcat 启动后会默认占用 8080,8009和 8005 三个端口
对网络端口的理解
- 实际上,电脑在网卡上的硬件网络端口只有一个。
- 常说的 1-65535 号端口,并不是真的有这么多个硬件端口,硬件端口实际上只有一个,访问所有端口的数据包都发往这个硬件端口。
- 硬件端口接收到数据包之后进行解析,然后通知监听对应端口的socket对象来取数据。
并发量计算
参考: 并发量计算
几个概念:业务并发用户数、最大并发访问数、系统用户数、同时在线用户数
- 假设一个 OA 系统有 1000 用户,这就是系统用户数
- 最高峰同时有 500 人在线,是“同时在线人数”,也称作“最大业务并发用户数”
- 500 个同时使用系统用户中20%查看系统公告,不构成压力;20%填写表格(只在提交时才会请求,填写对服务器不构成压力);40%在发呆(什么都没做);20%用户不停从一个页面跳转另一个页面(只有这20%对服务器产生了压力)
- 服务器实际压力(能承受的最大并发访问数),既取决于业务并发用户数,还取决于用户的业务场景,**这些可以通过对服务器日志的分析得到,**一般只需要分析典型业务(用户常用,最关注的业务操作)。
估算业务并发用户数的公式(测试人员一般只关心业务并发用户数)
该公式的得出是假设用户的 login session 产生符合泊松分布而估算得到。
假设:OA 系统有1000用户,每天400个用户发访问,每个登录到退出平均时间2小时,在1天时间内用户只在8小时内使用该系统。
C = 400 × 2 / 8 = 100
C^ = 100 + 3 × (100的平方根) = 100 + 3 × 10 = 130
另外,如果知道平均每个用户发出的请求数 u,则系统吞吐量可以估算为 u × C
注意:
- 精确估算,还要考虑用户业务操作存在一定的时间集中性(比如上班后 1 小时内是 OA 系统高峰期),采用公式计算仍然会存在偏差
- 针对例子 OA 系统可以把 1 小时设定为考察时间的粒度,将一天 8 小时划分为 8 个区间,这样可以解决业务操作存在集中性问题,更趋于精准,偏差更小。
系统吞度量要素
系统吞吐量的几个重要参数:QPS(TPS)、并发数、响应时间
-
QPS(TPS)= 并发数 / 平均响应时间
-
一个系统吞吐量通常由 QPS(TPS)、并发数两个因素决定。
-
系统响应时间,由 CPU 运算、IO、外部系统响应等等组成。
tomcat 高并发配置与优化
原文地址:https://blog.csdn.net/footless_bird/article/details/128778798
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.7code.cn/show_13073.html
如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除!