Tomcat中Max-thread配置项对TPS的影响

Tomcat中Max-thread配置项对TPS的影响

压测指标以及对应含义:

image.png

压力工具中的线程数和用户数与 TPS的关系?

Jmeter中线程数即虚拟用户数量;TPS即每秒事务数。在性能测试过程中,TPS 之所以重要,是因为它可以反应出一个系统的处理能力。

我们常说的并发是什么?

我们要先说明"并发"这个概念是靠什么数据来承载的。在上面的内容中,我们说了好多的指标,但并发是需要具体的指标来承载的。你可以说,我的并发是 1000TPS,或者 1000RPS,或者 1000HPS,这都随便你去定义(一般我们使用TPS来定义这个概念)。但是在一个具体的项目中,当你说到并发 1000 这样没有单位的词时,一定要让大家都能理解这是什么。比如一个线程平均处理请求的时间是250ms,压力工具是 4 个并发线程,由于每个线程都可以在一秒内完成 4 个事务,所以总的 TPS 是 16。

本次压测过程中,主要监控的几项指标: tps,响应时间,错误数,线程数,cpu使用率,jvm内存;

tps,响应时间,错误率可以使用jmeter来进行压测,结合报告进行判断;

线程数,cpu使用率,jvm内存则使用jconsole来进行监控。

jmeter相关参数配置以及指标

测试场景:

使用梯度施压的测试场景,最大压力值为600虚拟用户,每次增加30线程,每次施压持续一分钟。

image.png

Jconsole监控tomcat性能指标;

在jdk安装目录下,打开jconsole.exe可执行程序,即可看到如下界面;

image.png

这边可以选择本地进程以及远程进程,远程进程则需要配置

export JAVA_OPTS="${JAVA_OPTS} -Dcom.sun.management.jmxremote"

export JAVA_OPTS="${JAVA_OPTS} -Dcom.sun.management.jmxremote.port=9001"

export JAVA_OPTS="${JAVA_OPTS} -Djava.rmi.server.hostname=x.x.x.x"

export JAVA_OPTS="${JAVA_OPTS} -Dcom.sun.management.jmxremote.ssl=false"

export JAVA_OPTS="${JAVA_OPTS} -Dcom.sun.management.jmxremote.authenticate=false"

正确配置后即可看到应用程序的一个概况:

image.png

tomcat参数调整:

Tomcat主要负责两件事:

1、处理 Socket 连接,负责网络字节流与 Request 和 Response 对象的转化。

2、加载和管理 Servlet,以及具体处理 Request 请求

因此。Tomcat设计了两个核心组件连接器(Connector)和容器(Container)来分别做这两件事情。连接器负责对外交流,容器负责内部处理。

image.png
image.png

连接器用 ProtocolHandler来处理网络连接和应用层协议,包含了 2 个重要部件:

Endpoint 接收到 Socket 连接后,生成一个 SocketProcessor 任务提交到线程池去处理,SocketProcessor 的 run 方法会调用 Processor 组件去解析应用层协议,Processor 通过解析生成 Request 对象后,会调用 Adapter 的 Service 方法。

Tomcat关于ProtocolHandler的实现主要有NIO/NIO2/APR三种方式,分别代表非阻塞io,异步io,APR 本地库实现的非阻塞io;

因此Tomcat调优主要基于两个方向:

线程池参数
image.png

accept-count:最大等待数

官方文档的说明为:当所有的请求处理线程都在使用时,所能接收的连接请求的队列的最大长度。当队列已满时,任何的连接请求都将被拒绝。accept-count的默认值为100。

详细的来说:当调用HTTP请求数达到tomcat的最大线程数时,还有新的HTTP请求到来,这时tomcat会将该请求放在等待队列中,这个acceptCount就是指能够接受的最大等待数,默认100。如果等待队列也被放满了,这个时候再来新的请求就会被tomcat拒绝(connection refused)。

maxThreads:最大线程数

每一次HTTP请求到达Web服务,tomcat都会创建一个线程来处理该请求,那么最大线程数决定了Web服务容器可以同时处理多少个请求。maxThreads默认200,肯定建议增加。但是,增加线程是有成本的,更多的线程,不仅仅会带来更多的线程上下文切换成本,而且意味着带来更多的内存消耗。JVM中默认情况下在创建新线程时会分配大小为1M的线程栈,所以,更多的线程异味着需要更多的内存。

maxConnections:最大连接数

官方文档的说明为:

这个参数是指在同一时间,tomcat能够接受的最大连接数。对于Java的阻塞式BIO,默认值是maxthreads的值;如果在BIO模式使用定制的Executor执行器,默认值将是执行器中maxthreads的值。对于Java 新的NIO模式,maxConnections 默认值是10000。

对于windows上APR/native IO模式,maxConnections默认值为8192,这是出于性能原因,如果配置的值不是1024的倍数,maxConnections 的实际值将减少到1024的最大倍数。

如果设置为-1,则禁用maxconnections功能,表示不限制tomcat容器的连接数。

maxConnections和accept-count的关系为:当连接数达到最大值maxConnections后,系统会继续接收连接,但不会超过acceptCount的值。

maxConnections、maxThreads、acceptCount关系

用一个形象的比喻,通俗易懂的解释一下tomcat的最大线程数(maxThreads)、最大等待数(acceptCount)和最大连接数(maxConnections)三者之间的关系。我们可以把tomcat比做一个火锅店,流程是取号、入座、叫服务员,可以做一下三个形象的类比:

(1)acceptCount 最大等待数

可以类比为火锅店的排号处能够容纳排号的最大数量;排号的数量不是无限制的,火锅店的排号到了一定数据量之后,服务往往会说:已经客满。

(2)maxConnections 最大连接数

可以类比为火锅店的大堂的餐桌数量,也就是可以就餐的桌数。如果所有的桌子都已经坐满,则表示餐厅已满,已经达到了服务的数量上线,不能再有顾客进入餐厅了。

(3)maxThreads:最大线程数

可以类比为厨师的个数。每一个厨师,在同一时刻,只能给一张餐桌炒菜,就像极了JVM中的一条线程。

整个流程如下:

(1)取号:如果maxConnections连接数没有满,就不需要取号,因为还有空余的餐桌,直接被大堂服务员领上餐桌,点菜就餐即可。如果 maxConnections 连接数满了,但是取号人数没有达到 acceptCount,则取号成功。如果取号人数已达到acceptCount,则拿号失败,会得到Tomcat的Connection refused connect 的回复信息。

(2)上桌:如果有餐桌空出来了,表示maxConnections连接数没有满,排队的人,可以进入大堂上桌就餐。

(3)就餐:就餐需要厨师炒菜。厨师的数量,比顾客的数量,肯定会少一些。一个厨师一定需要给多张餐桌炒菜,如果就餐的人越多,厨师也会忙不过来。这时候就可以增加厨师,一增加到上限maxThreads的值,如果还是不够,只能是拖慢每一张餐桌的上菜速度,这种情况,就是大家常见的"上一道菜吃光了,下一道菜还没有上"尴尬场景。

IO模型选择

I/O 调优实际上是连接器类型的选择,一般情况下默认都是 NIO,在绝大多数情况下都是够用的,除非你的 Web 应用用到了 TLS 加密传输,而且对性能要求极高,这个时候可以考虑 APR,因为 APR 通过 OpenSSL 来处理 TLS 握手和加 / 解密。OpenSSL 本身用 C 语言实现,它还对 TLS 通信做了优化,所以性能比 Java 要高。如果你的 Tomcat 跑在 Windows 平台上,并且 HTTP 请求的数据量比较大,可以考虑 NIO.2,这是因为 Windows 从操作系统层面实现了真正意义上的异步 I/O,如果传输的数据量比较大,异步 I/O 的效果就能显现出来。如果你的 Tomcat 跑在 Linux 平台上,建议使用 NIO,这是因为 Linux 内核没有很完善地支持异步 I/O 模型,因此 JVM 并没有采用原生的 Linux 异步 I/O,而是在应用层面通过 epoll 模拟了异步 I/O 模型,只是 Java NIO 的使用者感觉不到而已。因此可以这样理解,在 Linux 平台上,Java NIO 和 Java NIO.2 底层都是通过 epoll 来实现的,但是 Java NIO 更加简单高效。

Springboot中,可通过如下来配置其他protocol

image.png

经测试,在设定的几种测试场景中NIO,NIO2对性能影响不大。所以本文使用nio为io模型进行测试;

确定了tomcat调整的方向,我们即可制定几组测试数据来进行压测,观察配置项对各指标的影响,

测试类代码如下:

image.png

即sleep 1000ms,然后使用jdbctemplate进行一次数据库查询;

首先我们观察max-thread对并发的影响;

这里配置max-thread = 50;max-thread=200两组数据,进行梯度压测

max-thread = 50

响应时间:

image.png

线程数:

image.png

TPS:

image.png

请求响应时间:

image.png

线程数和响应时间:

image.png
image.png

通过响应时间和线程数图可以看到,线程达到50左右后,响应时间上升的斜度开始升高,说明到达瓶颈,从tps图中可以看到,程序的并发峰值达到50tps左右,在50线程左右达到最高,而后趋于稳定;通过请求与响应时间图可以看到,当每秒请求(rps)达到35-40左右时, 开始出现响应时间波动;通过线程数与响应时间可以看到,当活动线程数达到50左右,响应时间开始出现升高;

max-thread = 200

响应时间:

image.png

线程数:

image.png

TPS:

image.png

请求响应时间:

image.png

线程数和响应时间:

image.png
image.png

通过响应时间和线程数图可以看到,线程达到200左右后,响应时间开始升高,说明性能存在瓶颈,从tps图中可以看到,程序的并发峰值达到200tps左右,在200线程左右达到最高,而后趋于稳定;通过请求与响应时间图可以看到,当每秒请求(rps)达到190左右时, 开始出现响应时间波动;通过线程数与响应时间可以看到,当活动线程数达到200左右,响应时间开始出现升高;

因此可以得到结论,当系统达到瓶颈时,通过提高max-thread可提升系统的吞吐量,TPS=( max-thread/平均响应时间) ,比如接口响应时间平均为20ms,则50的最大thread可达到2500左右的tps,每个线程每秒钟可处理50个请求;但如果盲目调大最大线程数,会造成大量的线程切换,导致吞吐量无法达到预期的值(如下图所示,设置最大线程数为2000,并用2000的虚拟用户进行压测,系统吞吐量在1700左右:由于线程数为2000,但由于大量线程之间切换,平均响应时间却超过了1s,所以导致每秒事务处理量无法到达预期


image.png
image.png

带宽对性能的影响:

假设服务器带宽为10Mbps,则每秒1.25MB的下载速度。

当对服务器进行压力测试时,如果服务器各项指标利用率还比较低,而tps已经达到瓶颈,则可以先考虑带宽的因素;

tomcat最大并发,是不是就是maxThread配置的数值?

不是。假设接口响应时间在50ms,则每个线程1秒钟可以处理20个请求,则tps为20*maxthreads

你可能感兴趣的:(Tomcat中Max-thread配置项对TPS的影响)