经验7:如何找到你应用中的性能瓶颈?
TIP:关于性能调优,SSW的黄金规则是永远不要在未经评估的请下进行任何调整,请参考:
http://rules.ssw.com.au/Management/RulesToSuccessfulProjects/Pages/NoPerformanceWithoutMetrics.aspx
你可能注意到了,目前为止我们还没有对应用本身进行任何的修改,无论是TFS本身的Web服务或者是定制的代码,都没有进行过任何修改。
当客户提出性能问题的时候,一般开发人员的反应是:难道我的代码有问题,然后马上根据自己臆想出来的最佳方式修改代码,这是绝对错误的。在这种情况下,我们首先要考虑的是那些调整是事半功倍的,以上的调整,无论是服务器基础架构,SQL Server还是IIS;我们的原则都是自下而上,尽量不对代码进行修改,因为这样我们才能最大化我们的调优结果,而且避免由于代码修改而造成的额外测试以及可能衍生的bug。
这就是我们所说的ROI原则,对于我们的项目而言,添加索引可能改进10x的性能,但是你很难搞到10x于现在的硬件,所以SQL 数据库调优是一定的首选。
不幸的是,在尝试了以上所有的可能性后,我们仍然无法达到指标;是时候对代码动手术了。我们使用了Visual Studio 中内置的Performance Wizard来进行性能评估,如下图:
图:VS 2010和VS 2012中的Performance Wizard
图:VS 2013中这个功能叫做 Performance and Diagnostics
以下是我们获取的第一份评估报告
图:你可以很容易的分辨出我们的瓶颈在于NewWorkItem()这个API操作
对NewWorkItem()这个API我们进行了进一步分析,发现其中最耗时的操作其实是承载对象的实例化操作。这时问题来了,对这个操作我们无能为力,因为我们必须要这个承载对象才能执行需要的操作。经过了一些调研后,我们决定使用“对象池”的方式来尽量多的缓存一些预先实例化好的对象,需要的时候直接取出使用,完成后再放回去。最终这个对象池为又将性能提升了22%左右。
关于对象池技术,请参考:http://msdn.microsoft.com/en-us/library/ms751482.aspx
经验8:如何发现那些最耗时的Web Service操作?
既然TFS是基于Web Service的,那么发现最耗时的Web Service调用也是进行调优的评估内容之一,这里我们激活了TFS的客户端Web Service跟踪,获得了以下报告:
上图中我们发现最耗时的操作是GetMetadataEx2[WorkItemTracking]操作,这其实就是NewWorkItem()中实例化对象的一个主要操作;这一分析再一次证实对象池的方向是正确的。对于这个GetMetadataEx操作,大家可能并不了解,其实这与TFS的操作机制有关:TFS的对象模型会在本地保存一个缓存,其中包括了工作项定制内容的定义(XML格式),这些数据其实非常庞大,因此造成了实例化操作的缓慢。
以下为激活跟踪的配置:
关于客户端跟踪配置请参考:
http://blogs.msdn.com/b/buckh/archive/2010/04/23/how-to-see-the-tfs-server-calls-made-by-the-client.aspx
关于服务器端跟踪配置请参考:
http://blogs.msdn.com/b/edhintz/archive/2007/03/30/tfs-client-tracing.aspx
经过了这一系列的评估后,我们尝试了2种代码调优方案:
1. 使用对象池技术
2. 直接调用Web Service (这样也可以避免metadata的缓存操作)
对2种方案测试后我们发现结果很接近,经过一些讨论后,我们决定使用方案1,因为方案2中我们必须使用未经微软公开的API,这样长远来看存在维护风险。
故事到这里也就结束了,我们的客户对结果很满意,我的团队也学到了很多。希望这些分享也能对你有帮助。
原文转自:http://www.almnetworks.net/wp/2013/07/21/tfs-is-huge-in-china-part2/