记一次基于Docker的性能测试
- 2019 年 12 月 12 日
- 笔记
来源:http://www.ltesting.net
一句话结论
对于跑在单核CPU上的运算类API, 根据业务需求(最大响应时间)来调试找到最大线程数,然后依据线程数调试出heap大小(主要看年老代的回收次数)
若有理解不到位之处,请在评论区留言,跪谢!
背景
断断续续忙碌了几个月,终于自己写的开源项目算是有了雏形,打包成Docker image发布到AWS EC2后,写代码算是告一段落。随之而来的问题就是“我的项目能够支撑多少QPS” ,由于用了Docker, 即变成了“我的项目基于Docker的配置能够支撑多少QPS”, 更进一步细化这个问题的话,有以下几点:
- 因为我用了IaaS来创建Linux服务器(选用了Ubuntu)基本配置为 1G RAM 1CPU (2.5GHz)10G+ 硬盘空间(非SSD)
- 当然我并不希望一个Docker container就把上述资源全部占用掉。另一个原因是目前IaaS所提供的内存最小单元是500M,算上系统其他进程的开销,可供一个Docker image 的最大内存资源我定在了400M
说句题外话,我认为按照服务商提供的最小单元来划分的好处在于:减少开销。500M的费用只有1G的一半,而且将来项目动态伸缩的灵活度高,粒度更小。
- 项目是一个OAuth2的Spring boot实现,本身对于IO的要求不高、都是短链接。因为要生成JWT令牌,主要压力在CPU。用了内置的Tomcat,多线程在一个CPU上跑,请求数目一多,99%使用率简直是家常便饭
第一步:确定性能测试的指标(benchmark)
俗话说的好, 抛开业务需求来谈IT就是耍流氓。
项目是开源项目,业务需求那就只好我自己定了,一般来说我们并不希望用户登录过快(并且并发登录的情况虽然有但是确实比较少见),这次的api (oauth/token) 我定在了2秒的最大值,以此为基础来找出性能瓶颈。
第二步:确定可调参数
那么在不改动项目代码的前提下,可以调整哪些参数来提升性能的呢?
- JVM 相关参数,例如 GC、Heap、Thread stack
- Tomcat 相关参数,例如 max-threads、max-connections、accept-count
对于计算为主的项目,主要关注点还是在max-threads,设置合理的话可以减少CPU上下文切换带来的性能开销,以及合适的Heap大小来避免频繁触发GC所造成性能抖动。
第三步:开测 (多图预警)
虽然标题是基于Docker的性能测试,但是我还是想对比一下用与不用Docker上的性能差异,所以测试会分为两个部分, 以下为jre的基本信息
ubuntu@ip-xxx-xx-xx-xxx:~$ java -version openjdk version "11.0.4" 2019-07-16 OpenJDK Runtime Environment (build 11.0.4+11-post-Ubuntu-1ubuntu218.04.3) OpenJDK 64-Bit Server VM (build 11.0.4+11-post-Ubuntu-1ubuntu218.04.3, mixed mode, sharing)复制代码
ubuntu jre 信息
/ # java -version openjdk version "11" 2018-09-25 OpenJDK Runtime Environment 18.9 (build 11+28) OpenJDK 64-Bit Server VM 18.9 (build 11+28, mixed mode)复制代码
docker jre 信息
3.1 无Docker下的性能测试
3.1.1 Heap 固定,不同线程数关系图





50m Heap大小在100个线程的情况下OOM,所以这里为0
3.1.2 线程数固定,不同Heap大小下关系图




3.2 基于Docker的性能测试
直接上对比图

上图为不限制Docker 容器大小的结果

上图限制了Docker 容器大小为450M
3.3 垃圾回收次数(1000QPS)


上图100 threads 50m Heap 的时候程序直接崩溃了所以为0
第四步:分析
4.1 Docker vs 非 docker
很明显,Docker会带来一定的性能开销,并且随着线程数的增加与QPS的增加,这种开销会更加明显。但是并不是说Docker不好,毕竟性能开销只要多开一个节点就搞定,和Docker带来的便利性相比,几乎可以无视。
4.2 线程数 与 JVM heap
这里的讨论仅限于单核CPU负载较高的运算类API,Serial GC
- 虽然线程数越多吞吐量越高,但是响应时间会更快的增长
- Heap过小会导致频繁的垃圾回收(年轻代影响较小,年老代最为突出)甚至会OOM导致程序崩溃
- Heap过小时,线程数越大,年老代的回收次数显著增多,年轻代反而会降低(年老代回收为主力)
- Heap过大并不会带来性能提升,但是年轻代回收次数会显著减少,而年老代几乎不受影响
4.3 一句话结论
对于跑在单核CPU上的运算类API, 根据业务需求(最大响应时间)来调试找到最大线程数,然后依据线程数调试出heap大小(主要看年老代的回收次数)
4.4 回到我的开源项目
很简单,10 threads 100m heap
作者:冰箱没有油 链接:https://juejin.im/post/5d4cd38cf265da03b120394c 来源:掘金 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
星云测试
http://www.teststars.cc
奇林软件
http://www.kylinpet.com
联合通测
http://www.quicktesting.net