在二年前开始使用 LoadRunner 工具,那时还是 8.0 版 Mercury 的产品,一年前开始使用 HP 的 LoadRunner 9.0,很好很实用的工具。用了这么长时间也没写过与它有关的东西,主要是觉得真是没什么可写的,仅仅是一个负载生成工具,为了在性能测试中生成需要的压力而已,能够很灵活的开发基于 C 或其它语言(如 C#)程序脚本,当然了为了使用它的一些自动指标采集等功能,需要基于它的框架/结构和函数集来开发,基本程序脚本可以通过“录制”来自动生成大半,更多时候运气好的话基本直接可以做参数化了,这个过程不会太困难。
这里想说的是使用 LoadRunner 工具来对应用系统的接口部分进行 Profiling。实际上个人觉得 LoadRunner“录制”功能本身就是个 Profiling 的过程,它记录了客户端(Bowser/Fat client app)与服务器端应用的通信过程.如在典型的B/S Web 应用结构中,它会记录如表单提交、JavaScript 异步请求等操作。根据协议的不同,Profiling 关注的方面/层面也会不一样。当然,Profiling 的角度问题平时我们不太会关注,因为使用该工具基本是为了完成模拟生成负载来做性能相关的测试,完成程序脚本的目的也在于执行测试本身。
我这里有这样一个需求。有一个基于 Microsoft .NET Remoting 框架的分布式应用,前端表现层有 Smart Client 和 ASP.NET 二套应用;业务应用层为 Remoting 服务,它包括了好多 Well-known 远程对象,用以实现业务用例;后端使用 Microsoft SQL Server 数据库做持久化。没错,很标准的企业应用(还是MIS系统,呵呵)。需求在于该业务用例出现较重负载下出现功能性问题,丢失少量事务。要想解决这样一个问题,首先就需要快速取得 Remoting 中一个特定业务用例所使用的接口(Well-known 远程对象及使用的方法集),因为对该问题的描述是从用户使用角度出发的,这就需要逐步细化的分析过程,从接口开始并最终找到用例实现中的问题本质原因。我想对于一般开发人员来说,头脑中闪现的是先找设计文档再看代码,这其中还可以参考 web.config 或 app.config 中的 Remoting 服务配置来辅助分析、判断。这个方法很对,也很有条例,也符合过程、方法,但关键问题是它不够迅速,其次会依赖其它相关设计、开发等人员。如果你负责做过应用系统(尤其是上线的生产系统)的 Troubleshooting 或 tuning 工作,你大概会理解我的意思。
说了这么多赶紧进入正题。聪明的读者肯定已经反应过来,只要用 LoadRunner“录制”一下应用中我们关注的业务用例,就可以把想要的 Remoting 接口得到了。说得很对不过真实过程还需要一些技巧。下面记录下我完成上面需求的做法。
首先使用 LoadRunner 9.0 提供的 Microsoft .NET 协议,配置“录制”的过滤器(Filters),这里可以说是你所关注的 Profiling 的层面,LoadRunner 9.0 支持 4 种过程器,这里我只关注 Remoting 层面的通信/调用,其它几项根据你的需要来配置:
通过上面配置的过程器完成“录制”后,就可以 Profiling 得到如下 Remoting 接口调用程序脚本,LoadRunner 实际是创建了一个标准的 C# 项目(csproj 8.0.50727)并生成了其中的业务用例接口的客户端调用代码,这个程序脚本也是通过 msbuild 工具编译的。下面列出简短片段:
namespace Script { using LoadRunner; using Mercury.LoadRunner.DotNetProtocol.Replay; using System; using System.Collections.Generic; using System.Data; using BusinessFacadeInterface; using Entity; public partial class VuserClass { public virtual int Action() { ... ... String url_17; url_17 = "Tcp://192.168.0.1:9090/Query.rem"; IBusinessFacadeQuery_3 = ((IBusinessFacadeQuery)(Activator.GetObject(typeof(BusinessFacadeInterface.IBusinessFacadeQuery), url_17))); otherChangeDec_2 = ((ChargeDescription)(LrReplayUtils.GetSerializedObject("Serialization_3016.bin"))); DataTable_27 = IBusinessFacadeQuery_3.QueryByChangeDec(otherChangeDec_2); String url_18; url_18 = "Tcp://192.168.0.1:9090/Query.rem"; IBusinessFacadeQuery_3 = ((IBusinessFacadeQuery)(Activator.GetObject(typeof(BusinessFacadeInterface.IBusinessFacadeQuery), url_18))); Result_1 = IBusinessFacadeQuery_3.QueryByNO("010"); String url_19; url_19 = "Tcp://192.168.0.1:9090/ResQuery.rem"; IBusinessFacadeResQuery_1 = ((IBusinessFacadeResQuery)(Activator.GetObject(typeof(BusinessFacadeInterface.IBusinessFacadeResQuery), url_19))); condition_1 = ((ResEntity)(LrReplayUtils.GetSerializedObject("Serialization_3017.bin"))); user_1 = ((SystemUserEntity)(LrReplayUtils.GetSerializedObject("Serialization_3018.bin"))); List_2 = IBusinessFacadeResQuery_1.GetResEntity(condition_1, user_1); ... ... return 0; } } }
namespace Script { using LoadRunner; using Mercury.LoadRunner.DotNetProtocol.Replay; using System; using System.Collections.Generic; using System.Data; using BusinessFacadeInterface; using Entity; public partial class VuserClass { ... ... private IBusinessFacadeQuery IBusinessFacadeQuery_3; private OtherChargeDescription otherChangeDec_2; private IBusinessFacadeResQuery IBusinessFacadeResQuery_1; private ResCondition condition_1; private User user_1; private ListList_2; ... ... } }
相信写过 Remoting 客户端的都已经看得很明白了,上面代码片段包括了激活服务器端 well-known Remoting 远程对象,通过反序列化准备参数对象,调用远程对象的接口方法并取得结果。通过这个简单的 profiling 过程我们可以很清晰的了解整个关注业务用例的接口调用、执行序列细节。说老实话,就接口 profiling 这一块来说,上面这个结果可比 Red Gate ANTS Performance Profiler 这类 profiling 工具快捷方便很多,而且结果相当清晰。
接下来,为了明确关注业务用例的接口执行/调用过程和状态迁移,则可以通过分析上面生成的 profiling 代码形成一份 UML序列图就会比较清晰了。当然这要看你需要解决问题的复杂度,如果简单看看就已经很清晰了,生成序列图就显然没有必要。
另外,可以供参考的重要资源是 Remoting 配置文件,web.config 或 app.config(进程 config)文件。因为上面 LoadRunner profiling 的代码中激活返回结果都是接口(C# interface),如其中第 4 行代码所示:
Activator.GetObject(typeof(BusinessFacadeInterface.IBusinessFacadeQuery), "Tcp://192.168.0.1:9090/Query.rem");
这可以通过和 Remoting 服务端配置中对应的服务rem地址,来确定接口的具体实现类是什么,这很容易找到。最后把我这里最后分析得到的流程图贴上来,由于涉及项目内容所以处理成了小图,看个意思吧。
有了上面些分析结果,已经可以明确问题可以存在的位置或范围,为下阶段的细化分析提供一个正确的方向和基础,通过逐步细化的分析过程,从接口开始并最终找到用例实现中的问题本质原因。
作者:lzy.je
出处:http://lzy.iteye.com
本文版权归作者所有,只允许以摘要和完整全文两种形式转载,不允许对文字进行裁剪。未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。