凡事了解一些性能测试的工程师,都知道要做好性能测试除了要会使用性能测试工具编写性能测试脚本外,更重要的两项工作是性能测试执行后,到底是否存在性能故障?以及存在性能故障的原因存在于何处?是网络原因、数据库原因、算法原因、硬件设备原因亦或是架构设计等等其他原因造成的呢?即使定位了性能故障,接下来如何对系统性能进行调优,使其满足用户的需求,这又是一大难点工作......
而今天想和大家交流的是性能测试中最最有价值又最最容易被忽略的事情—性能需求及风险分析!
我们先看一张图,下图是软件缺陷的修复费用示意图,大家一定都不陌生。从这张图中我们可以清楚的看出在后期bug修复的成本可能比需求阶段高出1000倍。
那我们再思考一下,性能测试执行的工作一般都是在功能测试基本完成,软件可正常使用的情况下才开展的一项工作,那就意味着我们定位性能bug以及优化性能bug基本上都在系统测试阶段后才开始。也就是说即使我们的性能测试技术很牛,能够进行性能测试的故障定位和调优,那么修复的成本和风险也是非常高的。从公司整体运营角度来看,这样“牛”的性能测试工程师,给企业带来的价值本身不一定是最大的。
图一
我自己就曾经在这方面有过深刻的教训体验。那是一次大型ERP系统的测试,其中“财务子系统”由我带团队负责测试。“工资计算”模块是其中最为复杂的一个部分,不光工资项目很多,而且每个员工的工资项目也不完全相同,计算公式各种各样,千差万别。因为涉及到财务制度以及工资不能有丝毫的偏差,我们花费了一个多月的时间,构造了上千条用例,甚至结合代码的单元测试的方法来达到更完美的覆盖,可以说是使用了所有可以使用的手段来进行全面的测试。最终在大家的通力合作下,这个模块终于测试通过了!
就在大家准备举杯庆祝的时候,我想看看我们的丰硕成果,就构造了1000条测试数据,一起来进行发工资的演示。以往我们的测试重点是检查每一笔数据计算的准确率,所以一个测试工程师就分配构造10组数据重点逐一检查,并没有经过更多数据的成批测试。因为当时觉得批量测试还不到时候,先保证单笔少量数据计算是正确之后再进行批量测试。这也是业内常用的测试工作思路,并无什么不妥。
但是当我们使用1000条测试数据同时进行工资计算时,发现测试服务机没有响应,只有这个沙漏图在不断的转动。
打开服务器的资源一看,吓一跳,CPU100%,内存也基本上接近100%。打开运行进程列表查看,除了被测的ERP系统和系统必备启动进程外,并没有其他应用在运行。
看到这个数据,我们并没有意识到有什么严重的,因为我们使用的是测试环境,服务器配置也一般,更何况我们使用了1000条数据进行同时发放,真实情况也许不需要这么多的数据量(真实情况是多少用户量,作为测试开发当时都没有人关注)。不过这个情况我们还是第一时间反馈给了项目负责人和产品经理,这下可炸锅了,尤其是产品经理一听,我们发1000个用户的工资服务器就没有响应了,完全崩溃掉了。
“什么?1000条记录都没有响应了,整个系统每次至少要完成6000人以上的工资发放啊!”“啊,啊......”所有在场的人都被吓到了,直到这一刻,我还抱着最后一点希望说:“我们是在测试服务器上测的,就是一台配置稍微高一些的PC机,是不是用户那边的配置好一些呢?”,项目经理压低声音,闷头说了一句:“客户的配置比我们测试机器还差......”。大家的表情终于统一如下:
顾不上那么多谁的责任不责任的了,赶紧定位问题。最后才发现是数据库设计导致的。本来正常的工资表的设计非常简单,就类似于下表:
但当时因为该企业客户每个岗位甚至每个员工的工资单都不统一,比如张三的工资单有20项内容,李四的工资单只有5项内容,而且内容还都不一样,如果按照这样的格式设计,就变成以下的表单:
不仅会有大量的空字段,而且这个表是动态增长的,只要有一个员工使用的工资项在当前工资表中不存在,就需要动态的增加一列。所以当时在设计这张表时考虑到以上两个方面的问题就把工资表的设计改为以下两个关联表单:
这样设计的优势就是表结构不需要动态变化,也不存在冗余字段,符合数据库范式的定义。所以从技术易实现和减少冗余字段的角度采取了这种工资表的设计。
无论是架构设计还是开发、测试,没有任何人会想到这样的表结构设计会直接导致性能出现严重问题。之所以会出现严重的性能问题,我们可以通过一组数据对比看出问题所在。
而且像这样每个月以10万级倍数递增,还不到一年这个工资表就会超过百万级数据量,随着历史数据的增多,整个遍历速度还会继续变慢。如果要显示员工姓名,还需要再关联员工基本信息表,这样所需要花费的时间就更久了。
性能故障的原因很快就被确认了,属于数据库表结构设计问题。要修改也很简单,那就以空间换时间,不用考虑范式规则,直接就采用传统工资表格的方式,一个员工一条工资记录,表结构动态生成就行。因为通过实际的更进一步的调研,大致统计后发现所有员工可能的工资项目全部加起来不重复的也不会超过1000个,也就意味着这个动态表的增长也是有限的不是无限的,到某种程度后,也会变成一个相对固定的表结构。只是在数据的存储方面有一些冗余(即有些字段对应的值是空值),但比起节约的时间而言,这一点点存储空间的浪费是非常值得的。
到此大家是不是认为此次性能测试已经顺利完成了,找到了故障点,也给出了优化解决方案,也进行了试验测定,这就算大功告成了呢?
告诉大家,根本不是这样的。虽然问题已经定位,优化方案已经给出,数据库表结构也非常好改,都是分分钟的事情,但凡事有一点编码经验的人都知道,数据库表结构相当于一个建筑的框架结构,如果这个建筑的框架结构变了,意味着所有的代码,调试,测试等工作都得推倒重来。这也就意味着这个模块所有的开发、测试工作全部都需要返工。大致写了一个工作量的统计如下:
如果按照新的数据库表结构编写代码进行测试,除了测试用例设计不需要返工,其他工作都需要重来一遍,就算工作量不增加,这一次返工造成的成本也超过7万了,而且这只是单纯一些人力最低成本的粗略计算,算上工期延迟,还有公司其他固定成本的分摊,对其他子系统开发工作的影响等等,也就意味着修复这一个性能bug需要投入的返工成本超过了十万!这对任何企业和项目而言无疑是一个巨大的浪费和风险!
通过以上这个工作案例,大家可以看到,在性能测试整个工作阶段,只是完成测试执行,故障定位和调优方案的确认,从整个公司层面而言是远远不够的。而大部分的性能测试工作都存在以上类似的这些风险,基本上都是在后期才开展性能测试,进行定位和调优的。
如果我们能在前期充分评估需求以及架构、数据库设计是否可能存在性能风险,提升在前期的性能测试分析和风险评估能力,那无论是从成本、收益还是风险方面都会带来本质的提升和改变。
要具备前期的性能测试评审和风险分析能力可以从以下几个方面来提升和改进:
1、加强前期性能测试需求分析及评审能力,尽早准确明确性能测试的具体范围和相应指标;
2、在进行架构设计和数据库设计评审时,要充分考虑是否存在性能的风险,并进行相关的技术试验;
3、在代码编写阶段,针对有重大性能风险的代码,只要基本能运行,就要提早进行代码级单元性能测试试验,尽早确认算法是否存在性能风险;
4、对于需要进行性能测试的功能,不要等到功能全面测试,修复回归等工作都结束后再进行性能压测,只要基本能使用,尽早进行性能测试
通过以上这些手段和方法,相信大家在性能测试技术能力提高的同时,也能为企业和项目最大程度上减少降低性能风险和修复成本,如果能减少一个价值10万的bug,我们的月薪拿到30K以上是有充分理由的,这才是真正全面的性能测试“高人”!
版权声明:本文出自51Testing会员投稿,51Testing软件测试网及相关内容提供者拥有内容的全部版权,未经明确的书面许可,任何人或单位不得对本网站内容复制、转载或进行镜像,否则将追究法律责任。