一怒之下,我写了一个开源流量测试工具

继一怒之下我写出了 Vivian(详见“测试驱动开发 Nginx 配置”)之后。又在等待客户审批流程的时间里自己写了一个流量测试工具。

背景

客户的站点是通过 Wordpress 搭建的,这个应用放在一台 EC2 虚拟机上。奇葩的是,这个应用的 MySQL 数据库也在这台虚拟机上,之前做过一次 RDS 迁移,失败了,原因未知。看起来这个应用和数据库就像筷子兄弟一样,不离不弃,而且没有办法通过 AutoScaling Group 进行水平扩展。也就是说,所有的东西都在一台虚拟机上。

我所要做的,就是把这个架构重新变成可自动水平扩展且高可用高性能有缓存低消耗具备监控和更加安全且有版本控制并可以通过持续交付流水线来半自动部署的架构。你可以重新读一下上一句加粗文字的内容。没错,目前他们连版本控制都没有,所有的操作在服务器上通过 mv 之间 scp 进行。

很不巧的时候,这个“筷子兄弟”应用在上周开始,晚上随机的 Down 机,表现为数据库被删。但通过日志可以发现,是由于内存资源不足导致的 MySQL 数据引擎加载不了导致的。

由于需要做“筷子兄弟”拆分手术,目的是要把数据库和应用程序分开,并且需要进行一些服务的重启和拆分。这些操作中会导致停机时间,为了能够度量这个停机时间,便于做出更好的决策,客户希望在测试环境上能够通过模拟生产环境的工作状态来完成这个任务。我设计了方案,包括以下几点:

  1. 知道每一个可能引起停机的操作引起停机的时长。

  2. 测试 RDS 能带来多少的性能提升。

  3. 找出整个架构引起停机的根本问题。

  4. 在 500 个并发用户访问的情况下,会出现的性能拐点。

  5. 能够度量应用的资源损耗。

客户已经购买了 NewRelic 和 Flood.io (我在 17 期技术雷达里提交的条目,叉会腰。)但是 Flood.io 的账号分配需要一个额外的审批才可以使用,也就是说,我得等到第二天才能使用。

我想,也许 github 上会有这样的工具能够满足我这个简单的需求,搜了一圈,没有合适的。

于是,一怒之下,我用了大概两个小时的时间用 Python 编写了这样一个测试工具。

工具的设计

There are only two hard things in Computer Science: cache invalidation and naming things.

-- Phil Karlton

在计算机科学里,缓存失效和命名事物是两件最困难的事情。于是,为了纪念这个事情,一开始我用提出这个需求的客户的名字(Dave)来命名它,但可能不太好记忆。所以最后还是用 Wade (Web Application Downtime Estimation)作为这个工具的名字。它很简单,可以在https://github.com/wizardbyron/wade 找到。

如果我需要知道停机时长,我必须要先能够持续不断的发出 http 请求,并记录下相应 状态不是 200 OK 的返回。我并不希望应用是一个死循环,因此我需要能够加入时间控制。我期望用下面的这样的方式来使用:

wade -t 10 -u https://www.baidu.com

其中,-t 代表时间,10 代表持续分钟,-u 表示要测试的 url。我期望这个工具能够连续的帮我输出每次请求的时间和 HTTP 状态字。

例如:

[2018-07-05 22:30:57]status:200
[2018-07-05 22:31:08]status:200
[2018-07-05 22:31:15]status:200

这实际上是在构造一个命令行工具的 End-2-End 测试的设计,#我们可以用 BDD 的方式来构造命令行工具的 End-2-End 自动化测试#。这个需求其实很简单,我大概花了半个小时就完成了。

在实际应用中,你需要先运行这个程序,然后再执行那些可能引起停机的操作。于是我准备让它运行30分钟,因为这些操作会执行多久我并不清楚。

很好,经过测试,这些操作只会引起 5 秒左右的停机。

不过,我好像忘了一个重要的事情……

那就是这个应用是单进程的,也就是说,这个实际上和真实的场景相差很远。我需要能够有 500 个并发 HTTP 请求,于是我把它改造成了多进程的。我期望用下面的这样的方式来使用:

wade -t 10 -n 5 -u https://www.baidu.com

其中,-n 代表进程数量。

有了多进程,我就需要改变这些应用的输出。对于多进程
应用,输出需要知道每个进程的执行情况并且要能够汇总。因此,我期望应用能够这样输出:

{'Thread': 0, '2XX': 2, '3XX': 0, '4XX': 0, '5XX': 0}
{'Thread': 3, '2XX': 2, '3XX': 0, '4XX': 0, '5XX': 0}
{'Thread': 1, '2XX': 4, '3XX': 0, '4XX': 0, '5XX': 0}
{'Thread': 4, '2XX': 4, '3XX': 0, '4XX': 0, '5XX': 0}
{'Thread': 2, '2XX': 4, '3XX': 0, '4XX': 0, '5XX': 0}

因为,其实3XX 类的返回值在某些情况下也应该算是正确,而 4XX 和 5XX 类的返回值应该分开统计。因此,我改进了一下这个工具。

在改进后我重新测试,我找到了问题的答案:

我成功的把数据库迁移到了 RDS 上,并在测试环境实例上停止了 MySQL 进程,带来了 40 倍的性能提升。发现这个应用的数据库需要最少 10 GB 的内存才能正常工作。

当我以 500 个进程去持续请求的时候,我把服务器弄挂了。输入的响应很慢,且执行命令会返回-bash: fork: Cannot allocate memory 的错误。通过减少进程数,我发现一个用户请求会占用 110 MB 左右内存,要满足 500 个用户的并发访问,主机需要最少 64 GB 的内存。

由于并发用户增长的同时,内存也在增长,物理内存用完之后会使用 Swap 区的虚拟内存空间。当 Swap 区的空间占满后,这个时候因为没有可分配内存,所以应用响应奇慢。即便是我终止了测试请求,仍然没有缓解,我猜之前的请求已经在 HTTP 端排队,在请求没有结束或者超时释放资源,后续的请求会继续排队。

那个…… 好像,我对这个服务器进行了一次 DoS (拒绝服务)攻击

加载了 NewRelic,我发现这个应用在加载首页的时候性能是最低的,而大部分的资源都消耗在了 select 查询上。因此,我判断其中的表或者数据有问题,会进行大量加载。其次,可以通过给首页增加页面缓存,或者在数据库库端加入缓存,来缓解资源占用。毕竟,首页的访问时最频繁的。

最后,我们可以把 wade 在测试中度量到的数据当做是架构演进中的验收测试或者冒烟测试,集成在持续部署流水线中,在变更基础设施或者部署应用之后执行。我们需要非功能的架构级别的自动化测试来保护应用架构的重构。

反思 - 少即是多

如果没有这个工具,想得到以上的答案。我需要同时在三个服务(AWS CloudWatch, NewRelic, Flood.io)之间来回切换,并且搜集到需要的数据。那么多的数据,找到一个简单直接能反应问题的数据也很困难。而在等待账号审批的过程中,我就写下了这个工具。这个工具覆盖了客户会关心的基本场景和数据之间的关系。而这三个工具不能同时都满足(其实NewRelic 其实就差一点点)。虽然每个工具在各自领域 和所面对的客户都是非常强大的工具,而一个真实客户需求的场景 - 找到在正常压力下影响停机时间的因素 - 却很难被满足。

所以,对于非目标的用户和使用场景,产品丰富的功能和数据有可能是需要被过滤的噪音。一个产品所要面对的用户场景越多样,它所引入的噪音就会越多。而更多的增值服务和高价值服务,则被淹没在了这样的噪音里。

支付宝和银行的手机端应用就有这样的问题,什么都做的事情,一般什么都做不好。

最后

作为一个两个小时之内完成的工具,wade 缺乏各种自动化测试。但是,从 wade 设计过程我们可以看出,虽然我没有写自动化测试,但是设定期望并完成期望的结果是一致的。从这个角度上讲,TDD 也是把大脑中对程序的设计过程记载下来的一个活动

如果对这个工具感兴趣,欢迎 PR:https://github.com/wizardbyron/wade

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,928评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,192评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,468评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,186评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,295评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,374评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,403评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,186评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,610评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,906评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,075评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,755评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,393评论 3 320
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,079评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,313评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,934评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,963评论 2 351

推荐阅读更多精彩内容

  • 1、通过CocoaPods安装项目名称项目信息 AFNetworking网络请求组件 FMDB本地数据库组件 SD...
    阳明先生_X自主阅读 15,975评论 3 119
  • 今天下了一天的大雨,打算最近天天去扫街,天天下雨,结果都没有去,活动粉扑今天全部到货,所以今天把活动的名单全部发出...
    罗新美阅读 186评论 0 0
  • 我在河边 坐在木椅上 左手是经久的皮包 右手是圆滚滚的丑橘 红桥上传来年月演奏的高声 凝怔一会 竟会移到远唐的灯火...
    勒鱼驴阅读 445评论 3 1
  • android图的压缩分三种 1.质量压缩 2.比例压缩 3.减少像素占的位数压缩图片 质量压缩 质量压缩就是对图...
    磨磨唧唧儿童杰阅读 410评论 0 1
  • 001不要等到明天 有一个冷笑话,“等明天请你吃饭!”“不用了,我今天有空!”意思是请人吃饭要真诚,不要隔夜。行动...
    流油果阅读 90评论 0 0