跳转到内容

WebObjects/Web 应用程序/部署/调试冻结的已部署实例

来自维基教科书,开放的书籍,开放的世界

本文由 Andrew Lindesay (http://www.lindesay.co.nz) 撰写于 2005 年 2 月左右。它最初以 LaTeX PDF 格式出现,并已转录到此维基。您自行承担使用本文档中包含的信息的风险。如果您认为维基标记转换过程中可能存在错误,请联系作者。

适用性

[编辑 | 编辑源代码]

此处讨论的材料已在 MacOS-X Server 上的 WebObjects 5 和 Java 1.4 中使用。它可能适用于或不适用于旧版或新版 WebObjects 或 Java。强烈建议您首先在非生产服务器上对其进行测试。请注意,如果您的系统在互联网上公开,此技术可能存在安全问题。

Java 提供了 WebObjects 5 应用程序运行的基础。Java 有其优缺点。一个优点是轻松实现软件系统的多线程操作。这通常可以用来充分利用您的硬件资产,但也意味着您需要确保对事物进行锁定,以防止两个线程同时访问同一事物。锁定失败会导致数据损坏,或者当一个线程由于某种原因无法释放锁定时,其他线程可能会无限期地等待。

当多线程系统中“出现问题”时,获得可靠的诊断可能很困难。问题通常很难重现,可能非常零星,并且通常很少见。可能需要一系列非常具体的事件,并且需要非常精确的时间才能重现问题,并且这些问题通常难以在“实验室”中重现。在生产环境中,此类错误可能会导致应用程序实例“冻结”,并最终使实时系统无响应。

无限循环等更常见的错误也可能潜入生产系统,并导致实例无响应。

本文重点介绍了一种技术,该技术可用于确定生产环境中冻结实例内部发生了什么。特别是,此技术将为您获取实例线程的堆栈跟踪。有了这些信息,您将更有可能诊断问题并快速解决问题。

开始之前

[编辑 | 编辑源代码]

以传统方式部署的 WebObjects 系统包含程序的多个副本,它们分别运行,每个副本都承载来自用户的某些入站负载。每个“副本”都被称为一个实例。该SiteConfig.xml文件定义了实例。此配置文件位于您的 MacOS-X Server 文件系统的以下位置。

/Library/WebObjects/Configuration/SiteConfig.xml

在修改它之前,请备份SiteConfig.xml文件以防出现任何问题。

实例被修改,以便可以使用jdb调试工具远程连接到它们。需要将一些“附加参数”插入到配置中的SiteConfig.xml文件中的每个实例,以便实现这一点。这些附加参数将如文本所示插入到元素additionalArgs中。您需要为每个实例选择不同的地址 - 从 8000 到 8999 之间选择地址。这是一个 TCP/IP 端口。请注意,所有附加参数都应显示在一条连续的行上。作者在此处将其拆分以提高可读性。

...
<instanceArray type="NSArray">
  <element type="NSDictionary">
    <id type="NSNumber">1</id>
    <port type="NSNumber">2001</port>
    <cachingEnabled type="NSString">YES</cachingEnabled>
    <additionalArgs type="NSString">
      -Xdebug
      -Xrunjdwp:transport=dt_socket,address=8121,server=y,suspend=n
    </additionalArgs>
...
  </element>

元素标签将在此处重复,以包含在instanceArray标签中的所有实例。

id标签给出实例编号,您需要记住从实例编号到地址的映射,这些映射在附加参数中。将这些信息记在一张纸上。例如,在上面,可以看出实例 1 映射到地址 8121。

现在重新启动您的实例。

出现问题时...

[编辑 | 编辑源代码]

实例列在 JavaMonitor 中。下面显示了一个屏幕截图,实例编号用红色圆圈标记。您首先需要确定哪个实例已冻结。

获得实例编号后,使用您的实例到地址映射(来自设置),识别您要连接到的地址。

使用jdbjava 环境附带的命令行工具连接到实例并调试它。为此,请在应用程序服务器上输入以下形式的命令。

fooserver$ jdb -attach 8121

如果您要调试远程机器,可以使用以下命令。

foodev$ jdb -attach woserverhost:8121

这可能在您的 WebObjects 应用程序服务器上没有安装jdb工具的情况下很有用,因此您需要从安装了jdb工具的主机运行 jdb 工具。

您现在将使用 java 调试器。有大量命令可以帮助您使用调试的 java 系统,但本文只关注获取线程堆栈跟踪。发出命令suspend以冻结所有线程,以便可以将其转储,然后发出命令where all以获取所有线程的堆栈跟踪。最后,当您希望再次恢复线程时,请发出命令resume。建议您在获得所需信息后立即退出jdb环境。

查找内容

[编辑 | 编辑源代码]

下面显示了堆栈跟踪的示例。您会注意到 java 类名和源代码行号位于堆栈中特定条目末尾。在这里,我们可以看到名为“WorkerThread103”的线程卡住了,试图从会话存储中获取会话。在这种情况下,另一个线程很可能拥有会话存储的锁定,并且没有释放该锁定。

WorkerThread103:
  [1] java.lang.Object.wait (native method)
  [2] java.lang.Object.wait (Object.java:429)
  [3] com.webobjects.appserver.WOSessionStore.checkOutSessionWithID (WOSessionStore.java:207)
  [4] com.webobjects.appserver.WOApplication.restoreSessionWithID (WOApplication.java:1,546)
  [5] com.webobjects.appserver._private.WOComponentRequestHandler._dispatchWithPreparedApplication (WOComponentRequestHandler.java:314)
  [6] com.webobjects.appserver._private.WOComponentRequestHandler._handleRequest (WOComponentRequestHandler.java:358)
  [7] com.webobjects.appserver._private.WOComponentRequestHandler.handleRequest (WOComponentRequestHandler.java:432)
  [8] com.webobjects.appserver.WOApplication.dispatchRequest (WOApplication.java:1,306)
  [9] nz.co.orcon.osm.webobjects.Application.dispatchRequest (Application.java:428)
  [10] com.webobjects.appserver._private.WOWorkerThread.runOnce (WOWorkerThread.java:173)
  [11] com.webobjects.appserver._private.WOWorkerThread.run (WOWorkerThread.java:254)
  [12] java.lang.Thread.run (Thread.java:552)
WorkerThread101:
  [1] java.net.PlainSocketImpl.accept (PlainSocketImpl.java:351)
  [2] java.net.ServerSocket.implAccept (ServerSocket.java:448)
  [3] java.net.ServerSocket.accept (ServerSocket.java:419)
  [4] com.webobjects.appserver._private.WOWorkerThread.run (WOWorkerThread.java:238)
  [5] java.lang.Thread.run (Thread.java:552)
...

如果您查看其他线程同时在做什么,您很有可能确定哪个区域可能存在错误。至少,您可以弄清楚应用程序的哪个部分存在错误。

尽管这种方法很简单,但它提供了一种方法,可以使您了解冻结实例内部发生了什么,而不是进行繁琐的猜测游戏。

华夏公益教科书