赞
踩
目录
实现Spring boot+Prometeus+Granafa的业务指标监控
核心依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>io.micrometer</groupId> <artifactId>micrometer-registry-prometheus</artifactId> </dependency> |
spring: application: name: prometheus-example management: endpoints: web: exposure: include: health,prometheus metrics: tags: application: ${spring.application.name} #为应用设置tag ,方便区分不同的应用 |
Counter 只会报告单个指标,可以增加一个可选的值,且该值必须是正数,默认为 1。Counter常用来记录某些将一直正增长的数据,如 请求次数、变化次数,通过在对应监控系统使用聚合函数,如 rate、increase 等,可以计算出指标在指定时间范围的变化率,也就是通常说的 QPS
import io.micrometer.core.instrument.MeterRegistry; import io.micrometer.core.instrument.Counter; @Data @RestController public class PrometheusController { private Counter counter; private final MeterRegistry registry; @Autowired public PrometheusCustomMonitor(MeterRegistry registry) { this.registry = registry; counter = registry.counter("order_counter", "orderCounter", "test-auth"); } } |
@RequestMapping("/counter") public String orderCounter() { // 统计下单次数 counter.increment(); Random random = new Random(); int amount = random.nextInt(100); return "下单成功, 金额: " + amount; } |
Summary用于跟踪事件的分发。 它在结构上类似于计时器,但记录的值不代表时间单位。 例如,分发摘要可用于衡量命中服务器的请求的有效负载大小。
import io.micrometer.core.instrument.MeterRegistry; import io.micrometer.core.instrument.DistributionSummary; @Data @RestController public class PrometheusController { private DistributionSummary summary; private final MeterRegistry registry; @Autowired public PrometheusCustomMonitor(MeterRegistry registry) { this.registry = registry; summary = registry.summary("order_summary", "orderSummary", "test-auth"); } } |
@RequestMapping("/summary") public String orderSummary() { Random random = new Random(); int amount = random.nextInt(100); // 统计下单记录 summary.record(amount); return "下单成功, 金额: " + amount; } |
一般用于监测有自然上限的事件或任务,而 Counter 一般用于无自然上限的事件或任务。有自然上限:如内存使用大小、容器大小、运行中的线程数量等。
import io.micrometer.core.instrument.Tags; import io.micrometer.core.instrument.MeterRegistry; @Data @RestController public class PrometheusController { private AtomicInteger gauge; private final MeterRegistry registry; @Autowired public PrometheusCustomMonitor(MeterRegistry registry) { this.registry = registry; gauge = registry.gauge("order_gauge", Tags.of("orderGauge", "test-auth"), new AtomicInteger(1000)); } } |
@RequestMapping("/gauge") public String orderGauge() { Random random = new Random(); int amount = random.nextInt(100); // 记录余额 gauge.decrementAndGet(); return "下单成功, 金额: " + amount; } |
Timer是计时器,用来测量短时间的代码块的执行时间的分布。Timer记录代码块的执行时间后,可以对执行时间进行统计,分析记录执行的最大时间、总时间、平均时间、执行完成的总任务等。
import io.micrometer.core.instrument.Timer; import io.micrometer.core.instrument.MeterRegistry; @Data @RestController public class PrometheusController { private Timer timer; private final MeterRegistry registry; @Autowired public PrometheusCustomMonitor(MeterRegistry registry) { this.registry = registry; timer = registry.timer("order_timer", "orderTimer", "test-auth"); } } |
@RequestMapping("/timer") public String orderTimer() { Random random = new Random(); int amount = random.nextInt(100); // 记录接口用时 timer.record(100, TimeUnit.MILLISECONDS); timer.record(Duration.ofMillis(100)); timer.record(() -> { try { Thread.sleep(amount2 * amount2 / 10); } catch (InterruptedException e) { e.printStackTrace(); } }); return "下单成功, 金额: " + amount; } |
LongTaskTimer一般监控长时间执行的程序,可以实时观测任务的耗时和正在执行的任务数量
import io.micrometer.core.instrument.LongTaskTimer; import io.micrometer.core.instrument.MeterRegistry; @Data @RestController public class PrometheusController { private LongTaskTimer longTaskTimer; private final MeterRegistry registry; @Autowired public PrometheusCustomMonitor(MeterRegistry registry) { this.registry = registry; longTaskTimer = registry.more().longTaskTimer("order_long_task_timer", "order_long_task_time", "test-auth"); } } |
@RequestMapping("/long/timer") public String orderTimer() { Random random = new Random(); int amount2 = random.nextInt(100); longTaskTimer.record(() -> { try { Thread.sleep(amount2 * amount2 * 10); } catch (InterruptedException e) { e.printStackTrace(); } }); return "下单成功, 金额, amount2: " + amount2; } |
Counter 只会报告单个指标,可以增加一个可选的值,且该值必须是正数,默认为 1。Counter常用来记录某些将一直正增长的数据,如 请求次数、变化次数,通过在对应监控系统使用聚合函数,如 rate、increase 等,可以计算出指标在指定时间范围的变化率,也就是通常说的 QPS
import io.prometheus.client.Counter; import io.prometheus.client.CollectorRegistry; @Data @RestController public class PrometheusController { private Counter counter2; private final CollectorRegistry collectorRegistry; @Autowired public PrometheusCustomMonitor( CollectorRegistry collectorRegistry) { this.collectorRegistry = collectorRegistry; counter2 = io.prometheus.client.Counter.build().name("order_counter2").labelNames("order_counter2", "testCounter2").help("counter").register(collectorRegistry); } } |
@RequestMapping("/order/counter2") public String orderCounter2() { Random random = new Random(); int amount = random.nextInt(100); // 根据不同标签区分不同数据类型 counter2.labels("amount1", "test1").inc(amount); counter2.labels("amount1", "test3").inc(amount); int amount2 = random.nextInt(100); counter2.labels("amount2", "test2").inc(amount2); return "下单成功, 金额, amount1: " + amount + " amount2: " + amount2; } |
Summary用于跟踪事件的分发。 它在结构上类似于计时器,但记录的值不代表时间单位。 例如,分发摘要可用于衡量命中服务器的请求的有效负载大小。
import io.prometheus.client.Summary; import io.prometheus.client.CollectorRegistry; @Data @RestController public class PrometheusController { private Summary summary2; private final CollectorRegistry collectorRegistry; @Autowired public PrometheusCustomMonitor( CollectorRegistry collectorRegistry) { this.collectorRegistry = collectorRegistry; summary2 = Summary.build().name("order_summary2").labelNames("order_summary2", "testSummary2").help("summary").register(collectorRegistry); } } |
@RequestMapping("/order/summary2") public String orderSummary2() { Random random = new Random(); int amount = random.nextInt(100); summary2.labels("summary1", "test1").observe(amount); int amount2 = random.nextInt(100); summary2.labels("summary2", "test2").observe(amount2); Summary.Timer timer = summary2.labels("summary4", "timer").startTimer(); summary2.labels("summary3", "timer").time(() -> { try { Thread.sleep(amount * amount); } catch (InterruptedException e) { e.printStackTrace(); } }); timer.close(); return "下单成功, 金额, amount1: " + amount + " amount2: " + amount2; } |
一般用于监测有自然上限的事件或任务,而 Counter 一般用于无自然上限的事件或任务。有自然上限:如内存使用大小、容器大小、运行中的线程数量等。
import io.prometheus.client.Gauge; import io.prometheus.client.CollectorRegistry; @Data @RestController public class PrometheusController { private Gauge gauge2; private final CollectorRegistry collectorRegistry; @Autowired public PrometheusCustomMonitor( CollectorRegistry collectorRegistry) { this.collectorRegistry = collectorRegistry; gauge2 = Gauge.build().name("order_gauge2").labelNames("order_gauge2", "testGauge2").help("gauge").register(collectorRegistry); } } |
@RequestMapping("/gauge2") public String orderGauge2() { Random random = new Random(); int amount = random.nextInt(100); gauge2.labels("gauge1", "test1").set(amount); int amount2 = random.nextInt(100); gauge2.labels("gauge2", "test2").set(amount2); return "下单成功, 金额, amount1: " + amount + " amount2: " + amount2; } |
import io.prometheus.client.Histogram; import io.prometheus.client.CollectorRegistry; @Data @RestController public class PrometheusController { private Histogram histogram; private Histogram histogram2; private Histogram histogram3;; private final CollectorRegistry collectorRegistry; @Autowired public PrometheusCustomMonitor( CollectorRegistry collectorRegistry) { this.collectorRegistry = collectorRegistry; // 默认刻度 histogram = Histogram.build().name("order_histogram").labelNames("order_histogram", "testHistogram").help("histogram").register(collectorRegistry); // 自己设定刻度 histogram2 = Histogram.build().buckets(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10).name("order_histogram2").labelNames("order_histogram", "testHistogram").help("histogram").register(collectorRegistry); histogram3 = Histogram.build().buckets(0, 10, 20, 30, 40, 50, 100).name("order_histogram3").labelNames("order_histogram", "testHistogram").help("histogram").register(collectorRegistry); } } |
@RequestMapping("/order/timer") public String orderTimer() { Random random = new Random(); int amount = random.nextInt(100); int amount2 = random.nextInt(100); histogram2.labels("histogram2", "test1").observe(amount); histogram2.labels("histogram2", "test2").observe(amount2); histogram.labels("histogram1", "test3").time(() -> { try { Thread.sleep(amount * amount / 10); } catch (InterruptedException e) { e.printStackTrace(); } }); histogram3.labels("histogram3", "test4").time(() -> { try { Thread.sleep(amount2 * amount2 / 10); } catch (InterruptedException e) { e.printStackTrace(); } }); return "下单成功, 金额, amount1: " + amount + " amount2: " + amount2; } |
- job_name: 'prometheus-example' # 抓取频率 scrape_interval: 5s # 抓取的端点,也就是服务暴露出来的指标接口地址 metrics_path: '/actuator/prometheus' static_configs: # 目标服务地址,数组,也就是说支持集群拉取 - targets: ['127.0.0.1:8080'] |
样例:windows安装启动,下载安装包解压,bin目录下双击.exe程序
Prometheus
Granafa
Prometheus地址:http://127.0.0.1:9090/graph
Grafana地址:http://127.0.0.1:3000/datasources
首先在Grafana模板仓库,找到要导入模板ID,模板地址:Dashboards | Grafana Labs
选择添加的数据源
完成
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。