1.基础配置
(1)spring boot 版本: 2.3.12.RELEASE
(2)应用名称配置为: seckill-client (配置正式应用名后注意修改以下相关配置)
(3)prometheus:prometheus-2.40.5.windows-amd64
(4)grafana:grafana-9.3.1
2.引入prometheus相关依赖包
- <dependency>
- <groupId>org.springframework.bootgroupId>
- <artifactId>spring-boot-starter-actuatorartifactId>
- dependency>
- <dependency>
- <groupId>io.micrometergroupId>
- <artifactId>micrometer-registry-prometheusartifactId>
- <version>1.8.2version>
- dependency>
3.配置文件
- server:
- port: 9001
-
- spring:
- application:
- # 服务名称
- name: seckill-client
-
- #promethues配置
- management:
- # server:
- # #管理端口,不配置则使用程序端口
- # port: 9002
- endpoint:
- metrics:
- enabled: true
- prometheus:
- enabled: true
- endpoints:
- web:
- exposure:
- include: health,info,env,prometheus,metrics,httptrace,threaddump,heapdump,springmetrics
- # include:
- metrics:
- export:
- prometheus:
- enabled: true
- tags: ${spring.application.name}
4.增加开启P90,P99统计
- package com.rendu.common.config;
-
- import io.micrometer.core.instrument.Meter;
- import io.micrometer.core.instrument.MeterRegistry;
- import io.micrometer.core.instrument.config.MeterFilter;
- import io.micrometer.core.instrument.distribution.DistributionStatisticConfig;
- import lombok.extern.slf4j.Slf4j;
- import org.springframework.boot.actuate.autoconfigure.metrics.MeterRegistryCustomizer;
- import org.springframework.context.annotation.Bean;
- import org.springframework.context.annotation.Configuration;
-
- import java.time.Duration;
-
- /**
- * @author mayiengly
- * @Date 2022-12-05 18:16
- * @Description
- */
- @Configuration
- @Slf4j
- public class MicrometerConfig {
- @Bean
- MeterRegistryCustomizer
metricsCommonTags() { - return registry -> {
- registry.config().meterFilter(
- new MeterFilter() {
- @Override
- public DistributionStatisticConfig configure(Meter.Id id, DistributionStatisticConfig config) {
- //匹配http开头并且是timer类型的监控指标
- if (id.getType() == Meter.Type.TIMER & id.getName().matches("^(http){1}.*")) {
- return DistributionStatisticConfig.builder()
- .percentilesHistogram(true)
- .percentiles(0.5, 0.90, 0.95, 0.99)
- .serviceLevelObjectives(Duration.ofMillis(50).toNanos(),
- Duration.ofMillis(100).toNanos(),
- Duration.ofMillis(200).toNanos(),
- Duration.ofSeconds(1).toNanos(),
- Duration.ofSeconds(5).toNanos())
- .minimumExpectedValue(Duration.ofMillis(1).toNanos())
- .maximumExpectedValue(Duration.ofSeconds(5).toNanos())
- .build()
- .merge(config);
- } else {
- return config;
- }
- }
- });
- };
- }
- }
5.切面监控api
- package com.rendu.common.aspect;
-
-
- import io.micrometer.core.instrument.Metrics;
- import org.aspectj.lang.ProceedingJoinPoint;
- import org.aspectj.lang.annotation.Around;
- import org.aspectj.lang.annotation.Aspect;
- import org.aspectj.lang.annotation.Pointcut;
- import org.springframework.stereotype.Component;
- import org.springframework.util.StringUtils;
- import org.springframework.web.context.request.RequestContextHolder;
- import org.springframework.web.context.request.ServletRequestAttributes;
-
- import javax.servlet.http.HttpServletRequest;
- import java.time.LocalDate;
- import java.util.concurrent.TimeUnit;
-
- /**
- * @author mayiengly
- * @Date 2022-12-05 17:23
- * @Description
- */
- @Aspect
- @Component
- public class PrometheusMetricsAspect {
-
- // 切入所有controller包下的请求方法
- @Pointcut("execution(* com.rendu.controller..*.*(..))")
- public void controllerPointcut() {
- }
-
- @Around("controllerPointcut()")
- public Object MetricsCollector(ProceedingJoinPoint joinPoint) throws Throwable {
-
- HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
- String userId = StringUtils.hasText( request.getParameter("userId"))?request.getParameter("userId"):"no userId";
- String appId = StringUtils.hasText( request.getParameter("appId"))?request.getParameter("appId"):"no appId";
-
- // 获取api url
- String api = request.getServletPath();
- // 获取请求方法
- String method = request.getMethod();
- long timeMillis = System.currentTimeMillis();
- LocalDate now = LocalDate.now();
- String[] tags = new String[10];
- tags[0]="api";
- tags[1] = api;
- tags[2]="method";
- tags[3]=method;
- tags[4]="day";
- tags[5]=now.toString();
- tags[6]="appId";
- tags[7]=appId;
- tags[8]="userId";
- tags[9]=userId;
- // 请求次数加1
- //自定义的指标名称:http_request_test_all,指标包含数据
- Metrics.counter("http_request_test_all",tags).increment();
- Object object;
- try {
- object = joinPoint.proceed();
- } catch (Exception e) {
- // 请求失败次数加1
- Metrics.counter("http_request_test_error",tags).increment();
- throw e;
- } finally {
- long f = System.currentTimeMillis();
- long l = f - timeMillis;
- //记录请求响应时间
- Metrics.timer("http_request_test_time", tags).record(l, TimeUnit.MILLISECONDS);
- }
- return object;
- }
- }
-
6.查看prometheus数据
浏览器访问:http://127.0.0.1:9001/actuator/prometheus
如下图所示即代表成功

7.配置prometheus
下载prometheus,在prometheus.yml文件的【scrape_configs】中增加监控配置,并运行prometheus.exe启动prometheus
- scrape_configs:
- # The job name is added as a label `job=
` to any timeseries scraped from this config. - - job_name: "seckill-client"
-
- # metrics_path defaults to '/metrics'
- # scheme defaults to 'http'.
- metrics_path: '/actuator/prometheus'
- static_configs:
- - targets: ["127.0.0.1:9001"]
8.测试查询prometheus
(1)浏览器访问prometheus:http://127.0.0.1:9090/
(2)执行【up】,如下图所示即代表成功

(3)访问spring boot开发的任意api,用于测试prometheus数据查询
(4)测试prometheus查询命令
http_request_test_all_total{job="seckill-client"}
如下图所示即代表prometheus查询成功

9.下载并运行grafana
(1)运行bin目录下grafana-server.exe
(2)浏览器访问:http://127.0.0.1:3000/
(3)默认登录账号:admin 密码:admin
10.grafana基础配置
(1)将以下内容存储为seckill-client.json文件
- {
- "annotations": {
- "list": [
- {
- "builtIn": 1,
- "datasource": {
- "type": "grafana",
- "uid": "-- Grafana --"
- },
- "enable": true,
- "hide": true,
- "iconColor": "rgba(0, 211, 255, 1)",
- "name": "Annotations & Alerts",
- "target": {
- "limit": 100,
- "matchAny": false,
- "tags": [],
- "type": "dashboard"
- },
- "type": "dashboard"
- }
- ]
- },
- "editable": true,
- "fiscalYearStartMonth": 0,
- "graphTooltip": 0,
- "id": 3,
- "links": [],
- "liveNow": false,
- "panels": [
- {
- "datasource": {
- "type": "prometheus",
- "uid": "y7CI3KKVz"
- },
- "description": "",
- "fieldConfig": {
- "defaults": {
- "mappings": [],
- "thresholds": {
- "mode": "absolute",
- "steps": [
- {
- "color": "green",
- "value": null
- },
- {
- "color": "red",
- "value": 80
- }
- ]
- },
- "unit": "short"
- },
- "overrides": []
- },
- "gridPos": {
- "h": 8,
- "w": 12,
- "x": 0,
- "y": 0
- },
- "id": 10,
- "options": {
- "colorMode": "background",
- "graphMode": "none",
- "justifyMode": "auto",
- "orientation": "auto",
- "reduceOptions": {
- "calcs": [
- "lastNotNull"
- ],
- "fields": "",
- "values": false
- },
- "textMode": "auto"
- },
- "pluginVersion": "9.3.1",
- "targets": [
- {
- "datasource": {
- "type": "prometheus",
- "uid": "y7CI3KKVz"
- },
- "editorMode": "code",
- "expr": "http_request_test_all_total{job=\"seckill-client\"}",
- "legendFormat": "__auto",
- "range": true,
- "refId": "A"
- }
- ],
- "title": "总访问数",
- "type": "stat"
- },
- {
- "datasource": {
- "type": "prometheus",
- "uid": "y7CI3KKVz"
- },
- "fieldConfig": {
- "defaults": {
- "custom": {
- "align": "auto",
- "displayMode": "auto",
- "inspect": false
- },
- "mappings": [],
- "thresholds": {
- "mode": "absolute",
- "steps": [
- {
- "color": "green",
- "value": null
- },
- {
- "color": "red",
- "value": 80
- }
- ]
- }
- },
- "overrides": []
- },
- "gridPos": {
- "h": 8,
- "w": 12,
- "x": 12,
- "y": 0
- },
- "id": 12,
- "options": {
- "footer": {
- "fields": "",
- "reducer": [
- "sum"
- ],
- "show": false
- },
- "showHeader": true
- },
- "pluginVersion": "9.3.1",
- "targets": [
- {
- "datasource": {
- "type": "prometheus",
- "uid": "y7CI3KKVz"
- },
- "editorMode": "code",
- "exemplar": false,
- "expr": "http_request_test_all_total{job=\"seckill-client\"}",
- "format": "table",
- "instant": true,
- "legendFormat": "__auto",
- "range": false,
- "refId": "A"
- }
- ],
- "title": "Panel Title",
- "transformations": [
- {
- "id": "merge",
- "options": {}
- }
- ],
- "type": "table"
- },
- {
- "datasource": {
- "type": "prometheus",
- "uid": "y7CI3KKVz"
- },
- "fieldConfig": {
- "defaults": {
- "color": {
- "mode": "palette-classic"
- },
- "custom": {
- "axisCenteredZero": false,
- "axisColorMode": "text",
- "axisLabel": "",
- "axisPlacement": "auto",
- "barAlignment": 0,
- "drawStyle": "line",
- "fillOpacity": 0,
- "gradientMode": "none",
- "hideFrom": {
- "legend": false,
- "tooltip": false,
- "viz": false
- },
- "lineInterpolation": "linear",
- "lineWidth": 1,
- "pointSize": 5,
- "scaleDistribution": {
- "type": "linear"
- },
- "showPoints": "auto",
- "spanNulls": false,
- "stacking": {
- "group": "A",
- "mode": "none"
- },
- "thresholdsStyle": {
- "mode": "off"
- }
- },
- "mappings": [],
- "thresholds": {
- "mode": "absolute",
- "steps": [
- {
- "color": "green",
- "value": null
- },
- {
- "color": "red",
- "value": 80
- }
- ]
- }
- },
- "overrides": []
- },
- "gridPos": {
- "h": 8,
- "w": 12,
- "x": 0,
- "y": 8
- },
- "id": 6,
- "options": {
- "legend": {
- "calcs": [],
- "displayMode": "list",
- "placement": "bottom",
- "showLegend": true
- },
- "tooltip": {
- "mode": "single",
- "sort": "none"
- }
- },
- "targets": [
- {
- "datasource": {
- "type": "prometheus",
- "uid": "y7CI3KKVz"
- },
- "editorMode": "code",
- "expr": "avg(http_request_test_time_seconds{job=\"seckill-client\" ,quantile =~ \"0.9|0.99\"}) by (job,quantile)",
- "legendFormat": "__auto",
- "range": true,
- "refId": "A"
- }
- ],
- "title": "P90 P99指标统计",
- "type": "timeseries"
- },
- {
- "datasource": {
- "type": "prometheus",
- "uid": "y7CI3KKVz"
- },
- "fieldConfig": {
- "defaults": {
- "color": {
- "mode": "palette-classic"
- },
- "custom": {
- "axisCenteredZero": false,
- "axisColorMode": "text",
- "axisLabel": "",
- "axisPlacement": "auto",
- "barAlignment": 0,
- "drawStyle": "line",
- "fillOpacity": 0,
- "gradientMode": "none",
- "hideFrom": {
- "legend": false,
- "tooltip": false,
- "viz": false
- },
- "lineInterpolation": "linear",
- "lineWidth": 1,
- "pointSize": 5,
- "scaleDistribution": {
- "type": "linear"
- },
- "showPoints": "auto",
- "spanNulls": false,
- "stacking": {
- "group": "A",
- "mode": "none"
- },
- "thresholdsStyle": {
- "mode": "off"
- }
- },
- "mappings": [],
- "thresholds": {
- "mode": "absolute",
- "steps": [
- {
- "color": "green",
- "value": null
- },
- {
- "color": "red",
- "value": 80
- }
- ]
- }
- },
- "overrides": []
- },
- "gridPos": {
- "h": 8,
- "w": 12,
- "x": 12,
- "y": 8
- },
- "id": 8,
- "options": {
- "legend": {
- "calcs": [],
- "displayMode": "list",
- "placement": "bottom",
- "showLegend": true
- },
- "tooltip": {
- "mode": "single",
- "sort": "none"
- }
- },
- "targets": [
- {
- "datasource": {
- "type": "prometheus",
- "uid": "y7CI3KKVz"
- },
- "editorMode": "code",
- "expr": "max(http_request_test_time_seconds_max{job=\"seckill-client\"})",
- "legendFormat": "__auto",
- "range": true,
- "refId": "A"
- }
- ],
- "title": "最大耗时",
- "type": "timeseries"
- },
- {
- "datasource": {
- "type": "prometheus",
- "uid": "y7CI3KKVz"
- },
- "fieldConfig": {
- "defaults": {
- "color": {
- "mode": "palette-classic"
- },
- "custom": {
- "axisCenteredZero": false,
- "axisColorMode": "text",
- "axisLabel": "",
- "axisPlacement": "auto",
- "barAlignment": 0,
- "drawStyle": "line",
- "fillOpacity": 0,
- "gradientMode": "none",
- "hideFrom": {
- "legend": false,
- "tooltip": false,
- "viz": false
- },
- "lineInterpolation": "linear",
- "lineWidth": 1,
- "pointSize": 5,
- "scaleDistribution": {
- "type": "linear"
- },
- "showPoints": "auto",
- "spanNulls": false,
- "stacking": {
- "group": "A",
- "mode": "none"
- },
- "thresholdsStyle": {
- "mode": "off"
- }
- },
- "mappings": [],
- "thresholds": {
- "mode": "absolute",
- "steps": [
- {
- "color": "green",
- "value": null
- },
- {
- "color": "red",
- "value": 80
- }
- ]
- }
- },
- "overrides": []
- },
- "gridPos": {
- "h": 8,
- "w": 12,
- "x": 0,
- "y": 16
- },
- "id": 2,
- "options": {
- "legend": {
- "calcs": [],
- "displayMode": "list",
- "placement": "bottom",
- "showLegend": true
- },
- "tooltip": {
- "mode": "single",
- "sort": "none"
- }
- },
- "targets": [
- {
- "datasource": {
- "type": "prometheus",
- "uid": "y7CI3KKVz"
- },
- "editorMode": "code",
- "expr": "60*sum(rate(http_request_test_all_total{job=\"seckill-client\"}[1m]))",
- "hide": false,
- "legendFormat": "__auto",
- "range": true,
- "refId": "A"
- }
- ],
- "title": "每分钟请求总数",
- "type": "timeseries"
- },
- {
- "datasource": {
- "type": "prometheus",
- "uid": "y7CI3KKVz"
- },
- "fieldConfig": {
- "defaults": {
- "color": {
- "mode": "palette-classic"
- },
- "custom": {
- "axisCenteredZero": false,
- "axisColorMode": "text",
- "axisLabel": "",
- "axisPlacement": "auto",
- "barAlignment": 0,
- "drawStyle": "line",
- "fillOpacity": 0,
- "gradientMode": "none",
- "hideFrom": {
- "legend": false,
- "tooltip": false,
- "viz": false
- },
- "lineInterpolation": "linear",
- "lineWidth": 1,
- "pointSize": 5,
- "scaleDistribution": {
- "type": "linear"
- },
- "showPoints": "auto",
- "spanNulls": false,
- "stacking": {
- "group": "A",
- "mode": "none"
- },
- "thresholdsStyle": {
- "mode": "off"
- }
- },
- "mappings": [],
- "thresholds": {
- "mode": "absolute",
- "steps": [
- {
- "color": "green",
- "value": null
- },
- {
- "color": "red",
- "value": 80
- }
- ]
- }
- },
- "overrides": []
- },
- "gridPos": {
- "h": 8,
- "w": 12,
- "x": 12,
- "y": 16
- },
- "id": 4,
- "options": {
- "legend": {
- "calcs": [],
- "displayMode": "list",
- "placement": "bottom",
- "showLegend": true
- },
- "tooltip": {
- "mode": "single",
- "sort": "none"
- }
- },
- "targets": [
- {
- "datasource": {
- "type": "prometheus",
- "uid": "y7CI3KKVz"
- },
- "editorMode": "code",
- "expr": "(sum(http_request_test_time_seconds{job=\"seckill-client\"})/sum(http_request_test_all_total{job=\"seckill-client\"}))",
- "legendFormat": "__auto",
- "range": true,
- "refId": "A"
- }
- ],
- "title": "请求平均耗时",
- "type": "timeseries"
- }
- ],
- "refresh": false,
- "schemaVersion": 37,
- "style": "dark",
- "tags": [],
- "templating": {
- "list": []
- },
- "time": {
- "from": "now-30m",
- "to": "now"
- },
- "timepicker": {},
- "timezone": "",
- "title": "seckill-client-dashboard",
- "uid": "PSpzcYFVk",
- "version": 5,
- "weekStart": ""
- }
(2)选择导入模板,在Dashboards中选择导入

(3)上传seckill-client.json文件,可修改名称和uid如下图,完成后导入即可
11.grafana效果图

12.promethues查询语句
(1)每分钟请求总数
60*sum(rate(http_request_test_all_total{}[1m]))
(2)统计指定api=/demo/name
60*sum(rate(http_request_test_all_total{api="/demo/name"}[1m]))
(3)请求平均耗时
(sum(http_request_test_time_seconds{job="seckill-client"})/sum(http_request_test_all_total{job="seckill-client"}))
(4)P90 P99指标统计
avg(http_request_test_time_seconds{job="seckill-client" ,quantile =~ "0.9|0.99"}) by (job,quantile)
(5)最大耗时
max(http_request_test_time_seconds_max{job="seckill-client"})
(6)访问总数
http_request_test_all_total{job=\"seckill-client\"}