有奖:语音产品征文挑战赛火热进行中> HOT
文档中心 > 腾讯云可观测平台 > 云压测 > 最佳实践 > 使用 Prometheus 观测性能压测指标
性能压测是一个充满挑战的领域,性能评估和优化贯穿开发、测试、部署、上线等各个阶段,直接影响系统运行效率和用户使用体验。本文将为您介绍在压测过程中 Prometheus 存储指标,并使用 Grafana 将指标可视化。通过观测指标的动态变化,发现系统瓶颈。

性能压测可观测

可观测体系主要包含3类指标:Metrics、Logs、Traces。三者既可独立工作,也可相辅相成,推导出系统整体的状况。
Metrics:是一种聚合的度量数值,能够量化系统各个维度指标,常用于提供系统全局视图,一般包括 Counter、Gauge、Histogram 等指标类型。
Logs:应用程序运行过程中产生的日志或者事件,提供系统运行的上下文信息,例如:某个变量值、发生错误详情等。
Traces:提供请求从发送到完成响应整个链路。在分布式系统中,一个请求完成需要经过多个服务,Trace 提供请求在链路各个环节的响应时间、响应体、是否报错等。通过 Trace 更方便分析出请求中的异常环节。

图片



指标概述

Counter:只增不减的计数器

Counter 是一种累积度量指标,用于表示一个只能增加的值,如果重置系统或服务,Counter 可能会从0开始重新计数。Counter 最常见的用途是计数器,用于记录发生的事件数量,例如请求的数量、完成的任务数、错误的数量等。例如 Counter 类型指标:http_requests_total,用于记录请求次数。
通过 rate()函数获取请求 QPS:
rate(http_requests_total[5m])
查询系统访问量前10的 http 请求:
topk(10, http_requests_total)

Gauge:有增有减的度量衡

Gauge 与 Counter 不同,Counter 用来反映事件发生次数,而 Gauge 用来反映系统当前的状态,例如当前的温度、服务器 CPU/内存使用率、剩余可用内存等。例如:通过 Gauge 指标,查看节点剩余可用内存:
# HELP node_memory_MemAvailable_bytes Memory information field MemAvailable_bytes.
# TYPE node_memory_MemAvailable_bytes gauge
node_memory_MemAvailable_bytes
查看剩余可用内存比例(这个语句通常可用来设置警报,当剩余可用内存低于某个阈值时进行通知,这样您就可以采取行动避免系统出现内存不足的情况):
(node_memory_MemFree_bytes/node_memory_MemTotal_bytes)*100

Histogram/Summary:分析数据分布

Histogram 和 Summary 主要用于统计和分析样本的分布情况。
以 Histogram 为例,通常使用 histogram_quantile 函数计算百分位数。例如,要计算请求响应时间的第90百分位数:
histogram_quantile(0.9, rate(http_response_duration_seconds_bucket[5m]))
这个查询会返回过去5分钟内所有记录的请求持续时间的第90百分位数。通过这种方式,Histogram 为您提供了强大的工具来监控和理解您的系统性能。

设计观测指标

可以通过性能压测暴露系统瓶颈,通过选择合适可观测工具、设计科学的指标监控,根据指标变化来帮助您定位系统瓶颈。

核心指标

压测过程中,从施压方看主要需要关注以下核心指标:
请求响应时间:包括平均响应时间、响应时间百分比水位。
请求 RPS
请求成功率,失败率。
请求错误原因
压测并发数
检查点成功数,失败数。
请求发送接收字节数
施压机内存/CPU 使用率等

指标维度

每个指标最好能够区分不同的维度,例如:
1. 按返回码统计不同请求的 QPS,例如返回码为200的请求的 QPS 是多少,返回码为500的请求的 QPS 是多少?
2. 统计发往不同服务的请求的 QPS,例如压测 www.test1.comwww.ok1.com 的请求的 QPS 分别是多少?
以 http 请求为例,常见的维度划分如下:
job:压测任务标识,每一次压测都是一个不同的 job。
method:请求方法,例如 GET、POST、HEAD 等。
proto:请求协议,例如 http、https、http2。
service:请求地址,例如 https://www.test1.com
status:请求响应码,例如200、404、500等。
result:标识请求响应码,例如200或者其他小于400对应 OK,404对应 Not Found,500对应 Internal Error 。
check:检查点/断言名字,一般用于简单描述该断言的作用。

指标设计

基于此我们设计了一套最基本、常用的指标体系,能够覆盖绝大部分用户的使用需求,详情请参见下表。您也可以基于如下指标体系进行拓展,以满足不同的需求。
Metric
Type
Labels
Description
req_total
Counter
job,method, proto,service, status, result
请求次数
req_duration_seconds
Histogram
job,method, proto,service, status, result
请求耗时
checks_total
Counter
job, check, result
检查点
send_bytes_total
Counter
job,method, proto,service, status, result
发送字节数
receive_bytes_total
Counter
job,method, proto,service, status, result
接收字节数
num_vus
Gauge
job
并发数,可用于指代虚拟用户数量。如果是 JMeter压测,也可用于指代线程数

示例

查看实时的并发用户数:
sum(num_vus{job=~"$job"})
查看请求的 QPS:
# 查看不同请求的qps
sum(rate(req_total{job=~"$job"}[1m])) by (service)
# 查看成功请求的qps
sum(rate(req_total{job=~"$job",result="ok"}[1m]))
# 查看指定http://www.test1.com服务的qps
sum(rate(req_total{job=~"$job",service="http://www.test1.com"}[1m]))
查看请求失败率:
# 请求总体失败率
sum(rate(req_total{job=~"$job",result!="ok"}[1m]))/sum(rate(req_total{job=~"$job"}[1m]))
# 基于请求维度,查看各请求的失败率
sum(rate(req_total{job=~"$job",result!="ok"}[1m])) by (service)/sum(rate(req_total{job=~"$job"}[1m])) by (service)
查询请求响应时间:
# 查询请求平均响应时间
sum(rate(req_duration_seconds_sum{job=~"$job"}[15s]))/sum(rate(req_duration_seconds_count{job=~"$job"}[15s]))
# 查询请求中位数(50百分位)响应时间
histogram_quantile(0.50, sum(rate(req_duration_seconds_bucket{job=~"$job"}[1m])) by (le))
# 查询请求90百分位响应时间
histogram_quantile(0.90, sum(rate(req_duration_seconds_bucket{job=~"$job"}[1m])) by (le))
查询请求出入带宽:
# 请求出带宽汇总
sum(rate(send_bytes_total{job=~"$job",region=~"$region"}[1m]))
# 请求入带宽汇总
sum(rate(pts_engine_receive_bytes_total{job=~"$job",region=~"$region"}[1m]))
检查点成功率(用户自定义的 test 语句,在JMeter 中对应断言):
# 检查点成功率
sum(rate(checks_total{job=~"$job", result="ok"}[1m]))/sum(rate(checks_total{job=~"$job"}[1m]))
# 指定检查点成功率
sum(rate(checks_total{job=~"$job", result="ok",check="response contains hello"}[1m]))/sum(rate(checks_total{job=~"$job", check="response contains hello"}[1m]))
说明:
用户也可以基于以上 demo 进行灵活扩充,对被压测服务进行同样的监控。在压测过程中,对比查看压测平台生成的指标报告与用户服务的指标报告,综合分析排查问题。
使用 Prometheus 存储以上指标,使用查询语句在 Prometheus 中查询数据,最后通过 Grafana 可视化展示以上数据。一边压测,一边实时观测服务性能指标变化。

操作步骤

2. 在左侧菜单栏中单击云压测 > 测试场景
3. 在测试场景页面单击新建场景。
4. 在创建测试场景页面选择“JMeter”压测类型,并单击开始,创建压测场景。

上传 jmx 脚本

必选:上传 jmx 脚本
可选:
上传 Jar 包:如果您的脚本中使用了 JMeter 三方插件,您可以上传对应 jar 包,来拓展 JMeter 功能。
上传 properties 文件:在原生 jmeter.properties 文件基础上,自定义 JMeter 属性。
csv 文件:在 Jmeter 中读取 csv 文件中的数据,作为变量在脚本中引用。
其他文件:任何在 jmx 中脚本引用的其他文件

image.png



将报告导出到腾讯云 Prometheus

高级配置 > 压测指标导出 > 腾讯云 Prometheus 托管集群中,点击添加配置, 选择您的实例:

image.png


如果您在该地域没有实例,您也可以点击新建

运行压测脚本

点击保存并运行即可开始压测。

image.png



查看实时报告

您可以选择不同的页签,查看不同维度的报告详情。

image.png



在 Prometheus 中查看压测报告

在压测过程中,指标会同步发送到腾讯云 Prometheus 中。您也可以在 Prometheus 中查询指标信息,自定义查询语句。
1. 登录 Prometheus 控制台,在搜索栏根据实例名称找到您的 Prometheus 实例。

image.png


2. 单击实例 ID,进入实例详情。 如果您的 Prometheus 实例没有对应的 Grafana,可以点击绑定 Grafana。通过 Grafana 来展示 Prometheus 指标。

image.png


3. 选择数据采集 >集成中心,搜索云压测 PTS 应用,在 Dashboard 操作中,点击 Dashboard 安装/升级, 将云压测监控面板安装到 Prometheus 绑定的 Grafana 上。



4. 在 Grafana 中查看压测报告,登录 Prometheus 绑定的 Grafana 页面。

image.png


5. 搜索 PTS,查看云压测压测报告。

image.png


6. 点击 PTS 任务详情,查看报告详情。

image.png



image.png

image.png



压测时如何评估系统瓶颈

在压测时,主要关注系统吞吐量(RPS,网络带宽)、响应时间、并发用户数等。公式如下:
RPS = VU(并发数)/ 平均响应时间

如何理解压测公式?

以一个线程循环去执行某个请求为例:如果请求平均响应时间是10ms,那么一个并发每秒可执行100个请求,对应的 RPS = 100req/s。
从这个公式可以推导,如果想提升压测的总体 RPS,有以下几种方法:
增加并发数,且请求平均响应时间保持不变。 这种情况就是被压服务还没有饱和,压测 RPS 随着并发压力的增加而增加。
降低请求平均响应时间, VU 保持不变。 这种情况比较理想,请求平均响应时间降低,代表被压服务进行了优化,单个 VU 单位时间内能够发送更多的请求。
在现实压测中,很可能随着 VU 增加,被压系统压力增加,响应时间也随之增加。
如果响应时间增加系数小于 VU 增加系数,总体 RPS 还是在变大,系统还未达到瓶颈。
如果响应时间增加系数大于 VU 增加系数,压测的表现就是随着 VU 增大,总体 RPS 反而降低,此时系统已经达到瓶颈。

评估系统性能拐点

压测就是在压力不断增加情况下,找到业务系统扩展性的拐点,即系统瓶颈/最大容量。
在一定的阶段,我们观测到扩展性是线性变化的。到达某一点时,此时对于资源的争夺开始影响性能。这一点也可以认为是系统拐点。作为曲线分界,过了拐点,整体的吞吐量会随着资源争夺加剧偏离线性扩展。最终,资源争夺的开销反而导致完成的请求数变少,吞吐量反而下降。

image.png

这种情况可能在系统负载到达 100% 使用率(饱和点)之后发生,也可能在接近100% 使用率的时候,这个时候排队比较明显。
例如:有一个计算密集型系统,在更多请求进来时候,需要更多的线程来执行请求。当CPU使用率接近100%时,由于CPU调度延时增加,性能开始下降。在性能达到峰值后,整体吞吐量反而会随着更多线程加入而下降。线程加入会导致更多上下文切换,消耗CPU资源,实际完成的任务反而变少。
性能的非线性变化,我们也可以通过响应时间的变化来看出来:

image.png


性能下降的原因非常多,除了上面提到的频繁上下文切换外,还有如下原因:
系统内存不够,开始频繁的换页(swap)来补充内存。
随着系统磁盘 IO 增加,磁盘 IO 可能进入缓冲排队。
系统内部实现队列算法,来进行削峰操作,导致请求处理等待时间变长。