“没有最优,只有平衡”。因此在配置与调优之前,我总喜欢先介绍理论基础。
Apusic AS V5.1的线程池只是个池服务,池中没有具体的线程,池中管理的线程是与业务相关的服务启动后并加入的。线程池只负责管理池中线程的数量和生命周期,从而简化了Apusic应用服务器的池管理框架。验证线程池的方法有以下几种:
1. 在Windows下启动Apusic V5.1的mydomain域,里面不带任何自启动线程的应用,在命令行窗口下按Ctrl+Break结果见附一(各人机器可能有所不同),发现系统没有任何与线程池相关的线程启动。打开IE访问一个HTML页面,再Ctrl+Break结果见附二,发现多了两个线程:Running HTTPHandler-1(HTTP服务线程)和Idle MuxHandler-1(多路复用服务线程),Mux空闲是因为多路复用的分配工作已经完成,而HTTP忙是因为HTTP服务刚结束,KeepAlive仍然保持着。可见线程池启动时是空的,当有服务时才生成线程加入到池中,池主要负责线程的数量和生命周期。这样的设定可以避免受到攻击时无限制地创建线程而导致系统宕机;或者合理使用机器的性能,平衡分配不同线程池中的线程数量。
2. 在apusic.conf文件中自定义一个线程池Test,然后可以在自己的代码中使用Apusic AS提供的池管理技术,当然如果没有使用这个池系统也仍然可以正常运行,因为这只是个池服务,只是没有线程加入到池中而已。
<SERVICE
CLASS="com.apusic.util.ThreadPoolService"
NAME="Apusic:service=ThreadPool,name=Test"
>
<ATTRIBUTE NAME="MaxThreads" VALUE="150"/>
<ATTRIBUTE NAME="Priority" VALUE="5"/>
<ATTRIBUTE NAME="ServicePriority" VALUE="H"/>
<ATTRIBUTE NAME="IdleTimeout" VALUE="300"/>
<ATTRIBUTE NAME="MaxSpareThreads" VALUE="30"/>
<ATTRIBUTE NAME="MinSpareThreads" VALUE="5"/>
<ATTRIBUTE NAME="MaxQueueSize" VALUE="500"/>
</SERVICE>
3. 只提供default池,其他池都注释掉,系统依然能够正常运行,也是因为池与服务之间不是紧耦合,没有的相关的池,所有的线程统一使用default池,如果有自己的池就通过自定义池处理。
注意:如果有了自定义池,池中线程数达到最大值后,系统不会使用defalut池来处理的,从而充分保证相应服务池的控制。
例如:定义了HTTPHandler池,当HTTPHandler线程达到最大值后,其他只能在Queue中排队,如果Queue也满了,则其他请求将会被拒绝。
Apusic AS自己使用了五种池:
default:Apusic AS系统默认的线程池
MuxHandler:多路复用的线程池,主要是将请求向不同的服务,如:HTTP、JMS、ORB等服务上分配
HTTPHandler:HTTP服务的线程池
JMSHandler:JMS服务的线程池
ORBHandler:ORB服务的线程池
了解了线程池的基本概念,就可以知道在线程池配置中default池最为重要,其他池可以根据需要增加或者注释,所有线程池的配置参数都是相同的,具体的配置参数解释如下:
MaxThreads:线程池中能够运行的最大线程数,也就是提供服务的线程数,-1代表无限制
MinSpareThreads,MaxSpareThreads:线程池中最小/最大空闲的线程数,当线程数符合这个区间时无论空闲多久都不会被销毁
IdelTimeout:空闲线程超时的时间,超时后会如果运行的线程总数大于MaxSpareThreads则被销毁
Priority(1~10):受Java线程优先级管理
ServicePriority:服务启动的优先级,五种(H > A > N > B > L)
MaxQueueSize:当所有线程都忙时,为无法获得线程的请求提供队列进行排队,Size代表队列长度,队列满时请求被抛弃
Apusic AS的线程池优化:
● 一般的WEB应用部署在Apusic上时,不会用到JMS和ORB服务,因此可以将这两个池注释掉,减少资源消耗。
● 如果应用现阶段使用人数不多,但是伴随着发展应用人数会不断增长,可以将MinSpareThreads调整为符合现阶段情况的值,将MaxSpareThreads调整为符合将来的值,这样系统无须再变动就可以有效支持很长一段时间;
● 如果应用一段时间内访问量变化不大,但是系统偶尔会遇到高峰访问,那么可以设置MinSpareThreads=MaxSpareThreads;
● MaxThreads的值依据CPU数量来定,参考值50×CPU核数,具体值还需要根据应用执行过程中对CPU的压力决定。
● 关于Apusic AS V5.1服务的配置,下篇文章会单独介绍。
附一、
Full thread dump Java HotSpot(TM) Client VM (1.5.0_14-b03 mixed mode, sharing):
"AutoDeployer" prio=6 tid=0x030f2970 nid=0x9e0 in Object.wait() [0x03cef000..0x03cefc6c]
at java.lang.Object.wait(Native Method)
- waiting on <0x23460458> (a com.apusic.deploy.runtime.AutoDeployer)
at com.apusic.deploy.runtime.AutoDeployer.run(Unknown Source)
- locked <0x23460458> (a com.apusic.deploy.runtime.AutoDeployer)
at java.lang.Thread.run(Thread.java:595)
"Thread-4" prio=6 tid=0x031ca7f0 nid=0x21c in Object.wait() [0x0349f000..0x0349fd6c]
at java.lang.Object.wait(Native Method)
- waiting on <0x2321c188> (a com.sun.corba.se.impl.javax.rmi.CORBA.KeepAlive)
at java.lang.Object.wait(Object.java:474)
at com.sun.corba.se.impl.javax.rmi.CORBA.KeepAlive.run(Util.java:736)
- locked <0x2321c188> (a com.sun.corba.se.impl.javax.rmi.CORBA.KeepAlive)
"HTTPSessionSwapper" prio=6 tid=0x031d8168 nid=0xb98 in Object.wait() [0x0345f000..0x0345fa6c]
at java.lang.Object.wait(Native Method)
- waiting on <0x2318ba58> (a java.lang.Object)
at com.apusic.web.session.SessionManager$HouseKeeper.run(Unknown Source)
- locked <0x2318ba58> (a java.lang.Object)
"HttpLogger" prio=2 tid=0x031be630 nid=0xfe8 in Object.wait() [0x0341f000..0x0341f9ec]
at java.lang.Object.wait(Native Method)
- waiting on <0x2317d2b8> (a com.apusic.web.http.HttpLogger)
at java.lang.Object.wait(Object.java:474)
at com.apusic.web.http.HttpLogger.getNextRecord(Unknown Source)
- locked <0x2317d2b8> (a com.apusic.web.http.HttpLogger)
at com.apusic.web.http.HttpLogger.run(Unknown Source)
"MuxListener" prio=6 tid=0x031a8be8 nid=0x7dc runnable [0x033df000..0x033dfaec]
at java.net.PlainSocketImpl.socketAccept(Native Method)
at java.net.PlainSocketImpl.accept(PlainSocketImpl.java:384)
- locked <0x23177890> (a java.net.SocksSocketImpl)
at java.net.ServerSocket.implAccept(ServerSocket.java:450)
at java.net.ServerSocket.accept(ServerSocket.java:421)
at com.apusic.net.BlockingListenerThread.run(Unknown Source)
"Timer-0" prio=6 tid=0x031c3b08 nid=0xc98 in Object.wait() [0x0339f000..0x0339fb6c]
at java.lang.Object.wait(Native Method)
- waiting on <0x23133120> (a java.util.TaskQueue)
at java.util.TimerThread.mainLoop(Timer.java:509)
- locked <0x23133120> (a java.util.TaskQueue)
at java.util.TimerThread.run(Timer.java:462)
"LogManager" prio=2 tid=0x02e2c680 nid=0xb20 waiting on condition [0x0335f000..0x0335fbec]
at sun.misc.Unsafe.park(Native Method)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:118)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:
841)
at com.apusic.util.concurrent.LinkedBlockingQueue.take(Unknown Source)
at com.apusic.logging.manager.ServerLogManager$PushThread.dequeue(Unknown Source)
at com.apusic.logging.manager.ServerLogManager$PushThread.run(Unknown Source)
"Low Memory Detector" daemon prio=6 tid=0x00a83bf0 nid=0xa6c runnable [0x00000000..0x00000000]
"CompilerThread0" daemon prio=10 tid=0x00a537b8 nid=0xdc4 waiting on condition [0x00000000..0x02c2f6cc]
"Signal Dispatcher" daemon prio=10 tid=0x00a95a58 nid=0xeb0 waiting on condition [0x00000000..0x00000000]
"Finalizer" daemon prio=8 tid=0x00a50870 nid=0xbd0 in Object.wait() [0x02baf000..0x02bafa6c]
at java.lang.Object.wait(Native Method)
- waiting on <0x230d25c8> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:120)
- locked <0x230d25c8> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:136)
at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:159)
"Reference Handler" daemon prio=10 tid=0x00a4f3e8 nid=0xf94 in Object.wait() [0x02b6f000..0x02b6faec]
at java.lang.Object.wait(Native Method)
- waiting on <0x230d2650> (a java.lang.ref.Reference$Lock)
at java.lang.Object.wait(Object.java:474)
at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:116)
- locked <0x230d2650> (a java.lang.ref.Reference$Lock)
"main" prio=6 tid=0x00038c00 nid=0x718 in Object.wait() [0x0007f000..0x0007fc3c]
at java.lang.Object.wait(Native Method)
- waiting on <0x230e0ed8> (a com.apusic.server.J2EEServer)
at java.lang.Object.wait(Object.java:474)
at com.apusic.server.J2EEServer.startup(Unknown Source)
- locked <0x230e0ed8> (a com.apusic.server.J2EEServer)
at com.apusic.server.Main.main(Unknown Source)
"VM Thread" prio=10 tid=0x00a80190 nid=0x490 runnable
"VM Periodic Task Thread" prio=10 tid=0x00a8e780 nid=0xcec waiting on condition
附二、
Full thread dump Java HotSpot(TM) Client VM (1.5.0_14-b03 mixed mode, sharing):
"Running HTTPHandler-1" prio=6 tid=0x02febe58 nid=0xbd8 runnable [0x03d6f000..0x03d6fb6c]
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.read(SocketInputStream.java:129)
at java.io.BufferedInputStream.fill(BufferedInputStream.java:218)
at java.io.BufferedInputStream.read1(BufferedInputStream.java:256)
at java.io.BufferedInputStream.read(BufferedInputStream.java:313)
- locked <0x234dd378> (a java.io.BufferedInputStream)
at com.apusic.web.http.tcp.TCP_BIOProtocol.readLine(Unknown Source)
at com.apusic.web.http.tcp.TCP_BIOProtocol.readRequestLine(Unknown Source)
at com.apusic.web.http.tcp.TCP_BIOProtocol.read(Unknown Source)
at com.apusic.web.http.tcp.TCP_BIOConnection.getNextRequest(Unknown Source)
at com.apusic.web.http.ConnectionHandler.processConnection(Unknown Source)
at com.apusic.web.http.ConnectionHandler.run(Unknown Source)
at com.apusic.util.ThreadPoolImpl$WorkerThread.run(Unknown Source)
"Idle MuxHandler-1" prio=6 tid=0x02cc0d90 nid=0x54c in Object.wait() [0x03d2f000..0x03d2fbec]
at java.lang.Object.wait(Native Method)
- waiting on <0x23147df0> (a java.lang.Object)
at com.apusic.util.ThreadPoolImpl.getWork(Unknown Source)
- locked <0x23147df0> (a java.lang.Object)
at com.apusic.util.ThreadPoolImpl$WorkerThread.run(Unknown Source)
"AutoDeployer" prio=6 tid=0x03146980 nid=0x7bc in Object.wait() [0x03cef000..0x03cefc6c]
at java.lang.Object.wait(Native Method)
- waiting on <0x2344f8c0> (a com.apusic.deploy.runtime.AutoDeployer)
at com.apusic.deploy.runtime.AutoDeployer.run(Unknown Source)
- locked <0x2344f8c0> (a com.apusic.deploy.runtime.AutoDeployer)
at java.lang.Thread.run(Thread.java:595)
"Thread-4" prio=6 tid=0x031e3868 nid=0xdc8 in Object.wait() [0x0349f000..0x0349fd6c]
at java.lang.Object.wait(Native Method)
- waiting on <0x2321c188> (a com.sun.corba.se.impl.javax.rmi.CORBA.KeepAlive)
at java.lang.Object.wait(Object.java:474)
at com.sun.corba.se.impl.javax.rmi.CORBA.KeepAlive.run(Util.java:736)
- locked <0x2321c188> (a com.sun.corba.se.impl.javax.rmi.CORBA.KeepAlive)
"HTTPSessionSwapper" prio=6 tid=0x031c1948 nid=0x9f4 in Object.wait() [0x0345f000..0x0345fa6c]
at java.lang.Object.wait(Native Method)
- waiting on <0x2318ba58> (a java.lang.Object)
at com.apusic.web.session.SessionManager$HouseKeeper.run(Unknown Source)
- locked <0x2318ba58> (a java.lang.Object)
"HttpLogger" prio=2 tid=0x031b8830 nid=0xb2c in Object.wait() [0x0341f000..0x0341f9ec]
at java.lang.Object.wait(Native Method)
- waiting on <0x2317d2b8> (a com.apusic.web.http.HttpLogger)
at java.lang.Object.wait(Object.java:474)
at com.apusic.web.http.HttpLogger.getNextRecord(Unknown Source)
- locked <0x2317d2b8> (a com.apusic.web.http.HttpLogger)
at com.apusic.web.http.HttpLogger.run(Unknown Source)
"MuxListener" prio=6 tid=0x02e654a8 nid=0xa28 runnable [0x033df000..0x033dfaec]
at java.net.PlainSocketImpl.socketAccept(Native Method)
at java.net.PlainSocketImpl.accept(PlainSocketImpl.java:384)
- locked <0x23177890> (a java.net.SocksSocketImpl)
at java.net.ServerSocket.implAccept(ServerSocket.java:450)
at java.net.ServerSocket.accept(ServerSocket.java:421)
at com.apusic.net.BlockingListenerThread.run(Unknown Source)
"Timer-0" prio=6 tid=0x02e65c08 nid=0xdf0 in Object.wait() [0x0339f000..0x0339fb6c]
at java.lang.Object.wait(Native Method)
- waiting on <0x23133120> (a java.util.TaskQueue)
at java.util.TimerThread.mainLoop(Timer.java:509)
- locked <0x23133120> (a java.util.TaskQueue)
at java.util.TimerThread.run(Timer.java:462)
"LogManager" prio=2 tid=0x02e2d488 nid=0xbfc waiting on condition [0x0335f000..0x0335fbec]
at sun.misc.Unsafe.park(Native Method)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:118)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:1
841)
at com.apusic.util.concurrent.LinkedBlockingQueue.take(Unknown Source)
at com.apusic.logging.manager.ServerLogManager$PushThread.dequeue(Unknown Source)
at com.apusic.logging.manager.ServerLogManager$PushThread.run(Unknown Source)
"Low Memory Detector" daemon prio=6 tid=0x00a83c78 nid=0xc5c runnable [0x00000000..0x00000000]
"CompilerThread0" daemon prio=10 tid=0x00a53910 nid=0x780 waiting on condition [0x00000000..0x02c2f6cc]
"Signal Dispatcher" daemon prio=10 tid=0x00a95ae8 nid=0xc8c waiting on condition [0x00000000..0x00000000]
"Finalizer" daemon prio=8 tid=0x00a50870 nid=0xd10 in Object.wait() [0x02baf000..0x02bafa6c]
at java.lang.Object.wait(Native Method)
- waiting on <0x230d25c8> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:120)
- locked <0x230d25c8> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:136)
at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:159)
"Reference Handler" daemon prio=10 tid=0x00a4f3e8 nid=0x1d0 in Object.wait() [0x02b6f000..0x02b6faec]
at java.lang.Object.wait(Native Method)
- waiting on <0x230d2650> (a java.lang.ref.Reference$Lock)
at java.lang.Object.wait(Object.java:474)
at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:116)
- locked <0x230d2650> (a java.lang.ref.Reference$Lock)
"main" prio=6 tid=0x00038c00 nid=0x7fc in Object.wait() [0x0007f000..0x0007fc3c]
at java.lang.Object.wait(Native Method)
- waiting on <0x230e0ed8> (a com.apusic.server.J2EEServer)
at java.lang.Object.wait(Object.java:474)
at com.apusic.server.J2EEServer.startup(Unknown Source)
- locked <0x230e0ed8> (a com.apusic.server.J2EEServer)
at com.apusic.server.Main.main(Unknown Source)
"VM Thread" prio=10 tid=0x00a80190 nid=0xab4 runnable
"VM Periodic Task Thread" prio=10 tid=0x00a8e808 nid=0x684 waiting on condition