内容


基于 SOAP 的应用程序性能测试

您的 Web 服务可以投放生产中了吗?

今天我们访问大量的网站,使用的服务器应用软件包已不止一个。对于那些提供个性化内容的动态网站情况更是如此。如果您在您公司的内部门户上人力资源 Web 页面中注册登记了,那么当您查看生产企业的出货报告时,同样的注册信息是否仍然有效?

在这场景的后面,工程师组成的团队在尽全力来使后端系统彼此保持协同工作。新的硬件(路由器、服务器及存储设备)及服务器软件(应用服务器、数据库及 ERP 解决方案)修订版的不断出现,频率之快令人惊动。软件工程师也在不停的编写那些昂贵且不易维护的定制软件来使系统数据的保持共享。

SOAP 框架

SOAP 至今仍是开发服务器-对-服务器通讯 lingura franca 的最大希望所在。能够编写可以与其他服务器、平台和硬件进行自由通讯的服务器应用程序的好处有很多。程序员将不再将时间花在代码维护上,而是集中精力解决更大的问题。操作管理者将有更多的平台和硬件选择。用户也因有更高级的应用程序可用而受益。

利用 SOAP 以支持软件彼此协同工作的工具不仅价格不贵、可随意获得且被广泛支持。您在工具、硬件及网络设备上的想法将极大的决定您所部署的基于 SOAP 的 Web 服务的性能和可扩展性的潜力。记住这一点,我打算讨论的是一个用于开发 Web 服务的可扩展框架,以及避免在性能上出现问题的一些策略,我还提供了开放源代码的用于测试可扩展性的一组对象,以及协助其在做性能和可扩展性测试时用到的叫作 Load 的脚本语言。

用于开发 Web 服务的框架

SOAP 是一种轻量级协议,意在适应于您现存的 Web 应用基础架构。新出现的用于开发可扩展的、基于 SOAP 的 Web 服务的框架有利于那种带有许多小服务器的 Web 体系结构,而这些小服务器通过负载均衡器才可被访问,这个框架向强大的数据库服务器提供了一个前端。

图1:用于开发 Web 服务的框架
图 1: 用于开发 Web 服务的框架
图 1: 用于开发 Web 服务的框架

用 Java 建造一个基于 SOAP 的 Web 服务框架需要这些组件(这些组件的链接,请参阅 参考资料):

  1. Apache SOAP
    主要基于 IBM 在 SOAP 上所做的研究成果,Apache SOAP 是一开放源代码项目,提供功能完全的 Java SOAP 实现。Apache SOAP 实现了大部分 SOAP v1.1 技术规范,其支持 SOAP 消息、服务器及客户机实现,并且遵照 Apache 方式的许可证下提供了完整的源代码(这意味着您可以修改这些代码甚至发布带有你的修改的有所有权的软件产品。)。
  2. JDOM
    JDOM 可能成为 Java 的组成部分,因为 Sun 接受 JDOM 作为 JSR102(请参阅 参考资料)。Apache SOAP 自带一个 Xerces XML 解析器 ― 其他任何遵循 SAX 的 XML 解析器也可代替。Java 开发者会发现 JDOM 是一个可用于处理 SOAP 的 XML 文档的更简单、更友好的 API,而且它允许您更改底层的 XML 解析器而无需重写 SOAP 应用程序。这种灵活性为您在一个特定的 XML 解析器下解决可扩展性或性能问题时提供更多的选择。JDOM 也是在 Apache 方式开放源代码许可证下发布的。
  3. SSL 支持的负载均衡器
    SOAP 1.1 协议还没有定义加密和认证的方法。在 SOAP 定义认证方法之前,该框架建议将业务逻辑写到 servlet,然后使用底层 Web 服务器的 SSL 支持来产生 Web 服务的 HTTPS 请求。负载均衡器的 SSL 支持对该请求解密,并将其作为解密的 SOAP 调用传给 Web 服务。这将使提供 Web 服务的服务器免除 SSL 的计算开销。
    图 2:几个故障点
    图 2: 几个故障点
  4. 带有基于 cookie 的会话跟踪的负载均衡器
    SOAP 1.1 还没有定义会话管理机制。在一个负载均衡环境里,一些 SOAP 请求必定载有状态信息。举个例子,与 Web 服务通信可能会需要多个请求及一连串的请求和响应(在一个会话期间负载均衡器必须可以选择将请求发往同一 Web 服务的服务器)。今天大多数的负载均衡器都是支持基于 cookie 的会话跟踪的。

这种框架有很多优点。因其在任何时候都很典型地运行较少的线程,这令 Java 工程师们调试变得简单。公司的财务经理喜欢它,因为他们可以购买许多小而廉价的服务器,而不必购买庞大的系统。网络经理则喜欢这些小服务器所提供的灵活性。

这就产生了一个问题:SOAP 可用在生产环境吗?

面向性能和可扩展性的设计

SOAP 仍是一个非常新的、未测试过的系统。SOAP 里面,有很多地方存在性能和可扩展性上的问题。决定其生产价值就需要从单元级和系统级全都进行测试。

SOAP 协议使用多步过程来完成通信事务处理。一个 SOAP 请求从应用程序的业务逻辑开始,从 Web 服务描述语言(WSDL)文档中获得调用方法和参数。

图3:面向性能和可扩展性的设计
图 3: 面向性能和可扩展性的设计
图 3: 面向性能和可扩展性的设计

举个例子, 清单 1为用于公众 Web 服务的 WSDL 的一部分,当输入一个美国邮政编码后,它会返回当前的天气信息(请参阅 参考资料里面有一个完整 WSDL 的链接)。

清单 1:返回当前天气信息的 Web 服务
<message name = "getTempRequest">
 <part name = "zipcode" type = "xsd:string"/>
</message>
<message name = "getTempResponse">
 <part name = "return" type = "xsd:float"/>
</message>

传递一个 zipcode 字符串值给天气信息服务的 getTempRequest 方法调用,最后以接收到的浮点值温度作为响应。

由于 WSDL 很少被修改,很多开发者把 WSDL 定义嵌入进他们的代码,以避免每次获得 WSDL 的开销。这确实会增进性能,但当 WSDL 日后作了修改时,这就会使维护变得令人头疼。

为避免维护上的麻烦,更好的一个办法就是把 WSDL 高速缓存在一个集中式数据库里,然后定期检查它的时间戳记/版本号,看看是否有一个更新的 WSDL 可用。

另一个提高性能的办法就是把 XML 确认关闭。这种情况下就减轻了应用程序对响应结果所做的确认工作。举个例子,在 清单 2的 WSDL 为响应定义了模式。

清单 2:减轻 XML 确认
<element name="zipcode" type="int"/>
<element name="temperature" type="float"/>
<element name="remarks" type="string"/>

对于本服务调用的结果如 清单 3所示。

清单 3:结果
<zipcode>95008</zipcode>
<temperature>65 F</temperature>
<remarks>Storm warning</remarks>

这个响应会抛出一个异常,因为温度的值不是浮点类型 ― 它实际上是一个字符串。您自己来做响应确认通常要比依赖于 DTD 或 XML 模式代码做响应确认要快的多。

在 SOAP 里面的参数类型可能呈现一个可扩展性的问题。SOAP 定义简单的数据类型:字符串、整数、浮点数以及负整数(NegativeInteger)。WSDL 中可能包含有价值的新数据类型。例如,设想一下温度 Web 服务也能对映射进行检索。其调用的模式如 清单 4

清单 4:检索映射
<message name = "getTemprequest">
 <part name = "zipcode" type = "xsd:string"/>
</message>
<message name = "getTempResponse">
 <part name = "return" type = "xsd:float"/>
 <part name = "map" type = "xsd:
http://www.pushtotest.com/wsdl/mapformat"/>
</message>

在读取响应的同时,确认 XML 解析器就会联系 pushtotest.com 主机来获得用于 mapformat 的 XML 模式定义。如果确认解析器没有对模式定义进行高速缓存,这种请求的开销会使系统失去可扩展性。

有利于性能的一个一般性的原则是保留简单 SOAP 数据类型,除非迫切需要使用其他数据类型。每一个新的数据类型导入一个序列化器,它把 XML 值转化成 Java 值然后再次转回来。这个序列化器可能会导致性能上的问题或者就是个 bug。比如 Apache 和 Microsoft 的 SOAP 实现都包含一个 BigDecimal 数据类型,可它们并不兼容。Glue 是一用来映射平台间 XML 的差别的商业产品。请参阅 参考资料那里有 Glue 及相关页面的链接。

虽然 SOAP 是被设计为与现存的 Web 应用环境一起工作,但这种协议可能会给防火墙及路由带来问题。它不像普通的 Web 服务器那样使用 HTTP,所有的 SOAP 信息都是 HTTP 表单提交的等价物。其调用移动的数据量要比一般的 HTTP GET 或 POST 调用要多,因此网络性能受到的影响必定很大。

应该对防火墙及路由设备采取专门的测试。比如,检查防火墙的安全策略,以确定它不把 SOAP 请求作为 Web 流量来监控。如果真是这样,防火墙会将这些流量当作拒绝服务攻击(DoS)流量分流掉。

早期的 Web 服务都是非常简单的 ― 发出一个 SOAP 调用就会得到一个响应。更高级的 SOAP 应用程序会发出连续的 GET 和响应调用直到一个事务处理结束。事务处理 SOAP 调用需要识别会话并将会话的状态高速缓存。这种供 SOAP 事务处理的高速缓存机制对可扩展性来说也是潜在的问题点。

现在我已经涵盖了寻找可扩展性与性能问题的着眼点,接下来可以把精力集中到实际的基于 SOAP 的 Web 服务的可扩展性和性能测试中了。

使用 Load 进行测试的策略

把基于 SOAP 的 Web 服务放进生产环境,就要确保使其具有高可用性和始终如一的良好性能。下面是一清单,Java 开发者在计划测试 Web 服务时,对此要心中有数:

  1. 有状态测试
    当您使用 SOAP 设置了一个服务器值,这台服务器稍后会正确响应吗?
  2. 权限测试
    当用户每天都试着访问仅授权给管理员的控制权时,会发生什么?
  3. 速度测试
    Web 服务是否响应的时间太长了?
  4. 边界定时(Boundary timing)测试
    当 Web 服务请求超时的时侯,或者用了非常长的时间响应会发生什么?
  5. 回归测试
    新的版本是否中断了现存的 Web 服务功能?

以上所列的测试,对于任何软件应用程序来说都是相当普通的测试。这虽是 Web 服务,测试范围可扩大为一个矩阵,如下面的 Web 服务测试组表格所描绘:

Web 服务测试组150500
有状态测试__
权限测试_
速度测试
边界定时(Boundary timing)测试
回归

即使您公司不重视测试,也没投资购买测试软件,在过去兴许您自己通过 Web 浏览器来测试 Web 应用程序。但对于基于 SOAP 的 Web 服务这是行不通的。以人工的方式阅读由 SOAP 在事务处理时产生出来的 XML 文档很快你就会发现它相当的浪费时间。所以必须开发和使用自动测试软件组。

在我的公司站点(Pushtotest)里有一个开放源代码的免费实用程序 Load,你也会在 IBM developerWorks 的开放源码专区找到(请参阅 参考资料中的链接)。Load 可用来编写用于测试基于 SOAP 的 Web 服务可扩展性和性能的自动测试软件组。它提供一个用于操作测试对象库的脚本语言,并能让您开发驱动 Web 服务的智能脚本。多个显示天气脚本的副本并行运行,使 Web 服务置于模拟的生产情况下。

我们看看如何使用 Load 来调用前面讨论的天气温度服务。 清单 5是脚本的全貌。

清单 5:使用 Load 来测试天气报告 Web 服务
<load>
<script>
<!-- Tells where to find the weather service -->
<variable name="serviceurl"
  value="http://services.xmethods.net/soap/servlet/rpcrouter"/>
<!-- Establishes a variable to hold the zip code -->
<variable name="thezip" value="95008" />
<!-- Identify the source of the delimited data -->
<soapsource name="temperature" target="urn:xmethods-Temperature"
  method="getTemp" url="$serviceurl;"/>
<soapsource name="temperature" action="addparameter"
  parameter="zipcode" value="$thezip;"/>
<soapsource name="temperature" action="call"/>
<echo message="The temperature is $soapsource[ temperature, 0];" />
<echo message="That request took $soapsource[ temperature, totaltime];
milliseconds" />
</script>
</load>

现在来看看每个单独函数是如何工作的。

<load>
<script>

这是导言,用来识别以下用 Load 程序来处理的脚本元素。

<!-- Tells where to find the weather service -->
<variable name="serviceurl"
  value="http://services.xmethods.net/soap/servlet/rpcrouter"/>
<!-- Establishes a variable to hold the zip code -->
<variable name="thezip" value="95008" />

有两个变量:第一个用来保存指向 Web 服务的 URI;第二个保存的是邮政编码的值。

<!-- Identify the source of the delimited data -->
<soapsource name="temperature" target="urn:xmethods-Temperature"
  method="getTemp" url="$serviceurl;"/>

接下来创建了一个名称为 temperature 的 soapsource 对象。这个 temperature 对象将调用 xmethods-Temperature Web 服务的 getTemp 方法,这个服务位于由 URL 定义的机器上。

<soapsource name="temperature" action="addparameter"
  parameter="zipcode" value="$thezip;"/>

这向 temperature 对象添加邮政编码参数。您可以使用 addparameter 操作来添加任意多的所需参数。Web 服务 WSDL 定义了所要求的参数。

<soapsource name="temperature" action="call"/>

调用 Web 服务启动一个到目标服务器的 http 连接, 通过请求及添加的参数来组织一个 XML 文档,然后等待响应。

<echo message="The temperature is $soapsource[ temperature, 0];" />

Load 察看响应文档并找到在 0 位置的响应域。您可以在 Load GUI 上面看到该值的显示。

<echo message="That request took $soapsource[ temperature, totaltime];
milliseconds" />

该 temperature 对象的 totaltime 方法以毫秒为单位返回发起和完成请求所需的时间。

当你满意本脚本时,Load 就可以并发运行该脚本把 Web 服务置于模拟负载的环境下进行测试。

<load>
<script sessions="25">
. . .
</script>
</load>

这就生成了 25 个脚本的副本并且并行运行。Load 同样包含循环、随机值、发送“傻瓜”文本(一种毫无意义的,反复发送的文本,其用于测试)及访问其他 20 多个测试对象的命令。

许可 Load 的条款类似于 Apache Web 服务器。您可以下载 Load 程序及其所有的源代码。您可以改写 Load 来修整 bug 或添加新的特性。该许可证甚至允许您在本代码的基础上建造商业性可用的新产品。

总结

在做完了多个并发请求强度下的质量测试后,那么程序设计并交付产品质量级的 Web 服务就会更容易更快速。当测试基于 SOAP 的 Web 服务时,开放源代码 Load 实用程序里面的脚本语言及测试对象能为您提供一个更有成效的方法。


相关主题

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=SOA and web services
ArticleID=21957
ArticleTitle=基于 SOAP 的应用程序性能测试
publish-date=09012001