现象描述:
服务早高峰时大量接口耗时激增最慢时达到20-30秒响应。且并非个别接口,而是所有接口都有超时现象,最终排除了机器与代码逻辑的问题,修改了springBoot内置tomcat的配置使现象好转。
经后续排查。最开始只有主页接口有超时现象,随后的两分钟所有的接口都产生了超时现象。
排查:
一.查看超时接口的代码,有逻辑复杂的也有逻辑简单的纯内存操作的,理论上不可能同时出现超时。查看了接口内方法的耗时,都在几毫秒。
- 接口耗时日志通过过滤器进行打印。显示耗时为10秒-30秒。
- 通过skywalking查看接口内部方法的耗时,都是简单的redis操作,耗时为几毫秒,但是最终的接口耗时达到28秒。
- 相同的接口在相同的时间有超时的有不超时的,且每个不同的接口都有这种现象。
二.综上所述排除了接口本身的问题,把排查目标转移到jvm和机器cpu,内存上
- 机器cpu:正常
- 机器内存:正常
- 网络请求数:为突然增多
解决:
一. 基本确定是由于突然增大的流量导致的,此时想到应该是springBoot内置的tomcat容器配置问题导致的
- 但是请求数增多为什么会导致接口响应时长变长?查看了springBoot项目的tomcat配置没有配置,所以使用的是默认配置。
- 查看springqBoot tomcat配置类:ServerProperties.Tomcat.maxThreads 默认配置为200个线程,即服务的线程超过200个时会进行等待。
- 超时的时间段是流量高峰,有一个外部接口的调用时长较高,平均响应时长在15秒以上,导致tomcat线程池中的线程无法释放,新来的请求就会等待,1分钟后外部接口熔断现象自动好转了。
结论:
- 早高峰时由于运营推送短信,造成较多用户同时访问主页接口,主页接口内通过http调用了一个第三方提供的接口,该接口响应非常慢,再该时间段平均响应时长在15秒左右。导致了tomcat中有大量的活跃线程无法释放。
- 在流量高峰期我们的服务cpu与内存都属于健康状态,说明服务器性能并没有瓶颈,接口响应慢是因为新的请求在等待tomcat线程池中的线程释放。适当增加tomcat线程池maxThreads的数量便可在不影响服务器性能的情况下减少接口响应时间,即让单机可并行处理更多请求。
- 查看了高峰期单机的活跃线程数为500个左右,远大于了tomcat默认的200个,所以将maxThreads设置为600
- 当然影响本次故障的主要原因并不是最大线程数问题,正常情况下200个线程是足够的,主要原因为我们的服务调用的第三方接口响应太慢,没有及时熔断引起了雪崩效应,如果用户请求不断增多,第三方接口一直阻塞。那么无论maxThreads是多少都会被打满,只有解决第三方接口响应慢才能根本的解决问题,方法有:
- 找第三方接口的开发人员沟通让他们降低自己接口响应时间(显然不可能)
那么就只能从自身做改变了:
- 熔断平均耗时较高的第三方接口,并设计降级方案
- 根据经验设置请求三方接口的超时时间,不要无限等待
- 对自己服务的接口进行限流
application.yml文件中增加如下配置
server:
port: 8080
tomcat:
max-threads: 600 #默认为200 我的机器是4核8g,根据压测结果设置为600