服务器挂起的原因以及需要如何应对?
文章目录
线程 dump 分析是找出服务器响应缓慢、服务器挂起、粘滞线程导致服务器崩溃等问题原因的最重要的一个手段。本文我们将了解到 Weblogic 线程模型以及这些线程所执行的功能和任务的一些非常基本但却很重要特性。本文将对我们在分析线程 dump 或者服务器挂起等场景所使用的一些通用术语进行讨论。
服务器挂起是什么情况,它有哪有症状?
- 如果一台服务器的响应速度跟预估的响应时间相比非常慢的话,那么它可能处于整个服务器挂起的情况了。
- 如果一台服务器甚至对客户端的请求都没有响应,那么这就是一个服务器完全挂起的场景了。有时服务器的完全阻塞也会引起服务器崩溃。
Weblogic 线程的角色和职责?
Weblogic 线程大致可以分为两大类。
- Weblogic Execute 线程:这种线程负责处理客户/用户请求。它决定了一台服务器可以并行执行多少个任务。在开发模式下 WLS 服务器会默认持有 15 个 Execute 线程而如果是生产模式 WLS 服务器将会默认持有 25 个线程。但只是提高 Execute 线程的数量并不意味着性能的提升…相反在某些情况下这反而会降低性能。
- Weblogic Socket Reader 线程:这类线程对进入的客户端请求进行监听。这也就意味着这些线程基本上负责的是处理网络流量部分的工作。它们属于 Execute 线程的一部分,默认情况下会占用 33% 的 Execute 线程。也就是说在默认情况下会有 33% 的 Execute 线程是为 Socket Reader 线程,可以根据实际需求对其进行调整。
举例说明:如果开发模式下的 WLS 服务器拥有 15 个 Execute 线程,那么会有 5 个线程是 Socket Reader 线程而其他 10 个线程负责实际客户请求的处理。
什么是 Execute 队列?
Execute 队列是一组负责指定的 Servlet / RMI 对象 / EJB / JSP 请求的 Execute 线程。在 WLS8.1 之前我们可以看到这些 Execute 队列信息是属于 “config.xml” 的一部分。但从 WLS9.x 开始,随着 Weblogic 线程模型由于引入了 WorkManager 的改变,我们在 WLS9.x 及以后版本的 WLS 中默认就看不到 Execute 队列的细节了。但是如果我们想在 WLS9.x 或更高版本的 Weblogic 中使用 WLS8.1 样式的线程模型的话我们可以使用这一 JAVA_OPTION:-Dweblogic.Use81StyleExecuteQueues=true
服务器挂起可能会有哪些原因?
服务器响应缓慢或者挂起背后可能会有很多原因…
原因一。如果可用的堆内存很小的话线程将无法在 Java 堆内存中创建所需的对象。
原因二。线程数量不足。通常发生在服务器负载 (用户请求数量) 突然增加而 MaxThreadCount 没有设置为一个合理的值的情况下,这种时候服务器将无法处理这些请求。
原因三。如果垃圾收集工作在占用很多时间,这种情况下垃圾数据的清理过程将会 (比正常情况下) 花费更长时间以至于所有线程被用于进行垃圾收集的工作而不是处理客户端请求。或者就是线程们在等待垃圾收集清理出来新的空间以创建新的对象。
原因四。有时候 Java (编译器) 的代码优化也会引起一个临时的挂起,这是因为代码优化是一个有点重的过程但却有助于获得更好的性能。
原因五。一些远程 JDBC 查找有时也会引起服务器挂起。
原因六。不恰当的 JSP 编译设置。(建议在将 JSP 部署到生产环境之前对其进行预编译并且正确设置 PageCheckSeconds 以便 JSP 编译不会频繁发生)
原因七。应用代码死锁或 JDBC 驱动死锁或第三方 API Bug:当线程在无限循环中等待获得对对象的锁定时…比如以下场景。
- 线程 Thread_A 拿到了对象 Obj_A 的锁。
- 线程 Thread_B 拿到了对象 Obj_B 的锁。
- 现在线程 Thread_A 在处理完针对 Obj_A 的一些逻辑之后开始请求对象 Obj_B 的锁 (对象 Obj_B 还在被线程 Thread_B 锁定中)。
- 与此类似,线程 Thread_B 在处理完针对 Obj_B 的一些逻辑之后开始请求对象 Obj_A 的锁 (对象 Obj_A 还在被线程 Thread_A 锁定中)。
在这种情况下,两个线程都在等待对方释放所锁定的对象…但实际情况下它们谁也无法释放自己已经锁定的那个对象。
原因八。分配给进程的系统文件描述符的数量非常小 (资源不足),在这种情况下我们也可能会面临服务器响应慢或者挂起的情形。
如果出现服务器挂起或响应缓慢的情形,服务端的日志是什么样子的?
Weblogic 将一个线程标记为 STUCK 线程的默认时间间隔是 600 秒 (也就是 10 分钟)。当出现 STUCK 线程时服务端日志会对此进行详细记录,所以你可以在服务端日志中找到如下日志:
<Warning> <WebLogicServer> <BEA-000337> <ExecuteThread: '7' for queue: 'weblogic.kernel.Default' has been busy for "630" seconds working on the request "aaa@qq.com", which is more than the configured time (StuckThreadMaxTime) of "600" seconds.>
服务器端出现上述这种日志是不是就意味着 Weblogic 已经挂起?
上述日志信息只是指示出有些线程在处理一些请求时占用了过多的时间,这当然会导致 Weblogic 服务器响应缓慢,同时这有可能会导致服务器挂起。但这并不 100% 意味着 Weblogic 无法从这些线程中恢复正常。
Weblogic 有能力将一个 STUCK 线程标记为 UNSTUCK。Weblogic 会根据 “Stuck Thread Max Time” 和 “Stuck Thread Timer Interval” 的设置对 STUCK 线程进行定期检查,请参考官方文档 http://e-docs.bea.com/wls/docs103/ConsoleHelp/taskhelp/tuning/TuningExecuteThreads.html。
Weblogic 只是对线程标记为 STUCK 进行报告,随着线程的处理结束 (可能看起来是卡住了,实际上是在运行一个很长的事务),Weblogic 还会将其标记为 UNSTUCK。很多时候应用需求确实需要线程花费很多时间来处理客户端请求 (多余 600 秒),在这种情况下屋面可以改变 “StuckThreadMaxTime” 的时间间隔。比方说我们的应用有一些需要长时间运行的 JDBC 查询可能会占用 900 多秒,这时候我们就可以增大 StuckThreadMaxTime 了。
收集调试数据需要哪些应急步骤?
调试一。使用 “weblogic.Admin PING” 工具 ping Weblogic 服务器五到六次来看看我们需要多久才能得到响应返回?
java weblogic.Admin -url t3://StuckThreadHostName:9001 -username weblogic -password weblogic PING
调试二。立刻检查详细的 GC 日志 (前提是你已经通过以下 JAVA_OPTIONS 启用了 GC 日志)。
set JAVA_OPTIONS=%JAVA_OPTIONS% -Xloggc:/opt/logs/gc.log -XX:+PrintGCDetails -Xmx1024m -Xms1024m
调试三。在九到十秒之间收集至少四到五次线程 DUMP 来查看线程的活跃度。遵循各种线程 DUMP 的收集方法:http://middlewaremagic.com/weblogic/?p=823。
调试四。检查服务器负载 (客户端请求数) 是不是异常高?
调试五。检查 JMS 子系统连接或数据库连接是否在某个地方丢失了…你可能会在服务器日志中发现一些奇怪的条目,比如说 DataSource is Disables/ Network Adapter could not Establish Connection to the Database/ JMS Messaging System “PeerGoneException”…Tuxedo/Jolt Connectivity Errors…等等。
作者简介
Jay SenSharma
Apache Ambari Committer、Staff Software Engineer
原文链接:What Is Server Hang And What Need To Be Done ?
推荐阅读