记录一次分析Java程序对cpu和内存的使用量并将其压缩到可以提供正常服务程度的过程
1. 准备工作
-
jmeter:对接口进行压测
-
Windows版的JDK工具:实时观测Java程序的堆内存及堆外内存的使用量
-
服务器中的docker:docker stats命令可以观察服务的cpu使用情况
2. 思考及心路历程
-
对于cpu和内存的使用,更应该关心的是在生产环境中,程序实际对这些资源的使用量,以及某些可能出现的极端情况,所以类似高强度的压测是可以直接pass掉的。
-
在分析程序对资源的使用量前,首先应该做的是分析这个程序的接口访问量是多少,然后再针对最主要、调用最频繁的接口编写jmeter测试用例,对接口的调用量不应该比实际的接口访问量高出太多,比如实际的访问量可能在每秒100以内,那就不要测到每秒几千的程度,对分析的结果没有实际意义。
-
其次,需要了解程序的底层特性,比如Java程序对内存的申请和使用,程序会先申请一部分内存,但不一定会全部使用,实际在用的也就是堆内存和堆外内存,top、docker stats等等相关可以看到进程对内存使用量的命令,但其实显示的数据会和程序实际的使用量有出入,所以我们需要使用到JDK提供的工具jconsole将堆内存和堆外内存获取到再进行计算,从而得出程序对内存的使用量。
-
相对于内存,cpu的观察方法会更加直接,如果是镜像就使用docker的官方命令stats,如果是直接跑在服务器里的程序,就使用top实时观察进程对cpu的使用量百分比即可。
3. 大量测试与观察数据
举个例子,一个程序部署在k8s中(目前我做的项目是打成docker镜像,部署在k8s中运行的,k8s中部署资源是可以限制内存及cpu资源的),有一到两个经常使用的接口,调用的频率分别是每秒100次、每秒150次。
- 上面已经分析了接口调用的频率,我们就应该从实际出发,先不要对内存和cpu做限制,或者做一个较大的限制,然后使用jconsole连接到该程序,找到该程序的镜像并使用docker stats实时监控其对cpu的使用。
- 在jmeter中创建测试用例,给这两个接口发送请求,发送的频率从每秒10、20…阶梯测试,观察cpu、堆内存和堆外内存的变化,并且多测试几次,找一个相对稳定的值进行记录,并且建议多换几个环境进行观察。(建议测试到接口频率的两倍以上,留出容错的空间,但不要让测试的频率高的太离谱,毕竟不是测试的压测,没必要太狠,太狠了对压缩资源时所依靠的数据没什么作用)
- 将这些数据汇总、整理,找出比调用频率高一倍时的数据,例如:找出的数据是,每秒给两个接口发送请求分别300次时,cpu的使用率为190%,堆内存使用300m,堆外内存无论请求多少次都稳定在120m左右,那我们就可以大概得出,在满足正常使用并稍微有容错的情况下,cpu使用了1.9核,内存使用了420m,将数据向上取整,cpu取2核,内存取1G(因为Java程序是需要分配堆内存大小的,我们在设置时,将-Xmx的设置为600m、800m都可以,只要比实际使用的堆内存大得多并且给堆外内存留出可以伸缩的空间即可),这就是我们评估出的提供正常服务程度的资源使用量。
4. 真实环境观察
- 多找几个模拟的生产环境,或者已经部署好的系统测试环境(当然这个是目前我做的项目中最接近生产环境的环境,了解我的意思就行,适当的可以找测试同事协助测试一下修改后正常使用是否会出现类似OOM的情况,或cpu不够的情况),将评估出的资源量修改进去,打开docker stats和jconsole,进行较长时间的观察
5. 总结
- 评估cpu、内存这些可以直接影响程序运行的使用量时要慎重,应该使用最接近生产环境甚至超出生产环境一点的数据进行大量的测试,需要有更稳定、更精确的参考数据才可以做出评估,其实压缩资源这个事情本身就是不太合理的,想让马儿跑,还不给马儿吃草,向内压缩的事情还是不建议的,根据实际情况判断吧!
6.鸡汤送上
每天多一点点的努力,不为别的,只为了日后能够多一些选择,选择云卷云舒的小日子,选择自己说了算的生活,选择自己喜欢的人。
最后说明:
创作不易,若转载请标明出处或原文链接!!!