出现这个问题,首先是采用临时加机器的方法来解决,有所好转
情况十分诡异,因为虽然接口返回时间达到了 2 到 3 秒,但返回数据是无误的
接口做了什么呢?逻辑十分简单,调用了一个远程接口,然后组装成一个新的对象返回
查看监控,我的接口调用的接口的 99.9% 的耗时在 450 毫秒左右,而我调用该远程接口的超时时间设置为 500 毫秒,如果超时,那么是无法返回任何数据的,而实际情况是数据返回无误,也就是说依赖的这个远程接口调用成功并在 500 毫秒以内返回了数据,而本地的创建并初始化对象占用了剩余的 1.5 到 2.5 秒的时间,这显然是不合理的,难道是因为返回对象过大,造成了频繁 GC ?查看 GC 日志,full gc 并没有增加,而 young gc 有小幅度上升,但是无论怎么 GC 显然不可能占用 1 到 2 秒的时间
排除了上述可能,还有可能是什么原因呢?最终定位了问题,我的接口在访问远程接口时是采用多线程并发的方式访问的,使用了 spring 封装的线程池 org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor
在正常情况下,依赖的后端接口返回时间大约是 100 毫秒,而线程池 corePoolSize 设置为 20,可以承受单机 200QPS 左右,而日常单机 QPS 仅在 20 到 30,因此服务能力绰绰有余
活动当天,午高峰时段,由于访问量暴增,依赖的后端接口超时显著上升,达到了 300 毫秒左右,单机可以承受 60QPS 左右,而当时 QPS 在 50 左右,服务能力刚好可以承受
晚高峰时,依赖的后端接口超时进一步上升,达到了 500 毫秒左右,由此单机仅能承受 40 QPS,而当时单机 QPS 已超过 80,由于线程繁忙,任务被缓存在线程池的任务队列中等待,因此等待时间达到了 1.5 秒到 2.5 秒,造成了大量超时的情况