WebSphere Application Server 中 Web 服务器插件工作原理及故障诊断

时间:2024-03-26 21:53:48

http://www.ibm.com/developerworks/cn/websphere/library/techarticles/1109_zhangt_plugin/1109_zhangt_plugin.html

 

 

引言

Web 服务器与 WebSphere Application Server ( 简称为 WAS) 配合进行请求分发是一种很常见的拓扑结构。而 IBM WebSphere Application Server 的 Web 服务器插件实际上就是 Web 服务器和 WAS 之间的连接器。它主要的职责就是将从 Web 服务器接收的请求转送给 WAS。了解 Web 服务器插件的工作原理不但可以帮助我们更快地检测跟插件相关的问题,还能帮助我们构建更加完善的应用架构。

 

Web 服务器插件的工作原理

跟 WAS 不同,Web 服务器插件是使用 C 语言开发的,所以它会稍微依赖于插件所在的操作系统及使用的 Web 服务器。但这个依赖关系非常小,因为 Web 服务器插件在不同操作系统和 Web 服务器上的操作都差不多。下面我们就一步步介绍 Web 服务器插件的工作原理。

Web 服务器插件基础

WAS 前端支持很多不同厂商的 Web 服务器,常见的 Web 服务器包括 IBM HTTP Server、Apache HTTP Server 和微软的 IIS 等。我们这里主要以 IBM HTTP Server ( 简称 IHS) 为例。如下图所示,一个从浏览器发送的 HTTP 请求经过 Web 服务器之后会被重新定向给应用服务器 ( 这里指的应用服务器都是 WAS)。这个重定向的操作就是由 Web 服务器插件来完成的,我们可以把它想成是一个 Web 服务器和应用服务器之间的“代理”。

图 1. Web 服务器插件

WebSphere Application Server 中 Web 服务器插件工作原理及故障诊断

这个重定向是基于一系列插件配置的规则,Web 服务器会优先让插件去处理每一个请求,只有当插件没有配置相关的 URL 才会让 Web 服务器去处理。我们可以这样去理解,如果 Web 服务器插件把 HTTP 请求发送给 WAS,那么插件就可以看成是一个 HTTP 客户端,WAS 接收这些请求,那 WAS 就可以看成是一个 HTTP 服务器。HttpTransport 组件就是在 WAS 内部充当 HTTP 服务器来接收 HTTP 请求的,我们可以设置多个 HttpTransport 组件配合多个端口使用。

那么肯定有人要问为什么要使用 Web 服务器插件而不直接将 HTTP 请求从 Web 服务器转给 HttpTransport 组件呢?使用插件来完成这个工作有很多优点:

  • 插件可以提供负载管理和故障转移的能力帮助我们将请求分发给多个 WAS 或者将请求转发给合适的 WAS。
  • 静态页面由 Web 服务器处理就够了,不需要转给 WAS 从而提高处理性能。
  • 插件相当于在客户端和 WAS 之间多加了一层结构,从而也提高了 WAS 的安全性。

Web 服务器插件架构

接下来就让我们看看插件工作的细节,帮助我们更好地理解插件的原理:

图 2. Web 服务器插件请求转发流程

WebSphere Application Server 中 Web 服务器插件工作原理及故障诊断

  1. Web Server Process – native code:从浏览器过来的请求第一步会经过默认的 80 端口进入 Web 服务器。
  2. httpd.conf:之后 IHS 会通过默认的 httpd.conf 找到插件的配置文件 plugin-cfg.xml 从而将 HTTP 请求转给插件。
  3. 插件会在 Web 服务器启动时加载 plugin-cfg.xml 配置文件。我们需要把插件同 IHS 安装在同一台机器上。
  4. plugin-cfg.xml:这是插件的核心配置文件。它包含了哪些 URL 将转发给 WAS。我们可以通过 WAS 的管理控制台修改和生成这个配置文件。但修改和生成配置文件后我们还需要同 Web 服务器同步配置信息。
  5. HttpTransport:这个组件实际上可以理解为一个 WAS 内部的基于 Java 的 HTTP 服务器。它主要的职责就是接收从插件转过来的请求并将请求再转给 WAS 的 Web 容器处理。
  6. Web Container:Web 容器最后就是利用 Java EE 的 servlet 规范解析并处理请求,再将处理的结果返回给 Web 服务器插件。

Web 服务器插件工作流程

下面我们将详细向大家介绍 Web 服务器插件的工作流程,流程主要包括四个步骤:

  • 初始化
  • URL 匹配和 WAS 服务器选择
  • 将请求发送给指定 WAS
  • 接收从 WAS 返回的结果
  1. 初始化

    当 IHS 启动后,IHS 会先读取 <HIS_HOME>\conf\httpd.conf 文件进行初始化。Web 服务器启动成功后会继续读取插件的配置文件 plugin-cfg.xml,并将配置文件中的配置解析出来。一旦 Web 服务器启动、读取并加载配置成功之后,插件就可以准备接收 HTTP 请求了。

    如果在 WAS 控制台中配置了 Web 服务器,当有新的应用安装到 WAS 上时,我们需要更新插件的 plugin-cfg.xml 配置文件。更新方法有两种:

    • 利用 WAS 管理控制台生成并传播新的配置文件
    图 3. WAS 控制台 Web 服务器管理界面
    WebSphere Application Server 中 Web 服务器插件工作原理及故障诊断
    • 手工拷贝到插件的配置目录中或者直接修改配置文件

    更新 plugin-cfg.xml 配置文件后,Web 服务器是不需要重启的。默认情况下,插件会每隔 60 秒自动重新加载配置文件。如果您想更改这个数值,可以修改 plugin-cfg.xml 的配置文件。下面我们把重新加载的时间间隔改为 5 分钟 (300 秒 ):

    清单 1. 代码最大长度示例
     <Config RefreshInterval=”300”> 
     <Log LogLevel="Warn" Name= 
    "D:\WebSphere\AppServer/logs/http_plugin.log"/> 
     <Property Name="ESIEnable" Value="false"/> 
     <Property Name="ESIMaxCacheSize" Value="1024"/>

    在测试或开发环境中可以使用较短的 RefreshInterval 时间,因为应用或环境需要经常修改。对于比较稳定的生产环境,我们建议 RefreshInterval 值可以设置的稍微长一些,这样可以提高整个系统的性能。

  2. URL 匹配和 WAS 服务器选择

    Web 服务器接受到新的 HTTP 请求会首先将这个请求传给插件。如果插件配置了相应的 URI,插件会匹配 URI 将请求传给 WAS 处理,如果没有配置相应的 URI,那只能由 Web 服务器来处理了。首先我们先介绍一下插件配置中的相关属性:

    清单 2. 插件配置的相关属性
     <Config> 
     <Log LogLevel="Error" Name="<WAS_HOME>\logs\http_plugin.log"/> 
     <VirtualHostGroup Name="default_host"> 
     <VirtualHost Name="*:80"/> 
     </VirtualHostGroup> 
     <ServerCluster Name="MyCluster"> 
     <Server Name="CL1"> 
     <Transport Hostname="SHARAD" Port="9080" Protocol="http"/> 
     </Server> 
     </ServerCluster> 
     <UriGroup Name="MyURIs"> 
     <Uri Name="/MyPath/*"/> 
     </UriGroup> 
     <Route ServerCluster="MyCluster"
     UriGroup="MyURIs" VirtualHostGroup="default_host"/> 
     </Config>

    这些配置的主要作用是就是将一个请求与 ServerCluster 中的一台服务器关联起来:

    • 插件首先先将请求同每一个 Route 对比一下。一个 Route 包括 ServerCluster、UriGroup 和 VirtualHostGroup 的信息。
    • 根据 HTTP 请求的信息,如果 Route 中有匹配的 UriGroup 和 VirtualHostGroup,那么插件就会将此请求发给相对应的 ServerCluster。
    • 如果 ServerCluster 中有多个服务器,那么插件会根据一定的策略或 Session 等信息将请求发送给合适的服务器。

    接下来,我们就看看整个插件 URL 匹配和选择服务器的过程:

    图 4. 插件 URL 匹配和选择服务器的过程
    WebSphere Application Server 中 Web 服务器插件工作原理及故障诊断
    • Step 1:当 Web 服务器接收到一个请求后,它会立即将这个请求转给插件。
    • Step 2:插件接收到这个请求后会把它分成两个部分:主机名和 URI 地址。
    • Steps 3, 4, 5, 6:插件会自底至上查找配置文件中定义的 Route,匹配 Route 中的 VirtualHostGroup。如果有多个 Route 都匹配,那么会选择最底下匹配的 Route,如果没有匹配的 Route,那么插件会把请求返回给 Web 服务器。
    • Steps 7, 8a, 9:接下来插件会依次匹配 UriGroup 中的 URI 地址。当主机名和 URI 地址都匹配了,插件就可以将这个请求转给合适的 WAS 了。
    • Steps 10a, 10b:如果 VirtualHostGroup 和 URI 匹配失败,插件会把请求发回给 Web 服务器,如果匹配成功,将从 ServerCluster 选择合适的服务器接收请求。
    • Steps 11, 12, 13:之后插件会检查请求的 Cookie 或 URL 中的 jsessionid 参数。从 jsessionid 中找到相应的 CloneID,如果此 CloneID 与某一台 WAS 的 CloneID 匹配,那么插件就会将请求转给这台 WAS,如果没有 jsessionid 或者没有 CloneID 匹配,那么继续执行 Step 14。
    • Step 14:如果没有 jsessionid,插件会根据 ServerCluster 中每台 WAS 的 LoadBalanceWeight 权重、ClusterAddress 地址和 Random/RoundRobin 随机 / 轮询 ( 依次分发 ) 规则寻找合适的 WAS,用户都可以自行修改这些配置。
    • Step 15:HTTP 请求会被送给目标 WAS,如果 WAS 没响应或者当机了,那么插件会通过选择策略重新选择合适的 WAS 发送。
  3. 将请求发送给指定 WAS

    相对于 WAS 来说,插件就是一个 HTTP 客户端。所以插件的发送过程就是通过 TCP/IP 协议将浏览器请求转发给 WAS。

    如果请求成功地转发给了 WAS,插件会从 WAS 端收到一个成功的 TCP/IP ACK 回复。如果在超时之前仍没有收到回复,插件会返回给 Web 服务器一个 500 错误。我们可以通过操作系统层面设置 TCP/IP 的超时时间,也可以在插件的 plugin-cfg.xml 配置文件中设置。

  4. 接收从 WAS 返回的结果

    将请求发送给 WAS 后插件会进入等待状态。当 WAS 返回给插件对应的结果后,插件结束其等待状态。但当请求处理失败后,插件会把 WAS 标为不可用的状态,如果此 WAS 长期处于不可用状态,插件会将请求转给 ServerCluster 中的另一台 WAS。如果所有的 WAS 都不可用或网络超时,插件会返回给 Web 服务器一个 500 的错误。

对于 WAS 端的 HttpTransport 模块来说可以理解成一个基于 Java 内嵌的 HTTP 服务器或者内部的 IHS。它会同 WAS 中的 Web Container 通信发送请求并接收处理后的结果。

 

Web 服务器插件的问题诊断

有时候检测一个 WAS 组件的问题很困难,而且检查到最后可能是和 Web 服务器插件相关的问题。接下来我们就会介绍一些工具和技术来帮助大家追踪和检测问题。

Web 服务器端的日志和 Trace

  1. 插件的日志文件:http_plugin.log

    当出现插件初始化失败了、HTTP 报 500 或 404 等错误、WAS 访问不了了或者网络错误等问题时可以检查这个日志文件。它位于插件目录的 logs/<web server>/ 里。

    插件的日志级别可以设为三种级别:Error、Warn 或 Trace。Error 级别是默认级别,只打印少量的信息,其次是 Warn 级别,Trace 级别会给出最详尽的信息。我们可以在 plugin-cfg.xml 配置中修改日志的级别:

    清单 3. 插件日志的级别
     <?xml version="1.0" encoding="ISO-8859-1"?> 
     <Config> 
     <Log LogLevel=”Error" Name="E:\Temp\HTTPServer\Plugins\logs\webserver1 
     http_plugin.log"/>

    具体的日志格式如下:

    [ddd mm dd hh:mm:ss yyyy] PID TID - MsgType: Component: Task: Message

    PID 代表了 Web 服务器的进程 ID,TID 是 PID 中目标请求的线程 ID,这两个 ID 都是以十六进制格式显示的。而 MsgType 主要显示的是三种日志级别。

    下面的列表显示的是插件接收到 HttpTransport 的信息 (Trace 级别 ):

    清单 4. Trace 级别的日志信息
     ============================================================================ 
     [Thu May 01 12:39:05 2003] 000006d0 00000750 - TRACE: ws_common: 
     websphereExecute: Wrote the request; reading the response 
     [Thu May 01 12:39:05 2003] 000006d0 00000750 - TRACE: lib_htresponse: 
     htresponseRead: Reading the response: 
     [Thu May 01 12:39:05 2003] 000006d0 00000750 - TRACE: HTTP/1.1 200 OK 
     [Thu May 01 12:39:05 2003] 000006d0 00000750 - TRACE: Server: WebSphere 
     Application Server/5.0 
     [Thu May 01 12:39:05 2003] 000006d0 00000750 - TRACE: Set-Cookie: 
     JSESSIONID=0000NIK0UC2LBSJ00VVNHITUAEQ:uji3uq4g;Path=/ 
     [Thu May 01 12:39:05 2003] 000006d0 00000750 - TRACE: Cache-Control: no- 
     cache="set-cookie,set-cookie2"
     [Thu May 01 12:39:05 2003] 000006d0 00000750 - TRACE: Expires: Thu, 01 Dec 1994 
     16:00:00 GMT 
     [Thu May 01 12:39:05 2003] 000006d0 00000750 - TRACE: Content-Type: text/html 
     [Thu May 01 12:39:05 2003] 000006d0 00000750 - TRACE: Content-Language: en-US 
     [Thu May 01 12:39:05 2003] 000006d0 00000750 - TRACE: Transfer-Encoding: 
     chunked 
     [Thu May 01 12:39:05 2003] 000006d0 00000750 - TRACE: ws_common: 
     websphereExecute: Read the response; breaking out of loop 
     ============================================================================
  2. Web 服务器日志:access.log 和 error.log

    当遇到 HTTP 500 或 404 等错误、Web 服务器初始化错误或或网络等问题时可以检查这两个日志文件。

    • access.log:这个文件主要记录返回给 Web 服务器的每一个回应,如果 Web 服务器发送一个请求但没有从 WAS 收到任何回应的话,我们将无法在这个日志文件中找到相应的回应。所以我们可以通过这个日志文件检查请求是否得到了正确的响应。他的格式如下:

      127.0.0.1 - - [01/May/2003:15:48:00 -0500] "GET /AnyPath/MyServlet HTTP/1.0" 200 9736

    • Error.log:这个文件主要记录 IHS 做遇到的任何错误。我们也可以通过 Web 服务器的配置文件 httpd.conf 修改日志的级别。

WAS 的日志和 Trace

  1. HttpTransport 的 Trace

    如果我们不能从 Web 服务器和插件的日志文件中找到有用的信息,那我们就可以在 WAS 中打开 HttpTransport 模块的 Trace 信息查找相关的信息。如图:

    图 5. 开启 Trace
    WebSphere Application Server 中 Web 服务器插件工作原理及故障诊断

    HtppTransport 的 Trace 信息如下:

    com.ibm.ws.http.*

    com.ibm.ws.webcontainer.*

  2. WAS 的 SystemOut.log 和 SystemErr.log

    当然,我们也可以通过 WAS 的两个日志文件,查看是否有和插件相关的 WAS 问题或 HTTP 错误等。

检测工具

我们还可以通过操作系统和 WAS 提供的工具帮助我们检测插件的问题。比如我们可以通过操作系统的 netstat 和 telnet 命令检测服务器是否可用、网络是否有问题。也可以通过 WAS 自带的 TPV (Tivoli Performance Viewer) 或者 ITCAM (IBM Tivoli Composite Application Manager) 辅助我们监测和检查问题。

 

结束语

通过了解 Web 服务器插件的工作原理及工作流程,我们可以更好地分析问题和完善应用架构。再加上多种日志信息和其他工具的辅助,我们可以很方便地定位和解决 Web 服务器插件相关的问题。

--------------------------------------------------------------------------------------------------------------------------

 

plugin-cfg.xml

●ConnectTimeout

插件文件plugin-cfg.xml中Server元素的属性ConnectTimeout可以使HTTP插件与后端服务器建立非阻塞(non-blocking)连接。非阻塞连接在HTTP插件无法连接到目的地址,无法确定群集成员的传输端口是否可用的情况下,可以缩短等待时间。例如:

<Server CloneID="10k66djk2" ConnectTimeout="10" ExtendedHandshake="false" LoadBalanceWeight="1000" MaxConnections="0" Name="Server1_WebSphere_Appserver" WaitForContinue="false">

<Transport Hostname="server1.domain.com" Port="9091" Protocol="http"/>

</Server>

如果ConnectTimeout的值没有设定,那么HTTP插件会尝试建立阻塞(blocking)连接。在阻塞连接状态下,当插件无法连接到目的地址的时候,插件会一直等到操作系统的TCP超时发生(不同的操作系统设置不同,一般是在90-120秒)后才会将群集成员标记为宕机。如果ConnectTimeout的值设定为0,那么HTTP插件依旧会建立阻塞(blocking)连接。如果ConnectTimeout的值设定为大于0,那么ConnectTimeout的值代表HTTP插件在成功建立连接前可以等候的秒数。如果过了这一时间间隔后连接没有被建立,那么HTTP插件会将群集成员标记为不可用,并且将请求转发给群集中其他可用的成员。

注意:在某些压力非常大或者网络非常慢的环境中,如果设置ConnectTimeout值过低可能会造成HTTP插件错误地将某个群集成员标记为不可用。

 

●ServerIOTimeout(Solaris平台无效)

HTTP插件文件plugin-cfg.xml中Server元素的属性ServerIOTimeout使HTTP插件对于从发出请求到接到群集成员响应设置了一个超时值,单位为秒。如果没有为属性ServerIOTimeout设定值,那么HTTP插件默认会使用阻塞(blocked)I/O向群集成员写请求和从群集成员读取响应,直到TCP连接超时。例如:

<Server CloneID="10k66djk2" ServerIOTimeout="120" ConnectTimeout="10" ExtendedHandshake="false" LoadBalanceWeight="1000" MaxConnections="0" Name="Server1_WebSphere_Appserver" WaitForContinue="false">

<Transport Hostname="server1.domain.com" Port="9091" Protocol="http"/>

</Server>

在这种情况下,如果群集成员停止响应请求,HTTP插件在结束TCP连接前将等待120秒。设置属性ServerIOTimeout为一个合理的值,能够在群集成员不响应请求的时候使HTTP插件更快地结束连接并将请求转发给其他可用的群集成员。

        在给属性ServerIOTimeout设置值的时候,需要注意有的时候群集成员确实需要1到2分钟的时间处理一个复杂的请求。在这种情况下将属性ServerIOTimeout设置地过低会造成HTTP插件向客户端传送一个服务器不可用的错误信息。

        如果在WAS和HTTP插件之间存在保持活动(keepalive)的连接,当WAS的服务器突然从网络上断开时,属性ServerIOTimeout能够很理想地解决这种情况下的失效接管。例如:当WAS某个群集成员所在的物理机器突然关机,在WAS和HTTP插件之间保持活动(keepalive)的连接可能没有全部关闭。这样,当HTTP插件需要将一个请求路由到关闭的主机,如果连接池内还存在保持活动(keepalive)的连接,HTTP插件将会使用这种连接。当插件将请求通过这种连接发送出去,由于机器已经宕机,HTTP插件不会接收到任何TCP包。HTTP插件发送的请求不会得到任何错误直到TCP级别的超时发生。接着,HTTP插件将尝试和同一个应用服务器建立新的连接。Connect()方法会在TCP超时后返回错误。这样,在HTTP插件启用失效接管前,花了大量的时间(时间长短依赖于操作系统的TCP超时设定)。如果在此期间有很多请求发送给服务器,那么每一个请求都会发生这种情况。

注意:为了避免这种情况,属性ServerIOTimeout在补丁PQ96015中被引入,这一补丁被包含在5.0.2.10和5.1.1.4以及以后的版本中。