如何用Prometheus绘制指定API端点的单次请求耗时?
问题描述
我在Spring Boot的API路由上添加@Timed注解,想要在Prometheus中统计API端点的响应耗时,但遇到以下问题:
- 未调用
/ping或/pong接口时,http://localhost:8080/actuator/prometheus中看不到对应指标,只有调用至少一次后才会出现 - 执行PromQL查询(如
rate(http_server_requests_seconds_sum{uri="/ping"}[5m])/rate(http_server_requests_seconds_count{uri="/ping"}[5m])、http_server_requests_seconds_sum{uri="/ping"})时,返回Empty query result
相关代码与配置
RestController代码
import io.micrometer.core.annotation.Timed; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class MyController { @GetMapping("/ping") @Timed(value = "ping.request.time", description = "time pIng") public String ping(){ return "pIng"; } @GetMapping("/pong") @Timed(value = "pong.request.time", description = "time pOng") public String pong(){ return "pOng"; } }
Prometheus配置文件prometheus.yaml
global: scrape_interval: 15s # Default is every 1 minute. evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute. rule_files: # - "first_rules.yml" # - "second_rules.yml" # A scrape configuration containing exactly one endpoint to scrape: scrape_configs: - job_name: 'prometheus' static_configs: - targets: ['127.0.0.1:9090'] - job_name: 'spring-actuator' metrics_path: '/actuator/prometheus' scrape_interval: 5s static_configs: - targets: ['SYSTEM_IP_ADDRESS:8080'] # refer system ip address rather that localhost
Prometheus启动命令
docker run -d --name=prometheus -p 9090:9090 -v C:\Users\Admin\Desktop\prometheus-test\prometheus.yaml:/etc/prometheus/prometheus.yml prom/prometheus --config.file=/etc/prometheus/prometheus.yml
解决方案
1. 解决指标未调用不显示的问题
Micrometer默认采用懒加载机制,只有接口被调用后才会生成对应时间序列。如果需要接口未被调用时也能看到指标,可以通过配置预初始化指标:
import io.micrometer.core.instrument.MeterRegistry; import io.micrometer.core.instrument.Timer; import org.springframework.boot.ApplicationRunner; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class MeterConfig { @Bean public ApplicationRunner initMeters(MeterRegistry registry) { return args -> { // 预初始化ping和pong的Timer指标 Timer.builder("ping.request.time") .description("time pIng") .register(registry); Timer.builder("pong.request.time") .description("time pOng") .register(registry); }; } }
2. 解决PromQL查询返回空的问题
确认Prometheus抓取状态
- 访问
http://localhost:9090/targets,检查spring-actuator任务状态是否为UP,确保目标IP、抓取路径配置正确 - 在
http://localhost:9090/graph执行http_server_requests_seconds_count查询,确认是否存在带uri="/ping"标签的时间序列
检查标签匹配准确性
- 从
/actuator/prometheus端点复制uri标签的准确值(注意大小写、是否存在路径替换),确保查询时标签完全匹配 - 可尝试模糊匹配排查:
http_server_requests_seconds_count{uri=~".*ping.*"}
调整rate函数时间范围
rate()需要时间范围内至少两个样本才能计算结果,若接口调用频率低:
- 缩短时间范围,比如将
[5m]改为[1m] - 多次调用
/ping接口,等待至少两次Prometheus抓取(抓取间隔5s,需等待10s以上)后再查询
3. 绘制单次请求耗时的正确PromQL
- 查看最近一次请求的耗时:
http_server_requests_seconds_max{uri="/ping"} - 查看请求耗时的分位值(如95分位):
http_server_requests_seconds{uri="/ping",quantile="0.95"} - 计算一段时间内的平均耗时(需足够样本):
sum(rate(http_server_requests_seconds_sum{uri="/ping"}[1m])) / sum(rate(http_server_requests_seconds_count{uri="/ping"}[1m]))
内容的提问来源于stack exchange,提问作者Maifee Ul Asad
相关产品推荐
相关产品推荐

