性能压测与调优

        性能压测是当服务上线前,或者之后重要需求发布流程中,需要做的必要测试;以模拟真实流量的方式,获取当前系统的性能指标、是否存着高并发隐患、瓶颈等信息的手段。

性能压测处于什么位置?或者说什么时候去做呢?如何做?

如何做好线上环境的性能压测、全链路压测,如何做到压测结果准确无误,不影响外部环境、不污染数据,需要深入思考。

一、测试分类

按照上线流程:

    单元测试

    集成测试

    兼容性测试(前端、客户端)

    性能测试

运维阶段:

    安全测试

    容灾测试(故障恢复测试)

由上可以看出,性能测试是应用服务在上线过程中的一个流程,除非是内部系统,访问量少,否则都应当做一下性能测试。

安全测试又叫渗透测试,是运维和研发需要关注的问题;尤其是对数据安全要求高的系统。当一个服务稳定运行后,模拟一些攻击手段,防止SQL注入、网络攻击、脚本攻击等。

容灾测试是容灾方式的验证,容灾方式包括:双机房建设、异地多活、两地三中心。

二、压测目的

    了解吞吐量

    瓶颈值

    系统隐患

可用:一次请求,到达服务器,有回应;那么针对这次请求,服务是可用的,无论返回成功或者失败。

不可用是指请求没有返回,长时间等待,没有应答,客户端不知道结果。

高可用级别:99%、99.9%、99.99%、99.999%

大家经常说的系统可用性达到三个9,就是指99.9%。

高可靠:是指服务可靠,数据可靠。请求返回是成功,数据写入正确,分布式环境下数据一致性等。

三、压测指标

压测指标

四、实现流程

1. 压测工具选型

   Jmeter + Influxdb + Grafana + Collectd


2.压测环境准备

    服务环境

    压测机

    数据库

    Redis

    MQ


3.压测数据准备

    日活数据:数据要真实、流量真实,结果才能越接近线上真实性能指标。

    数据隔离:防止污染真实用户数据

    数据恢复

    热点数据

    压测预热:尽量模拟线上真实环境情况,如缓存命中率


4.压测开发设计

    挡板

    Mock数据

    流量识别

    压测场景

    加压策略

挡板:是用来拦截调用第三方的请求,防止压测对第三方造成影响;提前设计好挡板逻辑,识别压测流量,执行挡板逻辑,并且为了真实,还可以合理延迟一定时间再返回Mock数据。

流量识别:nginx做负载均衡,upstream 转发服务器ip 时,可以获取http请求Header的参数,我们可以给压测流量header加标记参数,nginx获取参数判断后,转发压测流量到压测机器。


5.监控

监控很重要,可以说是压测中最为重要的地方,如果没有监控,或者监控不准确,会严重影响压测本身准确性。监控数据不详细,也会影响性能调优。

一般我们需要监控的如下:

    CPU、内存

    IO:网络、磁盘

    Http请求、接口方法

    JVM

    中间件

    数据库负载

    带宽占用

其中对接口和方法的监控需要有,而且要准确,是定位性能问题的有效手段,越细化越好。

以下是一些监控工具: 

Grafana 监控 (CPU、内存、成功率、http请求的RT)
Sentinel 监控 (接口、方法级别)
Visualvm 监控JVM

通过上图可以直观的看出JVM堆内存的增长情况和GC回收频率、回收后内存大小。如果回收后的内存在持续增高,且当前请求没有增长,说明有内存泄露,具体什么对象泄漏,需要通过jmap等命令,查看堆内存heap的详情。

JVM详情查看命令

对比GC前后的对象数量,分析是哪些没有回收。


五、性能优化

注意:

慎重优化,谨记二八原则 和 Amdahl定律。

优化一定要伴随着压测,通过性能指标、数据对比来论证和调整,否则没有意义。


1.优化目标

       提升吞吐量

        降低 RT

2.优化方向

        硬件层面:CPU、内存扩容、换SSD固态硬盘

        软件层面:集群扩容、代码优化、存储优化(缓存、数据库)、减少IO

3.优化方式

        代码优化:请求合并、异步、Cache、池化

        JVM调优

        Linux调优


JVM调优

1. 调优关注点

        减少JVM不可用时间:STW(Stop the word)

        GC 频率

        安全点SafePoint

安全点是需要注意的问题,很多初学者会忽略安全点线程等待时间,其实STW时间包括安全点等待时间。

2. 常用GC回收器

    ParNew + CMS     (低延迟、低核、小内存场景)

    G1                         (高吞吐量、高核、大内存)

G1只有在多核CPU,大内存情况下,才能体现出它的优势,如果内存过小,表现反而不如ParNew+CMS。

那么到底多大算大内存呢?

根据R大给出的建议是:以堆内存8g为限,大于8g用G1,小于8g用CMS。

3. JVM参数分类

    -:标准参数,所有JVM都必须实现,且向后兼容。

    -X :非标准参数,默认JVM实现该参数,不保证向后兼容。

    -XX:非stable参数,不同JVM有所不同,将来可能会取消。

4. G1关键参数

    -Xms16g   -Xmx16g   

    -XX:+UseG1GC    -XX:MaxGCPauseMillis=50    -XX:InitiatingHeapOccupancyPercent=60   

    -verbose:gc    -Xloggc:logs/gc_%p.log    -XX:+DisableExplicitGC

    -XX:-UseLargePages  -XX:+PrintGCApplicationStoppedTime  -XX:-OmitStackTraceInFastThrow 

    -XX:+PrintSafepointStatistics  -XX:PrintSafepointStatisticsCount=1

需要注意的是,G1最好不要加新生代大小参数 -Xmn ,如果固定了新生代大小,G1就没法根据 -XX:MaxGCPauseMillis 设定的最大期望GC时间,动态调整堆内存的新生代和老年代大小,相当于-XX:MaxGCPauseMillis 失效了。除非你很熟悉G1原理,加了新生代大小,配合其他参数,也可以调优出一个不错的结果。否则还是交给G1本身的自动调整吧。

5. GC 日志

2020-01-09T11:05:34.836+0800: [GC pause (G1 Evacuation Pause) (young) ……

[Eden: 8576.0M(8576.0M)->0.0B(8576.0M) Survivors: 16.0M->16.0M Heap: 8643.7M(14.0G)->68.2M(14.0G)]

[Times: user=0.05 sys=0.04, real=0.02 secs]

2020-01-09T11:05:34.863+0800: 2043140.818: Total time for which application threads were stopped:0.0286394 seconds, Stopping threads took: 0.0002674 seconds

2020-01-09T12:01:10.488+0800: 2046476.443: Application time: 3335.6250688 seconds

2020-01-09T12:01:10.490+0800: 2046476.444: [GC pause (G1 Evacuation Pause) (young) 2046476.444:


gc日志中 Stopping threads took 就是安全点时,线程的等待时间,所以STW时间应该是:GC时间 + 安全点等待时间。

如果 Stopping threads took 较大,说明代码程序是有问题的,需要深入查看;

具体什么情况会导致安全点时间过长,请参考:

JVM安全点介绍

HBase实战:记一次Safepoint导致长时间STW的踩坑之旅


Linux调优

我在对业务项目、RocketMQ、Redis、codis集群、Elasticsearch、Hbase等进行优化过程中,经常遇到一些相同的问题,我总结了下,主要有以下:

慎用交换区swap

        优化方式:禁止swapping 或者设置 swappiness = 1

        swapping会导致gc过程从毫秒级变成分钟级

善用 /dev/shm/

       /dev/shm/ 是linux的文件内存系统,是共享内存,直接从物理内存中开辟,根据使用情况会动态扩容。

针对一些写入文件,IO性能要求高的场景,可以使用/dev/shm/,例如gc日志存放。

高并发场景下,如果打开安全点日志,安全点日志是在安全点内打印,是同步的,所以日志写入文件速度,会严重影响gc快慢;应当将gc日志配置改为:

-Xloggc:/dev/shm/gc_%p.log

其他linux调优,一般大点的公司,都会有自己的运维团队,运维就会做基本的优化,例如tcp连接优化等,这里只介绍运维可能忽略的,不知道的点,这时候就需要研发同学介入,找运维做好应用相关的Linux内核优化。

你可能感兴趣的:(性能压测与调优)