转自:http://jjw.iteye.com/blog/703864
最佳线程数 :
性能压测的情况下,起初随着用户数的增加, QPS 会上升,当到了一定的阀值之后,用户数量增加 QPS 并不会增加,或者增加不明显,同时请求的响应时间却大幅增加。这个阀值我们认为是最佳线程数。
为什么要找最佳线程数
1. 过多的线程只会造成,更多的内存开销,更多的 CPU 开销,但是对提升 QPS 确毫无帮助
2. 找到最佳线程数后通过简单的设置,可以让 web 系统更加稳定,得到最高,最稳定的 QPS 输出
最佳线程数的获取:
1 、通过用户慢慢递增来进行性能压测,观察 QPS ,响应时间
2 、根据公式计算 : 服务器端最佳线程数量 =(( 线程等待时间 + 线程 cpu 时间 )/ 线程 cpu 时间 ) * cpu 数量
3 、单用户压测,查看CPU 的消耗,然后直接乘以百分比,再进行压测,一般这个值的附近应该就是最佳线程数量。
影响最佳线程数的主要因素:
1 、 IO
2 、 CPU
根据公式:服务器端最佳线程数量 =(( 线程等待时间 + 线程 cpu 时间 )/ 线程 cpu 时间 ) * cpu 数量
一般来说是 IO 和 CPU 。 IO 开销较多的应用其 CPU 线程等待时间会比较长,所以线程数量可以开的多一些,相反则线程数量要少一些,其实有两种极端,纯 IO 的应用,比如 proxy ,则线程数量可以开到非常大(实在太大了则需要考虑线程切换的开销),这种应用基本上后端(比如这个 proxy 是代理搜索的)的 QPS 能有多少, proxy 就有多少。
另一种是耗 CPU 的计算,这种情况一般来讲只能开到 CPU 个数的线程数量。但是并不是说这种应用的 QPS 就不高,往往这种应用的 QPS 可以很高。
QPS 和线程数的关系
1 、在最佳线程数量之前, QPS 和线程是互相递增的关系,线程数量到了最佳线程之后, QPS 持平,不在上升,甚至略有下降,同时相应时间持续上升。
2 、同一个系统而言,支持的线程数越多(最佳线程数越多而不是配置的线程数越多), QPS 越高
QPS 和响应时间的关系
1 、对于一般的 web 系统,响应时间一般有 CPU 执行时间 +IO 等待时间组成
2 、 CPU 的执行时间减少,对 QPS 有实质的提升, IO 时间的减少,对 QPS 提升不明显。 如果要想明显提升 QPS ,优化系统的时候要着重优化 CPU 消耗大户。
最佳线程数和 jvm 堆内存得关系:
以上都是依据性能瓶颈在 CPU 的情况,对于 java 应用还有一个因素是 FULL GC ,我们要保证在最佳线程数量下,不会发生频繁 FULL GC
根据公式:: ( 小 GC 时间间隔 /rt)*( 并发线程数量 * thm) <=young 计算得到的并发线程数量如果< 最佳线程数量 则可能导致FULL GC 较频繁,实际情况看来这种情况在web 系统上非常少。不过可以模拟出来。
所以我们在设置jboss 线程的时候,可以利用内存公式计算出来的线程数量来设置,通过压测和计算得到最佳线程数,然后设置线程数。
设置线程数量:
压测最佳线程数 < 真实设置的线程数量 < 内存极限线程数
比如,通过压测得到某系统的最佳线程数量是 10 ,然后通过内存计算的线程数量是 20 ,则,设置 jboss 的线程数量为 15 是可行的,如果直接设置了 10 ,由于系统本身会受到一些依赖系统的变化而产生一些变化,比如系统依赖一些 IO 的响应时间会突然延长,由于线程数量还是 10 ,其实这个时候最佳线程数量已经变成了 13 了,由于我们设置死了 10 ,其结果就是导致 qps 下降,但是如果超过 20 ,则又会引起 FULL gc 非常频繁,反过来影响 QPS 的下降。
jboss 的线程数设置:
对于 jboss 而言,设置线程数量要看使用了那种线程连接,如 http 、 ajp 等
http 和 ajp 的设置是完全一样的,非常简单:
以 ajp 为例,找到 server.xml 或者 tomcat-server.xml:
默认线程数量是 200 个
<Connector port="8009" address="${jboss.bind.address}" connectionTimeout="15000" protocol="AJP/1.3" maxThreads="200" minSpareThreads="40" maxSpareThreads="75" maxPostSize="512000" acceptCount="300" bufferSize="16384" emptySessionPath="false" enableLookups="false" redirectPort="8443" useBodyEncodingForURI="true"/>
这里将默认的线程数量改成了 20 ,当然相应的其他最小空闲线程数和最大空闲线程数也做一下调整:
<Connector port="8009" address="${jboss.bind.address}" connectionTimeout="15000" protocol="AJP/1.3" maxThreads="20" minSpareThreads="20" maxSpareThreads="20" maxPostSize="512000" acceptCount="300" bufferSize="16384" emptySessionPath="false" enableLookups="false" redirectPort="8443" useBodyEncodingForURI="true"/>