1. 业务背景
随着越来越多的金融行业基于mPaas搭建并上线新的App,App整体架构的负载能力,各个环节的优化逐步成为各个客户关注的重点。
压力测试是实现以上功能的主要方案,一般可以基于压力测试,测试后端业务的负荷瓶颈,评估整体架构性能,业务稳定峰值,排查出各节点的薄弱关系,优化系统资源,避免短板效应,也可以为运营提供准确的用户承载量作为作证,避免活动/新应用的上线带来的突发流量造成的用户体验不佳。
本次借着xxxx的压测机会,对以往的案列做一些梳理。
2. 全链路压测与原理
通常我们可以简单的把负载性能=单机性能*机器总量
这一公式套用到预估的方案中,但是在实际的场景下,常常会涉及到大量的业务节点,如dns,网关,数据库等环节,都有可能是导致整体业务性能的瓶颈,因而实际服务能力可能与预期存在较大误差。
一般用户会通过loadrunner等方案实现生产环境下的服务器性能压力测试,但是在对于mpaas下的使用中,如复杂的部署,无法通过mgs网关,高昂的费用等难点应运而生,为了解决这些痛点,mpaas团队这边依据多位客户的述求,提供出mgs全链路压测方案。
区别于以往的测试方案,全链路压测方案中最大的不同是视角上的不同,站在客户端角度上作为切入点,将整个服务端链路作为一个黑盒,以真实的request和response作为评估的依据,模拟真实的业务请求,真实的数据流量,真实的用户习惯,来达到得出尽可能真实的评估结果。
2.1 链路梳理
在一个标准的数据链路中,一般为以下模型
而在全链路压测中,我们把整体的服务端实现视为一个黑盒,因而我们所需关注的焦点聚焦在前半段,重点可以概括为
1.客户端请求构建
2.客户端请求发送并通过mgs网关
3.客户端解析mgs网关返回的response并做出正确处理
4.实现高并发的客户端请求集群
以上再次梳理,可以归纳出以下难点
难点1 客户端请求构建
mPaaS 移动网关 RPC 通讯是在 HTTP 协议基础之上的实现的一种标准化接口方式,在复用 HTTP 请求标准的前提下,定义了一套数据交换格式,采用Header,Body 作为实际区分,可以近似理解为,通过Header 中的Operation-Type做为真实api指向,将body部分依据规则封装后进行转发。
在该步骤中,我们以JMeter作为实现方案,Jmeter灵活的脚本特性可以良好的实现客户端的真实请求模拟。
难点2 数据加解密
mPaaS 移动网关 RPC 请求特有的数据加密方式构建请求中比较复杂的部分。客户侧已有的测试方案不能覆盖这部分能力,因此往往选择关闭网关服务端验签和加密功能实施压测。这种方式的隐患在于无法估计加解密给网关服务器带来的计算压力。根据经验,不同的加解密算法配置,对网关的吞吐量有 20% ~ 40% 影响。在此阶段,由金融线 SRE 团队基于用户生产环境定制开发的 JMeter 插件 MGSJMeterExt,该插件逆向实现了请求体的加密和解密过程,使得压测脚本的编排可以包括加密部分。
难点3 请求签名构建
mPaaS 移动网关 RPC 请求特有的签名校验机制也比较特殊。同数据加解密一样,目前客户侧无方案可覆盖这部分能力,往往选择关闭接口验签进行测试。同样借助 MGSJMeterExt,可以实现在 JMeter 中实现对报文的正确签名,并通过服务端校验。
难点4 压测集群环境部署
对于压测来说,需要的重点侧重于真实,真实的流量入口,真实的并发数量,才能得出真实的结果,而自行实现压测环境,高昂的集群部署费用,也成了不必要的开支,因而我们推荐用户采用阿里云PTS作为压测平台,基于其他方案,具有部署简易,支持jmeter脚本,流量真实等优势,也可为用户提供更为详实的压测报告。
概览
以上模型简单可以归纳为以下结构
3.全链路方案及实施
3.1 前期准备及调研
在前期阶段,目标是为了为实际的压测提供相关的准备和数据支撑,确立压测目标和整体方向。
3.1.1 目标及数据准备
1.客户需要明确自身的压测目标和压测目的,基于压测目标,参照以往的运营数据,给出涉及到的具体业务类目和可能的用户行为习惯,在整体的业务中各习惯所带来的相关比重关系。
3.1.2 客户端准备
1.客户端这边需要依据相应的业务目标,整理出在客户端实现中可能涉及到的接口和数据流程,如是否包含前置步骤,如登陆等,是否包含强制的步骤,如首页的刷新等,通过抓包等收集该步骤中真实的request和response,以及确定符合预期的值条件。
2.该步骤涉及业务结构的不同,亦可由服务端接口端完成该准备。
3.1.3 服务端准备
1.服务端这边依据3.1.2中统计的相关接口,做好相关的数据挡板,避免导致测试数据污染真实数据库。
2.由于在mpaas全链路压测中,服务端被视为黑盒,因而需要实现对于服务端各业务的性能指标的监控,为后期的服务端调优作为依据。
3.1.4 MGSJMeterExt插件准备
由于MGSJMeterExt需要依据实际网关环境进行定制开发,需要用户提供以下数据
1.工作空间相关环境数据
2.加密算法和公钥
用户Q&A答疑
Q:如何实现压测脚本
A:会由我们的专家团队和现场同学完成简单场景下的压测脚本培训,在实际的场景下,可能涉及到业务的多个环节,如登陆token的获取,一些明确的前置步骤,这一类由于涉及到复杂的业务场景,需要客户在阿里专家团队的协助下自行完成
Q:为什么是全链路的
A:虽然我们的压测脚本是基于客户端逻辑实现的,但是我们实际上是模拟了真实的数据请求,也会确认服务端的返回是否达到预期,涉及到整个完整的数据链路及节点
Q:链路的指标如何实现埋点
A:压测方案的对象是基于黑盒的,通过系统的pts指标,请求参数与返回的回报率,校验符合预期结果的成功率,来确认基于用户角度下的整个架构所能负载的性能,对于一些后端的指标,由于不同的客户采用的服务端的架构存在不少的差异,对于后端这类指标,一般对应的服务商都能提供相关的监控方案,也无需mpaas这边进行处理
Q:为什么使用PTS
A:mpaas团队实际上提供的是mgs的通讯解决方案,协助客户完成pts脚本的编写,并不强制使用PTS,只需要能提供相关的jmeter集群部署环境即可,且PTS相关资源需要用户自行采购,但目前mpaas团队基于多个案列评估,相对而言,使用PTS,有更高的性价比,且能提供更为符合预期的压测环境,完整的压测报告,故推荐用户使用PTS进行压测
Q:有没有什么详细的标准,如2c4g情况下,或者4c8g下,应该达到怎样的性能指标
A:压力测试本身即是为了明确在相关的系统资源下,可以达到的性能指标,由于服务端的架构不同,实际业务涉及的流程节点不同,不同环境下的性能存在着巨大的差异,这些即是使用压力测试的目的,需要通过压测才能明确真实的指标和评估各个节点的实际资源耗时
3.2 Jmeter开发与脚本改造
在2.1中,我们归纳出了MGS通讯方案的特殊侧重点,因而我们需要在jmeter完成这几点的改造
3.2.1 Header改造
在Header中,我们需要注意以下几点
1.MGS网关协议是依赖于一些Header字段的,因而需要确保网关参数齐全。
2.部分参数为固定值,可直接写死,相关的配置可以参考控制台下载的配置文件。
3.如业务有其他的header依赖如cookide等业务上需要使用,也可直接添加,mgs网关不会对header信息进行过滤
3.2.2 Url改造
在Url中,我们需要注意以下几点
1.Url的实际指向应为Mgs网关,而非实际的业务服务器,相关的配置可以参考控制台下载的配置文件。
2.目前所有到mgs网关的请求均为post,如有get请求,也是由mgs进行转发时变为get的,在与mgs的通讯中也为post。
3.Body部分如无特殊需求建议如图所示即可
3.2.3 Request改造
在Request中,我们需要注意以下几点
1.这里的加密/验签,依赖于MGSJMeterExt文件,需要引用该文件。
2.一般情况下仅需修改//config部分即可。
3.下述部分一般为统一方案,主要为了实现加密和验签,无需修改。
3.2.4 Response改造
在Response中,我们需要注意以下几点
1.在这里考虑到施压机性能,不会影响到服务端的评估能力,因此若无数据二次使用需求,或结果判断需求,这里可不写
2.如有相关需求,可在这里完成response回参的二次处理
3.3 实际压测
大致的步骤可归纳为
3.3.1 PTS 及脚本性能调优
阿里云性能测试服务(PTS)提供了方便快捷的云端压测能力,在本次压测服务中,借助 PTS 实现互联网压力流量的输入。有意思的点在于,加解密计算不仅给网关带来计算压力,也会给施压机带来了一定的计算压力。因此,第一个版本的插件和压测脚本在实施前,我们首先进行了针对试压机进行了的“压力测试”。
第一轮基础测试
PTS 试压机配置:
- PTS 单 IP 单元配置
- 并发数 500(单机最高并发)
- 固定压力值流量模型
- 2 分钟压测时常
从回收的压测报告看,TPS 结果并不高,但返回 RT 值并不高:
接下来观察施压机的性能表现,可以看到施压机的 CPU 使用率水位一直比较高,因此有理由怀疑加密计算压力给施压机的压力释放带来比较大的影响
随后在 MGSJMeterExt 插件实现代码中进行性能优化和缓存处理,通过对重复内容加密结果的缓存,大幅降低了计算压力;同时,为了避免缓存设计引起内存问题,对缓存上限进行了限制。
第二轮测试
与第一轮的测试配置完全相同,仅更换了优化后的加密插件。从回收的测试报告看,场景 TPS 有 75% 的提升:
从施压机 CPU 性能看有一个明显的优化。
第三轮测试
有了第一轮的摸底和第二轮的优化情况,第三轮测试在配置上使用两台施压机满负荷进行压测,观察压测结果:
从结果看,压测脚本和编排过程符合预期,可以在客户生产环境进行正式的 PTS 云端压测。
3.3.2 生产环境压测摸底
在正式压力测试开始,进行了若干轮小规模的压力测试,观察后端系统的工作状态是否符合预期。摸底期间发现如下问题:
Nginx流量转发不均
从MGS容器的日志表现上看,部分容器始终获取不到任何请求。经过排查发现该问题由三个原因导致:1)DMZ区Nginx转发配置少配了一个MGS容器IP;2)DMZ区到每一个MGS容器IP的网络策略均需要开通访问权限;3)Nginx转发规则设置为iphash,在单IP来源的测试情况,流量仅能转发到一个容器上。
配置了正确的IP列表、开通了网络权限以及修改转发规则后,该问题得到解决。
特定MGS容器基础CPU负载过高
前期测试发现,有一台MGS容器(mpaasgw-7)在静默状态下的CPU负载在25%,不符合预期。登录容器发现存在一个JPS进程,消耗了大量的CPU。(注:JPS, Java Virtual Machine Process Status Tool),是java提供的一个显示当前所有java进程pid的命令,参见 https://docs.oracle.com/javase/7/docs/technotes/tools/share/jps.html )。怀疑是前期调测阶段调用后未正常释放。杀掉JPS进程后问题解决,为了避免其他问题,一并重启了该容器
CoreWatch监控平台无法访问
CoreWatch控制台无法访问,浏览器中报502错误。重启CoreWatch容器后,页面可以加载,但始终处于加载中状态,http://corewatch.***.com/xflush/env.js 一直处于pending状态。排查发现 ALB 实例监听配置存在错误,修正后问题得到解决。
3.3.3 生产环境压力测试&总结
在解决了 3.3.2 中的所有问题后,系统具备了压力测试的条件,正式压测会针对“加密场景”和“非加密”场景分别做压力测试。
由于生产数据不做外泄,以下仅对遇到的问题进行一些例举。
“加密”情况下测试
1.压测时发现在并发数500左右即出现TPS不做增长,代表着可能到达了瓶颈。
2.观察MGS网关容器的负载情况,整体CPU负载达到极限。
3.同一时间段的MCUBE容器CPU负载情况健康,其他性能指标(IO、网络等)也处于健康状态。
4.从上述情况看,加密场景下,主要性能瓶颈在MGS网关上,根据经验及流程分析,主要性能压力由报文加解密过程中的密集计算所带来。要解决这一瓶颈,需要对MGS容器进行扩容。
“不加密”情况下的测试
1.TPS的增长在并发达到1000左右时停止增长。一般情况下,这种情况说明触及了系统容量的瓶颈。
2.观察MGS网关容器的负载情况,与加密情况下的情况不同,此时整体CPU负载均不高。
3.与此同时,根据网络组的反馈:压测期间互联网到DMZ区的TCP Session数量是DMZ区到内网区的3~4倍,交易内网段的防火墙CPU压力较高。
4.结合上述三种表现,怀疑触及网络层面瓶颈。根据现场情况发现,DMZ区Nginx转发到内网时没有采取长连接保持策略。修改Nginx配置,添加keepalive 1000配置,重新进行第二轮测试。关于参数Keepalive说明:默认情况下,Nginx访问后端都是用的短连接(HTTP1.0),每一个新的请求,Nginx 都会新开一个端口和后端建立连接,后端执行完毕后主动关闭该链接。Keepalive参数会告知Nginx和后端服务器之间缓存的长连接数量,当新的请求进来时,可直接复用TCP连接,减少建立TCP连接所带来的性能影响。参见:http://nginx.org/en/docs/http/ngx_http_upstream_module.html。
总结
在上述问题优化后,非加密场景下至少有70%的性能提升,加密场景下10%的性能提升,并在行方MGS扩容完成后可实现大幅的性能提升,调优的结果超过了客户的预期,得到了客户的认可