概述
最近公司在某个银行项目POC的时候,需要压测某个接口,这个接口用来接入行内所有业务场景的流水,所以对tps的要求非常高,但是在我们用jmeter做压测的过程中,发现tps一直上不去,如下图所示,可以看到tps一直在1w7左右,那么究竟是什么原因导致的呢,让我们来一探究竟吧。
排查思路
1.首先通过jsatck命令行工具查看应用的线程,发现了存在着大量的blocked线程。
jstack pid
2.查看具体的blocked线程,可以看到堆栈信息,如下图所示:
原因分析
分析堆栈信息,发现调用GenericScope的get方法时,最后会调用到ConcurrentHashMap的putIfAbsent()方法,而ConcurrentHashMap是一个并发容器,会存在资源竞争,特别是在并发度非常非常高的情况下,竞争就会比较大,导致最终一些线程出现阻塞的情况,从而影响了性能。 性能问题。
而GenericScope是由于@RefreshScope导致的,@RefreshScope主要是用来实现配置的自动刷新,而这个注解引入的时候,会发生调用GenericScope的get方法,具体的源码解析可以参考这篇源码分析的文章:一文带你理解@RefreshScope注解实现动态刷新原理
解决办法
- 去掉了@RefreshScope这个注解。
- 改读取配置通过采用@ConfigurationProperties这个注解。 最终tps提升到了4.4w。
总结
该性能瓶颈一般出现在超高并发的场景下,一般生产不会出现压测这么高的并发,所以大部分的场景使用RefreshScope都是没有问题的。
但是,还是建议大家读取配置尽量都优先使用@ConfigurationProperties这个注解。