“工欲善其事必先利其器”。无论是哪个行业,这都是一句至理名言,软件测试当然也不例外。这也正是分布式测试框架(下文简称DST)设计的初衷。
DST是海量数据项目背景下,为了解决测试集管理、运行、查询和测试执行、控制以及监控、日志数据的收集整理的一个通用型测试与分析平台。这个平台既包含了传统测试框架的特点也包含了自身的开创性思想。作为DST从前端界面到后端服务的亲身经历和开发者,下面我将从技术选型、架构设计、功能点分析、使用场景以及周边支持工具这几个角度来对DST测试平台做一个总结,进一步思考和回顾,以便发现不足和需要改进之处。
第一篇 奠基
对于一个好的软件来说,技术选型无疑是最重要的一步,这将决定软件是否有良好的扩展性、健壮性、可靠性以及可维护性。对于DST来说,传统的B/S是一个显而易见的架构性选择,那么从前端到后端都需要有良好的Framework以及清晰的技术轨道与之配合。
好的技术选型可以大大缩短开发周期,并提高代码的质量,减少bug产出率,优良的技术往往是具有清晰的结构化框架的,便于追踪问题,以及向其他开发者分享代码。
技术选型贯穿了整个DST的设计与开发始终,并经历了多次回滚调整,最终采用现在的技术轨道并非是一件一帆风顺的事情。下表列举的是DST使用到的相关技术:
名称 | 描述 |
Webx | 基于经典MVC设计模式的WEB框架,构建前端UI的主要骨骼脉络,具有清晰地层次化构造,良好的扩展机制。 |
Velocity | 基于java的模板引擎,允许仅仅简单的使用模板语言(template language)来引用由java代码定义的页面对象。 |
ibatis | 持久层框架包括SQL Maps和Data Access Objects(DAO),是一种“半自动化”的ORM(Object/Relation Mapping)实现。 |
Jeasyui | jQuery Easyui,基于jQuery的前端页面和javascript设计框架,简单且易于上手,封装的AJAX简洁易用。 |
HBase | 一个分布式的、面向列的开源nosql数据库,DST利用其实现海量监控和日志数据的存取。 |
Mysql | 持久化前端以及测试数据。 |
HighCharts | 一套界面美观的纯Javascript图表库。 |
RESTful | REST (REpresentational State Transfer) 描述了一个架构样式的网络系统。 |
Ueditor | 一个百度开源的富文本编辑器。 |
AJAX | 交互式网页应用的网页开发技术。 |
SyntaxHighlighter | 高亮显示代码用的Javascript库。 |
Thrift | Facebook开发的一个软件框架,用来进行可扩展且跨语言的服务的开发。 |
Jetty | 开源的servlet容器。 |
其他还有一些例如SimpleTip(浮动标签)、MapReduce(用来做nosql数据的定期备份)等技术,由于涉及不多,不再列举。
在整个DST的开发周期中,围绕技术选型以及开发模式,曾经发生过几次重要的争论,列举如下:
1. 框架之争
DST之前有Kelude测试平台可以借鉴,Kelude采用Ruby语言的Rails框架,其特点是轻巧灵活,代码极少重复,开发效率极高。然而考虑到精通Ruby语言的程序员不多,后端服务的技术人员大多精通Java而非Ruby,且海量数据平台的大部分产品都是Java开发(如Hadoop),将来在DST与测试场景接合的时候,相同的语言可以省却很多麻烦。最终定选的Webx作为一个成熟的MVC设计模式,在淘宝的使用很广泛,有大量资料实例可以参考。
持久层采用Hibernate还是ibatis,这要归功于我们团队的leader叶渡的技术选型,在后来的开发过程中,不谈外部的一般说法,我的感觉是ibatis结构非常清晰,sql语句完全被抽象到了sqlmap文件中,适合DBA以及其他开发人员对sql语句的审核。从DAO接口到之上的事务层,都可以通过ibatis很好的管理起来。但是ibatis从生成到增删改非常繁琐,增加一条sql语句,一般情况下至少要修改6、7个文件,这个过程很容易出错。
2. UI设计之争
作为后端测试工程师,因为我在DST立项开始的时候并没有太多的前端开发经验,因此在UI设计上,曾经发生过是否要专业UED参与的争论。这个争论虽然之后随着DST的开发渐渐消失,但此时提及,是为了记录我在设计过程中的一些思考。
我觉得DST如果有专业的UED协助进行用户体验的设计那是最好不过的事情,但是对于此类项目的开发早期,很多功能点不是很清晰的情况下,由开发人员掌握住整个流程还是相当有必要的。开发者的亲身参与会省去许多探雷的过程,且测试人员自己才最清楚需要一个什么样的系统,UED的参与更多从普通用户角度思考,而测试框架作为一款特殊的软件产品,更需要从开发者角度去思考他们的操作习惯。
3. 海量数据持久化之争
身处海量数据开发项目,自然少不了和动辄上千个节点的集群打交道,从这些集群收集到的监控数据和日志数据的量也可以用浩如烟海来形容。按常规经验,一个百台规模的集群,收集到的监控数据一年约有8TB,传统关系型数据库撑住这样的数据量还要保持高效的并发读写效率,往往需要一个很有经验的团队来支撑,分表操作会成为一个常态。而我们所需的查询动作往往又非常简单,基本上都是扫描一段时间内的数据。这恰好是nosql型数据库最擅长的领域。
但是在这部分设计之初,我们发生了关于持久化是通过直接存取二进制文件方式,还是存取HBase方式之争。
直接存取二进制文件方式的理由是,可以直接从RRD(Round Robin Database)数据库文件中读取所需的监控数据,对查询请求可以通过固定算法计算出数据所在位置后,用seek函数直接跳转过去进行连续读取,好处是速度快,硬件资源需求少。但这样的方式带来的问题,一是查询依赖于编程,不利于查询方式的扩展和数据挖掘;二是没有足够可靠的数据冗余备份方案,一旦机器损坏,数据就将发生不可逆转的丢失;三是扩展性不够,能够hold住百级别节点的集群,并不意味着我们仅仅只有百台机器需要存取监控和日志数据,一旦规模扩大,这样的解决方案将面临无法动态扩容的危险。
最终我们选择了将监控和日志数据存到HBase中这个方案,上述的三个问题都不会发生。而在后来的设计中,我进一步发现与其从gmond保存的RRD数据库文件中读取监控数据,不如通过替代gmond master节点的方式来直接解析xml形式的监控数据。这样可以避免磁盘操作这个性能瓶颈,数据流完全是从内存到网络(gmond)再到内存(我们的工具)再通过网络到HBase集群的内存中。整个过程完全将没有磁盘这种慢速设备的干扰。关于这部分的详细设计思想,我将会在后文中继续描述。
4. 敏捷开发模式实施之争
采用敏捷开发模式是DST设计过程中不可忽视的一个重要技术选型。按照书本上的定义:敏捷开发强调程序员团队与业务专家之间的紧密协作、面对面的沟通(认为比书面的文档更有效)、频繁交付新的软件版本、紧凑而自我组织型的团队、能够很好地适应需求变化的代码编写和团队组织方法,也更注重做为软件开发中人的作用。
而DST在开发之初,有过一些并不是很适宜的对某些开发点的反复关注和修改,浪费了一些时间。这在随后持续进行的迭代开发周期中,还是需要警醒自身,并持续改善的。一方面避免代码浪费,另一方面还要和业务需求层面多进行沟通,以便做出的产品与实际需求之间偏差较小。
综上所述,技术选型的过程并非是一帆风顺的,其过程尤其是人与人之间交互中,需要各方不断的争执和妥协。有些选型也并非一成不变,在发现问题之后,及时的回滚就可以了,最重要的是不可一条错路走到黑。而我们平时更愿意只选择自己最熟的路走,这对于开发产品来说并不是一件好事。
我认为一个比较好的习惯是,无论遇到什么问题,哪怕是自己已有成熟想法的,都应该首先去搜索一下业界同类问题的解决办法,能够走大部分人共同走过的路,才是最安全可靠的。我们设计一个优秀的软件,做一个零散部件的组装者要比做一个从矿工开始的开发者需要付出的更少,且有更多的机会获得成功。技术选型正是一个选择零件的过程,这比架构的角色更为重要,无论拥有多么优秀的架构,一个足够分量的错误的零件都有可能会毁掉你设计的整座大厦。