考试压测及瓶颈排查
引入
对整个考试系统再次进行压测,并给出排查瓶颈以及不断优化的过程
可能影响性能因素
- 代码(设计缓存是否命中)
- exam pod数量,pod的Xmx
- gateway 、usercenter 数量
- redis
- mysql
- 索引
- 本地网速
最简单查看是否是瓶颈的方式:cpu利用率
压测参数
人数x=6k~10k
warm-up=100s
题目延时5~195s,平均delay = 100s
只测exam 1pod 1核1G,并对比两次优化前后的提升
QPS:
- 进入峰值QPS = 在进入考试warm结尾:x/warm * 3(notices\startExam\getExamInfo) + x/delay = 40QPS / 1k人
- 稳定QPS = x/delay = 10QPS / 1k人
2K人
- 进入考试exam 40%利用率,mysql20%利用率 平稳后降到一半
- 交卷时exam突然崩溃,内存在考试阶段一直在上升,怀疑有内存泄漏?
内存泄露排查
慢慢给请求,老年代占用率一直上升
观察
- 修改dockerfile为jdk
- 使用arthas分析查看,发现当内存过高时,GC开始活动占用大量CPU
不停慢慢压测,老年代一直上升到极限 为什么?理论上没有对象一直被引用
一段时间后自动下降(后来推断原因:session过期)
再压测
定位
输出占用高的对象 jmap -histo:live pid | head -20
1 |
|
jmap -dump:live,format=b,file=heapdump.hprof pid
dumpMAT定位为org.apache.catalina.session.StandardManager
1
2
3
4
5
6One instance of "org.apache.catalina.session.StandardManager" loaded by "org.springframework.boot.loader.LaunchedURLClassLoader @ 0xe0620e30" occupies 306,798,192 (76.02%) bytes. The memory is accumulated in one instance of "java.util.concurrent.ConcurrentHashMap$Node[]" loaded by "<system class loader>".
Keywords
java.util.concurrent.ConcurrentHashMap$Node[]
org.springframework.boot.loader.LaunchedURLClassLoader @ 0xe0620e30
org.apache.catalina.session.StandardManager查看http返回确实返回了JSESSIONID,此外本地debug打开security日志也可也看到
1
2
3
4
5
6
7
8logging:
level:
com.student.exam.mapper: debug
org:
springframework:
security: DEBUG
o.s.s.w.c.HttpSessionSecurityContextRepository 91 : SecurityContext 'org.springframework.security.core.context.SecurityContextImpl@ae3cc182: Authentication: org.springframework.security.oauth2.provider.OAuth2Authentication@ae3cc182: Principal: 51255903044; Credentials: [PROTECTED]; Authenticated: true; Details: remoteAddress=127.0.0.1, tokenType=BearertokenValue=<TOKEN>; Granted Authorities: ROLE_student' stored to HttpSession: 'org.apache.catalina.session.StandardSessionFacade@72a3d742修改EXAM下 ResourceServerConfig:session策略(登录使用JWT方式,整体微服务应该都需要满足无状态的)
1
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
参考:一次压测中tomcat生成session释放不及时导致的频繁fullgc性能优化案例 - Agoly - 博客园 (cnblogs.com)
优化后无内存持续上升问题,内存泄漏解决。
6~8k
整体能够运行,但rt较高
mysql直接打满(上次压测已经发现,gateway在每一个接口都会去根据用户id拿用户的详情信息,导致mysql打满),符合预期
如果8k人直接系统rt爆炸
优化:将JWT在鉴权后用户id转化为用户信息的查询使用本地缓存(guava)
10k (缓存+MQ)
P95 130MS
exam pod
Mysql(整体几乎平稳,因为代码基本上只操作数据库,但注意用户信息是缓存了,如果缓存刚好集体失效会有一个小峰值)
usercenter 3pod
gateway 5pod
结论
- 在强行不使用session后,系统不再OOM,恢复正常
- 对查询用户信息缓存后,mysql不再是瓶颈,整体系统并发大幅度上升
- 如果想增加系统的并发,扩展机器即可
- 本次压测是在本地个人机器上,使用jmeter命令行进行,可能会受到本地带宽、性能影响;标准做法应该使用专门的云服务器进行压测