全链路压测降低 rt之路

前言

概念名称

RT,即real time(实时),计算机领域术语,来描述操作系统。

RT,即Regression Testing(回归测试)。

RT,也有Reaction Time(响应时间)的意思。

概念含义

1.RT=real time意思是实时.常用来描述操作系统(实时操作系统).RT实际只是个相对概念指延时不足以造成影响.常在控制领域使用实时操作系统.例如VXworks,RTlinux等.

RT(realtext),实时文本,是一种常见的流媒体格式。

2.RT=Regression Testing 回归测试,是软件生命周期的一部分。一般用于完成了旧代码重编辑后,重新进行测试以确认修改没有引入新的错误或导致其他代码产生错误。

3.RT=Reaction Time 响应时间,指系统对请求作出响应的时间。在讨论一个系统的响应时间时,人们通常是指该系统所有功能的平均时间或者所有功能的最大响应时间。当然,往往也需要对每个或每组功能讨论其平均响应时间和最大响应时间。

最近在进行全链路压测,实际负责订单相关接口。降低rt之路总体总结如下:

一、引入监控

监控引入可以再极大程度上,帮助我们分析压测过程中各阶段耗时,以及耗时的方向。此次压测试件使用监控工具为grafana与jaeger。

cat前期有使用,但前期压测内存使用一直80%以上,dump之后查看发现cat线程占用大量内存,去除cat引用之后,内存使用得到明显降低,保持在20-30%之间。

二、适当冗余

对于订单列表和详情等数据展示接口,一些商品、优惠信息可以作为快照,在创建是即冗余在订单库,查询时不再次去外部服务获取对应信息。

三、数据层优化

由于此次订单存储采用了分库分表的方式,订单详情与列表的访问到哪个库,取决于压测准备的数据是否足够离散。中途出现单一数据库压力远高于其他数据库,后发现是数据准备问题。

合理化索引与redis等缓存也能降低rt。

四、并行调用接口

由于订单确认和创建过程,会从大量其他服务获取数据,不同接口之间又存在一定的依赖关系,所以前期使用串行调用的方式。但实际上部分接口可以并行,所以前期使用CompletableFuture去分批调用外部接口的方式并行调用,接口性能有一定提升。

后续改进主要有以下几点:

4.1、隔离各接口使用的线程池

防止长短尾拖垮线程池

4.2、合理设置线程的线程数

一次服务中,所有异步外部接口实际都会被调用一次,所以最慢的接口决定线程池线程数大小。由于外部调用线程是io密集型,接口等待时间远超自身逻辑耗时,根据公式

线程数=CPU可用核心数/(1-阻塞系数)+1

rpc调用阻塞系数远大于0.5,所以线程数可以远大于2*cpu+1个数,

此时实际线程池大小可以取决于接口目标rt与tps,比如确认订单接口目标rt100ms,单机tps320, 但是确认订单调用其他服务,耗时最长的接口rt为25ms,则此时一个线程可以承担40tps,8个线程可以承担所有tps,但此时公式还有+1,多聊几句说说这个+1的含义。

如果我们先假定给予8->8个线程数作为最大线程数,同时以8/4=2作为核心线程数。
当网络抖动或者下游接口抽风严重,线程池中全部线程运行仍旧不能满足需求时,新的请求会进入等待队列。
此时设定接口超时为1000ms。假设此时抽风接口耗时100ms,单机qps达到320,那么每秒有160个请求希望进入等待队列。
此时如果一秒后接口处理速度恢复正常,线程处理速度刚好等于进入速度,等待队列永远无法清空。
所以实际最大线程数+1用于抖动后清理等待队列

4.3、合理设置等待队列

为了防止网络抖动,所以实际上我们使用的线程数是CPU可用核心数/(1-阻塞系数)*2=16。即哪怕出现问题,下有接口需要双倍rt,我依旧可以正常运行,此时正常情况请求不会进入等待队列,但是如果网络抖动特别厉害,出现三倍乃至四倍rt,那么线程池依旧无法及时处理所有请求。

等待队列长度算法,个人倾向正常处理后,队列尾的请求多久后被正常处理来计算,接受最长时间为500ms,超过500ms还不能处理,倾向丢弃。那么一致正常rt25,每个线程500ms可以处理20个等待队列内的请求,我们有16个线程,所以等待队列长度设置为320。此时队列过程无意义,队尾请求一定会超时,而且后续全部超时,灾难性后果。

4.4、主线程不能停

最后聊一下线程池的使用,前期使用CompletableFuture时,是把可以异步的都new出来,然后用allof之后get的方式异步执行,但这样存在的问题是主线程被空置了,等待期间主线程并没有执行任务而是在空跑,所以后续采用了类似下文的写法

// 异步线程开启——从A服务查询数据
CompletableFuture<Void> aFuture = CompletableFuture.supplyAsync(
  () -> queryFromA();,
  OrderConfirm1ExecutePool.getInstance().getExecutor()
);
// 主线程执行——从B服务查询数据
queryFromB();
// 获取异步线程结果
ThreadsUtils.completableFutureGet(aFuture);

五、替换BeanCpy

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值