初期的性能测试主要是在测试环境进行,对单节点或集群发起高并发的调用,通过分析其在测试环境下的表现情况来评估生产的性能,但这种方式存在几个问题:
测试环境的实例数量相较生产是较小的,生产集群的性能多通过测试环境的数据简单乘以系数得到的,无法准确评估生产性能以及复杂链路下的节点资源配比。
测试环境的基础设施与生产环境存在差异,如机器配置、安全设备、网络、带宽、系统拓扑等,测试环境性能会低于生产环境,如生产环境接口响应为毫秒级而测试环境响应会到达秒级。
测试环境压测系统间多是独立的,即使各系统指标都正常,生产多系统链路串联至一起后也可能出现不达标的情况。
由于上述这些问题,我们便开始对生产压测进行了探索和实施,生产压测可以真实、高效的对系统链路的实际承载能力进行评估,同时可以提前发现当前系统链路瓶颈
可以保障重大活动时系统的稳定性,避免公司声誉因为技术故障受到损失;
可以对业务系统进行精准的容量评估,帮助公司以最低的成本满足业务的性能需求;
可用于一些重要项目重构后的进行性能验证,避免上线切换后可能出现的性能故障,快速渡过不稳定期。
目前我们已经在Landing页、流量准入以及春节红包活动等场景进行对应的生产压测,得到容量评估结果的同时,也暴露了一些系统的瓶颈问题,同时对于业务的方案设计也提供了数据支撑。
压测的实施流程可分为明确压测目标、前期准备、压测前、压测中、压测后这几个阶段,接下来会对其中重点流程进行介绍。
4.1. 明确压测目标
进行一次生产压测需要明确压测的目标,压测的目标包含所压接口的目标TPS/QPS、目标RT、目标成功率、目标SA(满足目标RT的请求比例),此外还包含链路中的设备的一些指标,比如网络带宽。压测目标的设置可以参考历史的峰值与增长趋势,进行合理的设置,建议设置时需要预留一定的buffer。
4.2. 链路梳理
链路梳理是生产压测中非常重要的一个环节,链路梳理的质量会直接影响压测实施的效率与安全性,链路梳理的目标是得出对应压测接口的完整链路拓扑,首先我们需要梳理链路上涉及到的大节点,如接口(出入)、应用、数据库、缓存、消息队列及各类中间件,通过大的链路拓扑可以关联到对应的负责人,便于我们进行前期的压测沟通明确压测范围,同时为进一步的详细梳理打下基础。推荐可以通过相关的链路监控快速获得链路拓扑。
梳理得到链路拓扑后还需要进一步详细梳理:
数据库信息,包括数据库的类型、jdbc连接串、用户名等相关信息,便于后续进行影子存储准备;
涉及到的数据表,对于压测接口会读到哪些表,会写到哪些表,表中是否包含敏感数据,便于后续设置漏数检测,构建影子数据时进行脱敏与偏移;
redis读写所涉及的数据,对于写入的场景需要考虑设置影子redis,根据实际情况觉得使用影子server或者对key添加压测前缀的进行隔离;
消息队列:需要梳理压测接口所涉及到的topic, 为避免压测产生的消息被正常消费者消费,针对这些topic后续会采用影子topic进行隔离;
外部接口调用:需要梳理出链路上未参与压测的依赖接口,这些接口后续需要进行mock挡板设置,避免压测流量流经非压测范围,造成不好的影响与损失;
站点涉及的下游压测站点:对于参与压测的站点,需要设置进下游检测列表,这样可对不参与压测的下游站点形成兜底的保护机制。
4.3. 数据隔离
数据隔离能力主要包括压测流量识别、影子存储、Mock挡板、下游调用检测等,是通过Agent的方式实现的,被压测应用需要接入Agent。
4.3.1. 压测流量识别
对于压测流量Agent会进行一些数据隔离的操作,那Agent如何识别此时是压测流量还是真实的业务流量呢?
压测引擎发出的流量会进行流量染色,做法是填加一个Http的请求头(例如isPresure=true
)将请求标识为压测流量。
应用服务接收到压测流量的请求后,Agent会在ThreadLocal中设置压测标记,保证后续Agent做隔离处理的时候能够在ThreadLocal中获取到从而识别此时是否是压测流量。针对于ThreadLocal跨线程传递丢失的问题是通过TTL(TransmittableThreadLocal)来解决的。
在服务间调用时和MQ等场景下也需要能够保证压测标记能够在链路中传递下来:
1)服务间Http调用,Agent在调用下游服务的Http请求中添加一个Http的压测请求头来标识压测流量,下游服务的处理同步骤2。
2)MQ生产者发送消息时,Agent在消息中添加压测消息头来标识压测流量,MQ消费者接收到消息后,如果消息头中有标记压测流量的消息头,会在ThreadLocal中设置压测标记。
4.3.2. 影子存储
Agent对于真实的业务流量不做处理,对于业务流量会写入和读取对应的影子存储。DB隔离有影子库和影子表两套方案:
影子库:基于业务库复制出新的影子库,压测流量会读取和写入影子库。
影子表:基于业务库中的表复制出新的影子表(表名添加压测前缀),压测流量会读取和写入业务库中的影子表。
Redis隔离有影子Redis Server和影子Key两套方案:
影子Redis Server:压测流量会读取和写入影子Redis Server。
影子Key:压测流量在读取和写入Redis时在Key中添加压测前缀。
4.3.3. Mock挡板
在真实的业务场景中,业务服务会调用一些第三方服务,而在做压测的时候第三方服务通常不会参与压测,那就需要Mock掉第三方调用。
用户添加Mock挡板配置,包含需要Mock的类名方法名以及返回结果代码块。
Agent读取到新增的Mock配置会对在需要Mock的方法调用前添加新的拦截点,在压测流量执行Mock的方法之前,使用Groovy执行Mock中配置的返回结果代码块并直接返回,不会执行该方法中的业务逻辑。
为了在压测前验证的时候能够方便看到Mock方法是否调用成功,Agent会定期将Mock方法的调用次数进行上报并在平台进行展示方便用户查看。
4.3.4. 下游调用检测
隔离能力是通过应用接入Agent实现的,在生产压测过程中需要保证应用的所有实例都接入,否则一旦压测流量请求到未接入Agent的站点就会对生产业务造成影响。
虽然提供了Mock挡板的功能,但是在压测前进行链路梳理的时候,如果漏梳理了一些第三方服务的调用,未添加Mock配置,压测流量就有可能会调用的第三方而对业务造成影响。
在链路梳理过程中,需要梳理应用的下游站点中一起参与本次压测的列表,在平台进行配置。
平台根据Agent上报的心跳和实例数进行对比,过滤出下游站点中全部接入Agent的列表下发配置。
Agent对压测流量的下游调用(例如Http调用)进行拦截,如果在下游站点列表中允许调用,如果未在下游站点中则抛出异常。
数据隔离整体方案如下图:
4.4. 压测实施
生产压测实施过程中,通过采用TPS模式+阶梯递增的方式使压测流量可控,同时压测平台也提供了终止条件、漏数检测等功能来降低压测过程中对生产实际业务的影响。
4.4.1. 终止条件
为了减少压测过程中对生产实际业务的影响,压测平台支持配置压测终止条件,一旦触发终止条件,立即停止压测。
终止条件包含RT、成功率、RT达标率(SA)等接口指标,CPU利用率、内存使用率等应用指标,以及前置链路节点指标如高防、WAF、F5等。
如上图,当压测接口响应时间>=2秒或成功率<99%时,立即停止压测。
4.4.2 漏数检测
针对一些极端情况可能造成的压测流量写入业务DB的情况(简称漏数),压测平台也提供了漏数检测的能力。
由于压测准备期间会对影子库和影子表中的数据进行偏移,偏移后的数据在真实业务库中是不存在,压测前根据偏移数据的特征添加漏数脚本。
压测过程中,压测平台连接对应生产库执行漏数脚本,若存在漏数情况则立即停止压测。
4.5. 实况监控
压测过程中,通过平台实时查看接口TPS、平均RT、请求成功率、平均RT达标率变化以及应用节点的CPU利用率、CPU Load、内存利用率变化,同时会观察业务大盘和监控大盘,如有异常情况及时停止压测。
4.6. 压测报告
压测结束后,平台自动生成压测报告,通过和业务目标对比判定本次压测是否通过。报告中还包含接口TPS、平均RT、请求成功率、平均RT达标率变化趋势,应用节点的CPU利用率、CPU Load、内存利用率变化趋势,以及压测流量调用链明细。
最后通过分析压测报告中的数据进行瓶颈分析和容量评估。
目前我们已经完成了生产压测的初步探索,后续我们也会对生产压测进行更加深入的研究,丰富数据隔离的插件支持,同时会探索在压测期间对压测链路与正常链路的情况进行监控,此外也会探索对非java生态的生产压测支持,逐步的使生产压测往更安全、更全面、更智能的方向发展。
Java、大数据、前端、测试等各种技术岗位热招中,欢迎扫码了解~
更多福利请关注官方订阅号“拍码场”
好内容不要独享!快告诉小伙伴们吧!
喜欢请点击↓↓↓