Home | 简体中文 | 繁体中文 | 杂文 | 知乎专栏 | 51CTO学院 | CSDN程序员研修院 | Github | OSChina 博客 | 腾讯云社区 | 阿里云栖社区 | Facebook | Linkedin | Youtube | 打赏(Donations) | About
知乎专栏多维度架构

1.27. 多维度架构之压力测试

1.27.1. 压力测试中存在的问题

1.27.1.1. (What) 什么是压力测试

软件压力测试是一种基本的质量保证行为,它是每个重要软件测试工作的一部分。软件压力测试的基本思路很简单: 不是在常规条件下运行手动或自动测试,而是在计算机数量较少或系统资源匮乏的条件下运行测试。 通常要进行软件压力测试的资源包括内部内存、CPU 可用性、磁盘空间和网络带宽。

压力测试涵盖,性能测试,负载测试,并发测试等等,这些测试点常常交织耦合在一起。

1.27.1.1.1. 压力测试存在哪些问题

我归纳一下有几点:

  1. 操作系统默认安装,在未做任何优化的情况下实施压力测试

  2. 未考虑磁盘IO对软件的影响

  3. 未考虑网络带宽对软件的影响

  4. 网络软件测试,没有考虑到TCP特点

  5. 各种超时参数优化

  6. 测试客户端未优化

  7. 并发理解有误

  8. WEB服务器,数据库,等等服务器未优化

如果上面几项没有做优化,压力测试数据基本没有任何参考价值,任何一项没有优化,都会导致你的压力测试数据出现偏差。 下面我来逐条说明:

  1. 操作系统问题: 操作系统是大众化软件,出厂优化都是面向大众,不可能为某个领域做单独优化。所以我们第一步需要优化操作系统。 Linux 系统优化内核参数,Windows 系统优化注册表等等。

  2. 磁盘IO: 这是最容易出现瓶颈的地方,常常是CPU还没有达到极限,磁盘已经不堪重负。

  3. 网络IO: 与磁盘IO相同

  4. TCP连接: 几乎所有 B/S, C/S 软件都是采用多线程,或者多进程技术。这种技术有个特点,开发者将程序设计为线程可自动伸缩模式,开启进程后会启动少量线程,当连接不断提高后,线程数逐渐增加,随着线程运行结束后,线程逐渐减少。 这样的设计会更有效地利用硬件资源,在程序空闲时将硬件资源让给其他进程。少有软件设计为开启服务独占资源。 这样测试软件做压力测试,不能一次并发很多请求,而是要采用逐渐增加的方式,否则第一次测试会有一部分并发不能及时响应,导致测试数据偏差。另外也你可以多做几次压力请求(让多线程工作起来),从第三次开始记录测试数据,忽略前面两次的测试数据。

提示:另一个问题是TCP连接复用,这也是一个重要配置项。如果这项没有配置,我想测试出的数据也会有偏差

  1. 超时参数: 超时参数在压力测试中是非常重要的参数,例如从WEB到数据库连接超时是60秒,如果有一个SQL查询超过300秒,那么后面的请求会持续排队等待,当连接数达到数据库的最大连接时,接下来的所有请求都是失败的。 通常我们的WEB服务器超时不会超过30秒,有时我设置为10秒,一旦出现超时,宁可让该连接Timeout,不要让他影响整体服务。

  2. 客户端: 很多网络软件需要从客户端发出压力测试请求,所以客户端的优化也是必须的,否则客户端压力出不去,服务端压力进不来。

  3. 并发: 很多人认为并发,就是同一时间内的最大连接数,这是错误的。如果你写过多线程程序,就会发现多线程运行时有规律的。是顺序排队运行的,根本不是同时运行的。 所以并发是指,相对时间内能完成的连接总和,例如,每秒并发,每分钟并发等等,通常我们已秒为单位。 我们目前使用的操作系统叫分时操作系统,这种系统的特点就是可能实现多用户,多任务。操作系统将进程排队(优先级)轮询运行,只不过这个操作太快了,使你认为多个进程在同时运行。

  4. 服务器优化: 主要B/S软件压力测试,WEB,缓存,数据库等等服务器,都需要逐一优化到最佳状态

1.27.1.2. (Why) 为什么做压力测试

如果在软件设计阶段都将这些问题元素都考虑进去,同时开发阶段严格执行。那么开发出些软件几乎不用做这个劳人伤神的压力测试。

所以在软件设计阶段就要考虑,灵活性,扩展性,可靠性与性能,还要考虑高可用与负载均衡。

同时软件优化伴随开发,持续集成,持续测试,持续部署。

1.27.1.3. (Where) 在哪里做压力测试

有些软件需要封闭的环境测试,不能在共享资源的环境中做测试。所以你有必要做Vlan隔离,甚至独立的路由器与交换机在封闭网络中测试。

1.27.1.4. (When) 什么时间做压力测试

任何时间都可能做压力测试,为什么我将“时间”重点提出呢?目前受地球自转影响,经常闰秒,你不的不考虑这个问题。

1.27.1.5. (Who) 压力测试过程参与人员

  1. 运维部门

  2. 开发部门

  3. 测试部门

1.27.1.6. (How) 如何做压力测试

下面我们举一些例子,讲述压力测试方法,限于篇幅不可能面面俱到,我仅仅是给你提供思路。

测试前你需要一些监控工具,实时监控服务器的资源变化。

例如 Web 服务器压力测试,测试场景是 nginx :

    
    worker_processes  8;            处理器数
    worker_rlimit_nofile 65530;     允许最多打开文件数
    worker_connections  4096;       最大连接数数为
    keepalive_timeout  65;          开启复用连接
    gzip  on;                       压缩传输数据
    
			

怎么测试呢?你要获得最大化性能吗?还是相对性能?我们通常需要的是满足需求就好的相对性能,而不是最大化性能。为什么呢?因为要获得最大化性能是要做出很多配置牺牲的,例如关闭日志,禁止访问时间等等。

按照上面的配置你的测试用例应该是,每次并发4000 请求 8000~10000 次, 你不能并发8000 请求 4000 这样测试。很是很多人常常犯的错误,所以测试者需要连接系统的配置参数,不能盲目使用数字实验。

上面我说过线程的开启时随着请求,逐渐增加的,所以首次发起测试数据是不准确的,通过pstree命令可以看到线程数量。等第三次以后线程逐渐增加到4096个,并且之前开启的TCP可以复用,这时测试的结果比较有说服力。

延伸阅读《Netkiller Web 手札》《Netkiller Testing 手札》《Netkiller Linux 手札》

1.27.2. 协议测试

1.27.2.1. What 什么是协议测试

什么事协议? 协议是计算机进程或网络中进行数据交换而建立的规则、标准或约定的集合。

什么是协议测试? 协议测试就是软件界面与应用服务器间通信规则的测试。

需要注意一点,协议测试不是接口测试,接口测试通常是RPC调用,例如基于HTTP SOAP, XML-RPM 并不在本文的讨论范围之内,接口测试可以放在单元测试中。

1.27.2.2. Why 为什么要做协议测试

传统测试更多注重界面的测试,界面是针对用户的,也是唯一可见,也是最容易测试的。我们通过下面的金字塔说明。

	
```text

          /\
         /  \ 
        / UI \
       /``````\
      /  API   \
     /``````````\
    /   Service  \
   /..............\
```	
	
			

用户只能看到 UI ,UI测试是有局限的,只能看到冰山一角,越往下层越难发现软件的缺陷。

互联网的今天应用软件已不仅仅是三层架构,互联网特点是多语言混合开发,软件运行在异构平台上。

举例最简单的B/S结构的应用测试如下:



```text
用户 -> DNS -> CDN -> Proxy / SLB -> Web -> Application -> Cache -> Database
```

			

这已经是最简单的结构了,复杂都远不止这些。中间环节还可以加入搜罗引擎,计划任务,单点登录......

所以仅仅通过UI测试是无法满足,但我们往往看到企业中测试团队的人员比例是,UI测试人数最多,Service 人数最少,呈现出倒金字塔形状。

1.27.2.3. where 在哪儿测试

这里谈的协议,不仅限于UI到服务间的协议,还有服务于服务见的协议,进程与进程间的协议。

这些协议五花八门,有私有协议,有开放式协议,有二进制协议,有文本协议,还有中性协议二进制与文本混用。

难以归类,从不同角度可能做不同的归类。

1.27.2.4. when 什么时候测试

什么时候测试,我的建议紧随开发的进度。不要等待软件开发完时在测试,这样的好处是随时可能发现问题。

1.27.2.5. Who 谁来做,执行对象

协议测试可能是传统科班出身测试工程师的门槛,但对于全栈工程师来说相对容易。协议测试通常无法使用现有的测试软件做测试,很多情况需要我们写专用的测试软件。

编写测试软件需要掌握哪些技术呢,除了精通一门语言还要掌握下面最基本的技能?

数据处理:

  1. XML处理 DOM / XPATH
  2. 系列化与反序列化 例如 语言自身的系列化 / Json / Hession / MsgPack / Protobuf
  3. 编码与解码 URL / Base64 / Unicode / GB系列
  4. 摘要 MD5 / SHA1 / CRC32
  5. 加密解密 DES / ASE / 分对称公私钥加密
  6. pack/unpack 主要用于处理C/C++结构体重的数据库结构

通信:

  1. HTTP GET/POST/PUT/DELETE
  2. 消息队列 RabbitMQ / ActiveMQ / ZeroMQ
  3. Unix Socket / Tcp Socket / UDP Socket
  4. HTML5 / Web Socket / Ajax
  5. 管道
  6. Sniffer 软件(抓包/监控)

信号,线程,存储:

  1. 共享内存
  2. 线程锁
  3. 信号处理

1.27.2.6. How 怎样做测试

使用现有的测试软件

编写软件模拟协议发出请求然后验证反馈结果

嗅探,植入

目前自动化测试软件发展很快,可以实现很多协议测试,但仍有局限。所以仍然需要用户自己开发测试工具。

对于 HTTP GET / POST 完全可以通过现有测试软件实现我们的测试需求。

对于已知协议的测试是比较容易进行的,更多是工作是,编码/解码,协议的送出与反馈。

对于很多未知的私有协议就需要经验了,需要大量协议嗅探,总结,反复尝试。文本协议门槛比较低,对于私有的二进制协议难度相对高些。

1.27.2.7. 如何学习协议测试

学习协议测试分为几个阶段:

  1. 首先从文本协议开始学起,第一步先拿 SMTP 发送邮件 练手,了解基本协议后,就可以进行下一步学习,学习HTTP协议,处理基本的请求。

    可以尝试自己开发一个 Web 服务器,不用太复杂,实现基本的目录浏览,文件下载,GET/POST 处理。最后学习ajax, json, websocket 等等,

  2. 然后学习二进制协议。早年都欢拿 MSN / QQ 练手,实现一个QQ机器人,这里涉及到其他语言处理C/C++的结构体的问题,就是 pack/unpack 操作,这是一道门槛,阔跨过去前途光明。

    目前很多软件架构上尽量避免使用结构体,而是使用序列化例如msgpack/hession/Protobuf等等,主要是方便多语音环境的通信。

  3. 最后学习与硬件交互,可以拿GSM Modem AT 命令练手,DTMF 信令解码,AFSK数字信号处理 等等

1.27.2.8. 总结

掌握协议测试的测试工程师钱途无量,协议测试门槛也远远高于一般的测试。

对于协议测试工程师我要说的是,不要局限在协议测试工程师这个领域,格局要放大些,例如监控领域,自动化领域,游戏外挂领域等等。

1.27.3. 打破软件自动化测试的格局

1.27.3.1. 自动化测试的误区

自动化测试仅仅被认为是替代人工,所以我们看到很多企业实施自动化测试仅仅是将现有的 Test Case 转换成自动化脚本。

这样做既没有提高测试整体水平,也没有改善测试结果。结果是通过手工能测试出来的问题自动化测试可以测试出来,手工测试不出来的问题自动化测试也没有测试出来。

因为测试的观念仍停留在已有 Test Case 阶段,而 Test Case 停留在业务流程测试的阶段。

最终自动化测试仅仅是按照测试用例走一遍业务流程,完成业务流程的检验。

1.27.3.2. 分层与部署带来的问题

随着技术发展,软件的多样性,测试已经不局限于基于CS结构的GUI测试, 基于BS浏览器WEB UI测试。例如目前的安卓系统,苹果IOS系统,微软的 Windows Mobile 系统等等也加入到自动化测试领域。

应用软件也越来越复杂,例如:

  1. 分层的变化:界面层,接口层,业务逻辑层,实体模型层

  2. 部署的变化:从单机运行到双机热备份再到负载均衡,最近进化到分布式系统。

  3. 存储的变化:关系型数据库,非关系型数据库,缓存数据库,搜索引擎数据库

从下面的金字塔架构可以看出软件展示给用户的只有UI界面层

    
            /\
           /  \
          / UI \
         /------\
        /   API  \
       /----------\
      /   Service  \     
     /--------------\
    /    Component   \
   /------------------\  
  /      Database      \
 /______________________\
 
			

上面是软件的分层,一个软件经过部署后结构将会更复杂。

        
            /\
           /  \
          /CDN \
         /------\
        / WEB SER\
       /----------\
      / APP Server \     
     /--------------\
    / Message Queue  \
   /------------------\  
  / Cache|SearchEngine \
 /   Database| NoSQL    \ 
/________________________\

			

就WEB应用测试而言,涉及的内容就太广泛了,从浏览器->WEB服务器->APP服务器->缓存->数据库,中间会经过各种代理,负载均衡,分布式文件系统等等。

我们测试要涵盖:

  1. CDN测试,域名解析测试,

  2. WEB UI测试,包括HTML,Ajax

  3. API 服务器测试,api 是非人机交互界面,它是通过特定协议与API服务器交互通信。

  4. 代码单元测试

  5. 配置测试,配置管理过程中配置变更后的测试,含系统与应用

  6. 安全测试,接口安全,认证,权限

  7. 注入测试,JS注入,SQL 注入,Shell 注入

  8. 缓存测试,命中率测试,包括CDN,WEB服务器,缓存服务器,搜索引擎

  9. 压力测试,健壮性测试

  10. 扩展性测试,水平扩展测试,垂直扩展测试

  11. 高可用测试,集群测试

1.27.3.3. 压力测试存在的问题

请参考我的另一篇文章《压力测试中存在的问题》

这里我要再单独强调压力测试,很多人的测试方法是有问题的。

压力测试不是准备一台机器安装压力测试软件就可以开始测试的。 压力测试的环境非常重要,很多工作多年的测试人员都没有意识到这个问题。

压力测试有两个重点,一是压力测试环境的建设,二是压力测试顺序。

1.27.3.3.1. 压力测试环境

压力测试无论是单机还是网络,都需要一个好的压力测试环境,例如网络好比高速公路,如果公路成为瓶颈,你能测试出准确的数据吗?

首先准备测试环境,如单机测试要考虑CPU速度,磁盘IO速度,RAID卡的速度,RAID卡缓存大小,内存速度,PCI—E总线速度,甚至会涉及多对称CPU相关配置,内存与CPU通道的问题......等等

如果是测试分布式系统,除了上述单节点的注意事项,还要考虑到路由器/防火墙的包转发与连接数限制,交换机的背板带宽以及吞吐能力,负载均衡器的转发能力。

操作系统要考虑内核参数优化,TCP/IP栈优化,各种服务器的配置。

1.27.3.3.2. 测试顺序

压力测试顺序的切入点非常重要,测试顺序上多数人是从UI(人机界面)切入,即由UI驱动业务逻辑,这种测试顺序是错误的,例如用户->浏览器->WEB服务器->APP服务器->缓存->数据库等等,这就带来很多问题。

      
\------------------/
 \    Web server  /
  \   App Server /
   \ Cache / MQ /
    \ Database /
     \ Disk IO/
      \      /
      
				

软件的性能瓶颈通常是沙漏型的,最大的瓶颈莫过于数据库,其他服务器的瓶颈我们都能从架构的角度去解决性能问题。

所有我们应该先从数据库测试,首先确认数据库的配置优化是否能达到我们预期值。然后是缓存,消息队列,搜索引擎等等.....

至此我们已经知道数据库,缓存,消息队列,搜索引擎不会成为我们压力测试中的瓶颈。接下就可以测试应用服务器和应用软件了。

如果你的测试格局能够放大一点要考虑的远不止上述那些。 你还需考虑硬件,网络,操作内核参数优化,TCP/IP栈优化,验证运维配置是否能满足我们需求等等.....。

1.27.3.3.3. 瓶颈分析

我们需要有一套监控解决方案,能够监控到硬件的性能,软件的性能。

测试目的不是为了得出一个结果,告诉开发人员你的软件能支撑XXX并发,而是在我们测试中监控每项操作,计算出每个功能所用的时间,分析出性能的瓶颈,指导开发人员改进软件。

监控分为外部监控与内部监控。

外部监控是最容易实现的,有成熟的工具以及解决方案,CPU,内存,磁盘IO,网络流量等等。

内部监控是指软件运行加载到内存中之后的变化状态,例如内存地址,变量,函数调用,动态链接库载入,打开文件句柄,Socket地址和数据包等等。

1.27.3.3.4. 指导开发

通过数据,图表,快速定位软件存在的问题点,指导开发完成软件的改进

1.27.3.4. 持续集成形同虚设

持续集成,自动化构建几乎每个测试团队都会实施,但实际境况并不理想,仅仅停留在工具配置的阶段。几乎没有人在生产环境上使用自动化构建。

为什么持续集成无法应用到生产环境?

(待续,敬请关注作者微信公众号,现在已经是早上6点中了,要去睡觉了)

1.27.3.5. 测试的终极目标

我认为测试不仅仅是完成按照测试用例完成软件验收,如果仅仅测试用户可见的UI(人机接口)是不能满足现代软件的测试需求的。

测试者应该站在更高的角度看问题,测试者是有能力指导开发人员,改善软件的性能,健壮性,安全性,以及影响软件架构的设计。 测试者需要有广泛的跨界知识支撑,要不断学习提高,打破现有格局。

2016-12-03 06:30 AM