需求背景
此次压测的IOT平台是基于k8s+docker搭建的,应平台规划后续需支撑千万级用户和设备。故此次对平台进行性能测试、评估及调优,确保平台在预期用户量和设备量下的稳定运行。(目前此平台已稳定支撑千万级用户运行2年,每日流量亿级)
业务特点
采用云原生k8s+docker技术,微服务架构,引用了redis,es,rocketmq等多个中间件,用户或设备的业务模型非常复杂,涉及多个重要接口,且接口的请求链路很长。
用户模型
数据模型
因现网参考数据较少,与业务方沟通,采用如下计算公式估算预期TPS:
接口TPS=((活跃用户数)(或设备数)*每天单用户(或单设备)调用次数)/高峰时段时长(单位:秒)
高峰时段:7-9时、18时-20时,共计4小时,即14400s。
各接口请求链路
压测链路
压测端使用jmeter分布式压测,被测端使用k8s集群容器化部署,业务上述的链路如下图,实际中间件和第三方服务不止列举的这些,压测环境下,第三方厂商和直连平台接口使用mock(固定响应实际50ms)接口代替。
机器环境
需求要求IOT平台满足500W用户,300W智能设备。基于k8s集群的伸缩性和机器成本的考虑,我们只需在测试环境部署一套最小可测集群(即满足业务全链路请求的最小部署单元),后续通过此最小集群的性能能力水平扩展至满足性能要求的集群大小即可。
初始压测结果
调优过程
1.机器环境调优
参考《性能基线配置参考V1.0》(公司内部文档,可以让运维帮忙操作),进行机器环境调优
2.网络因素排查
压测过程使用脚本判断TCP建立连接时间,业务耗时时间,结束时间(使用shell脚本,for循环模拟单线程一直执行curl命令即可),发现响应时间和jmeter一致,且TCP建立时间短。说明压测端没有问题。
压测过程通过pingIP查看网络延迟,发现问题:使用的云主机发现网络延迟问题
最终通过云主机提供团队迁移虚机解决。
部署单位调整
机器环境和网络因素排查后,重新压测。(此时入口组件app-rest单pod)
调整入口组件app-rest的pod数为2个,重新压测,结果如下:
发现部分接口的请求耗时偏长
耗时长原因定位
定位链路
通过直接压测pod和通过ingress压测两种方式对比(须先将压测端加入到k8s集群内部), 发现问题:ingress的tps瓶颈有限制, 解决:更改ingress版本至0.24.1
链路定位方法: 进入pod内部:kubectl exec -it PODNAME -n NAMESPACE bash 用tcpdump抓包,在用wireshark展示
使用基准项目(通过一个pod部署一个压测基准项目)调优JVM参数
诊断java应用方法
使用JAVA应用诊断工具MyPerf4J(有兴趣的同学可查看博主《k8s集成MyPerf4J》文章,目前更推荐阿里开源无侵入式Arthas工具)
查看JVM是否异常(以下先通过基准容器调整):
初始压测结果:4500TPS:
线程:
打印堆栈
发现发生在controller层,属于正常
再查看gc,发现YGC次数过于频繁:
YGC次数 、 YGC时间 、 平均单词YGC时间 、 FGC次数 、 FGC时间
因为使用的是ParNew+CMS垃圾回收器,改年轻代大小(不设置-Xmn默认是64m)
| -Xmn | 年轻代大小 | 此处大小=(eden + 2 survivor space)。官方推荐配置为整个堆的3/8 |
|---|
再调整垃圾回收线程数 (建议和核数一样)
| -XX:ParallelGCThreads=8 |
|---|
调整后效果
基准项目通过此次jvm调优,性能从4500 提升至1W1 tps
优化后结果
调优后,重新进行压测IOT平台,效果如下,基本所有接口均满足500W用户性能要求的一半,故现网部署两倍的最小集群即可。
其他问题
调优过程中发现物理和容器化压测结果不一致,物理部署的还低于容器化部署的性能。
最终发现默认eth0的mtu是1500 容器网络的mtu 是1440 此现象导致了直接通过eth0 tps7000上不去
容器隧道:
eth0: