需求背景
下单接口承接公司内部业务和开放API业务需求,在与PDD对接过程中,PDD给我们的订单量级是每日百万,峰值可达40W单以上,PDD要求我方单台TPS能达550笔/s。
瓶颈
专业测试人员在UAT环境进行下单压力测试,经过反复压测及配合阿里云监控,下单接口性能只能维持150-200笔/s,且压测到一半,后续的压测会经常出现请求超时的情况。
分析
首先,对于下单接口的性能问题,会有很多原因的,可能是RPC线程池设置不合理,下游依赖超时时间不合理等,需要对业务进行全链路分析。下单链路简至如下:
由此初步判断,在高压下单时,会经由小前台进行转发,可见小前台和中台的对接,受HTTP线程池和依赖超时时间影响。
同时,观察阿里云监控并在数据库操作时记录debug日志,分析得知,高压力下单,数据库的连接池会得不到很好的利用,后续很多请求即使到达中台也会在数据库操作处等待很久从而导致小前台超时。
再次,在中台下单业务处理层面,涉及到多个系统之间的依赖调用,进一步增加了耗时。下单业务简化如下(实际上要比下图复杂的多):
理论上下单接口整体的响应时间取决于链路最慢接口的响应时间,在debug日志分析中,分析到下单中台再进行下单业务处理时,会向百度的开放API进行请求,且该接口属于另一中台业务,耗时尤为长,平均高达600ms。于是对该业务进行内部沟通,是否与下单接口要求强一致性,答案是否定的,于是将这部分业务调用进行异步化处理,从下单接口整体链路中剥离出去。
其二,在基础数据获取层面,依赖基础数据中台,发起的HTTP调用就会存在耗时,即使对方在接口数据层面做了一层缓存,经分析这部分数据是不经常变动的,为了下单接口的性能极致化,在下单中台加入一层缓存,不再发起HTTP调用,对于基础数据的变更,根据数据的类型不同,采用不同的监听方式,例如MQ、binlog这里不展开描述。
初步阶段优化总结 :
1.提高小前台HTTP超时时间,调大小前台HTTP线程池,调大中台数据库连接池大小。
2.对业务进行全链路分析,结合业务,异步优化。
3.qps调用增加缓存机制
再次压测
UAT环境拟80W订单,效果比之前好点,超时减少,但是在压到35W左右,数据库IO和应用服务器CPU飙升,请求一瞬间被hang住,效果仍然不理想,远没有达到PDD的对接要求。复盘重整迫在眉睫!
复盘
现状 : 订单中台接收上游订单推送,对于订单的业务处理都集中在该服务上,微服务链路上,拆分为接收上游单据小前台、订单中台内部处理、推送给其他下游。上游小前台主要还是承担"履约"职责,接收外部交易订单。核心处理还在订单中台。
链路改善 : 与PDD业务方进行沟通,对于订单的下发交易并非要求实时响应。于是将订单小前台–>订单中台的HTTP协议改造为消息驱动的MQ协议。效果很明显,下单接口不再依赖HTTP同步机制,很友好的利用MQ协议进行解耦。
新的问题
再次压测,无疑TPS上去了,却引发了新的问题。
外部交易订单的下发对于外部系统不再有感知,压力来自中台内部去消化。中台MQ存在大量消息堆积,队列经常堆积50W单左右,UAT单台机器吞吐平均5.6条/s。
业务上,订单下发完后续的业务处理依赖订单的查询,若交易订单堆积在MQ中,势必会影响后续的业务处理流程。中台提高订单处理效率迫在眉睫!
解决思路
继续debug日志分析,经过上述一轮又一轮的优化,下单业务处理平均耗时在300ms以内,那单台机器平均1s能消费处理5个请求,按照压测70w订单量,假设在30分钟内全部消费完,那单台机器30分钟能吞吐5 x 60 x 30 = 9000,在生产上至少需要增加10倍以上的机器。于是查阅MQ官方文档(Spring-Cloud-Stream),以多线程的方式增加消费者的数量,从而提高吞吐。单台机器MQ的消费线程数初始化增加到50,最高可到达最大线程数设置为100,效果很明显,消息堆积明显减少了很多,进一步优化,50个线程每次都是一条一条消费,希望消费能力强的机器能一次多消费,于是调整预拉取数量为10,也就是说,所有的机器运行极好的情况下,初始化50个线程,每个线程预拉取10条进行消费,一次能拉取500条。
总结 : 接口的超时或是性能优化,存在的因素会有很多,首先要定位到具体API,结合业务对链路进行全方位分析瓶颈在哪,qps调用增加缓存,耗时操作结合业务进行异步化。