Java获取Prometheus监控指标数据
Posted 浪浪山的猿
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java获取Prometheus监控指标数据相关的知识,希望对你有一定的参考价值。
Java获取Prometheus监控指标数据
一. 准备工作
1. 有可以被Prometheus监控的服务
没有的话可以参考以下链接本地搭建:SpringBoot应用接入Prometheus+Grafana
2. 选择我们调用远程服务的方式
可以选择RestTemplate 作为远程调用工具,RestTemplate 内部默认用的是 jdk 自带的
HttpURLConnection 发送请求的,性能上面并不是太突出。可以将其替换为 httpclient 或者 okhttp。
二. 实战
1. 引入依赖
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
2. 编写http请求工具
package com.alibaba.bizworks.om.account.prometheus;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.Header;
import org.apache.http.client.HttpClient;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.ssl.SSLContextBuilder;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.web.client.DefaultResponseErrorHandler;
import org.springframework.web.client.RestTemplate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
/**
* RestTemplate 远程调用工具类
* @author gf
* @date 2022/10/24
*/
@Slf4j
public class RestTemplateUtils
/**
* 读取时间,自定义默认8s,0表示没有超时时间
*/
public static final int READ_TIMEOUT = 1000*8;
/**
* 连接时间,自定义默认8s,0表示没有超时时间
*/
public static final int CONNEC_TIMEOUT = 1000*8;
/**
* 重试次数,自定义默认1
*/
public static final int RETRY_COUNT = 1;
/**
* http 请求 GET
*
* @param url 地址
* @param params 参数
* @return String 类型
*/
public static String getHttp(String url, JSONObject params)
String result = getHttp(url, params, READ_TIMEOUT, CONNEC_TIMEOUT, RETRY_COUNT);
return result;
/**
* http 请求 GET
*
* @param url 地址
* @param params 参数
* @param connecTimeout 连接时间
* @param readTimeout 读取时间
* @param retryCount 重试机制
* @return String 类型
*/
public static String getHttp(String url, JSONObject params, int connecTimeout, int readTimeout, int retryCount)
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
requestFactory.setConnectTimeout(connecTimeout);
requestFactory.setReadTimeout(readTimeout);
RestTemplate restTemplate = new RestTemplate(requestFactory);
restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8)); // 设置编码集
restTemplate.setErrorHandler(new DefaultResponseErrorHandler()); // 异常处理
url = expandURL(url, params);
String result = null; // 返回值类型;
for (int i = 1; i <= retryCount; i++)
try
log.info("【GET/HTTP请求信息】,请求地址:,请求参数:", url, params);
result = restTemplate.getForObject(url, String.class, params);
log.info("【GET/HTTP请求信息】,请求地址:,请求参数:,返回结果:", url, params,result);
return result;
catch (Exception e)
log.error("【GET/HTTP请求信息】异常,重试count:,请求地址:,请求参数:,异常信息:", i, url, params,e);
e.printStackTrace();
return result;
/**
* https 请求 GET
*
* @param url 地址
* @param params 参数
* @return String 类型
*/
public static String getHttps(String url, JSONObject params)
String result = getHttps(url, params, READ_TIMEOUT, CONNEC_TIMEOUT, RETRY_COUNT);
return result;
/**
* https 请求 GET
*
* @param url 地址
* @param params 参数
* @param connecTimeout 连接时间
* @param readTimeout 读取时间
* @param retryCount 重试机制
* @return String 类型
*/
public static String getHttps(String url, JSONObject params, int connecTimeout, int readTimeout, int retryCount)
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
requestFactory.setConnectTimeout(connecTimeout);
requestFactory.setReadTimeout(readTimeout);
RestTemplate restTemplate = restTemplate();
RestTemplateUtils.clientHttpRequestFactory();
restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8)); // 设置编码集
restTemplate.setErrorHandler(new DefaultResponseErrorHandler()); //error处理
restTemplate.setRequestFactory(clientHttpRequestFactory()); // 绕过https
url = expandURL(url, params);
String result = null; // 返回值类型;
for (int i = 1; i <= retryCount; i++)
try
log.info("【GET/HTTPS请求信息】,请求地址:,请求参数:", url, params);
result = restTemplate.getForObject(url, String.class, params);
log.info("【GET/HTTPS请求信息】,请求地址:,请求参数:,返回结果:", url, params,result);
return result;
catch (Exception e)
log.error("【GET/HTTPS请求信息】异常,重试count:,请求地址:,请求参数:,异常信息:", i, url, params,e);
e.printStackTrace();
return result;
/**
* @Title: URL拼接
* @MethodName: expandURL
* @param url
* @param jsonObject
* @Return java.lang.String
* @Exception
* @Description:
*/
private static String expandURL(String url,JSONObject jsonObject)
StringBuilder sb = new StringBuilder(url);
sb.append("?");
Set<String> keys = jsonObject.keySet();
for (String key : keys)
sb.append(key).append("=").append(jsonObject.getString(key)).append("&");
return sb.deleteCharAt(sb.length() - 1).toString();
/**
* 获取RestTemplate实例对象,可自由调用其方法
*
* @return RestTemplate实例对象
*/
public static HttpClient httpClient()
HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
try
//设置信任ssl访问
SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, (arg0, arg1) -> true).build();
httpClientBuilder.setSSLContext(sslContext);
HostnameVerifier hostnameVerifier = NoopHostnameVerifier.INSTANCE;
SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext, hostnameVerifier);
Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
// 注册http和https请求
.register("http", PlainConnectionSocketFactory.getSocketFactory())
.register("https", sslConnectionSocketFactory).build();
//使用Httpclient连接池的方式配置(推荐),同时支持netty,okHttp以及其他http框架
PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
// 最大连接数
poolingHttpClientConnectionManager.setMaxTotal(1000);
// 同路由并发数
poolingHttpClientConnectionManager.setDefaultMaxPerRoute(100);
//配置连接池
httpClientBuilder.setConnectionManager(poolingHttpClientConnectionManager);
// 重试次数
httpClientBuilder.setRetryHandler(new DefaultHttpRequestRetryHandler(1, true));
//设置默认请求头
List<Header> headers = new ArrayList<>();
httpClientBuilder.setDefaultHeaders(headers);
return httpClientBuilder.build();
catch (Exception e)
throw new RuntimeException(e);
public static ClientHttpRequestFactory clientHttpRequestFactory()
HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(httpClient());
// 连接超时(毫秒),这里设置10秒
clientHttpRequestFactory.setConnectTimeout(10 * 1000);
// 数据读取超时时间(毫秒),这里设置60秒
clientHttpRequestFactory.setReadTimeout(60 * 1000);
// 从连接池获取请求连接的超时时间(毫秒),不宜过长,必须设置,比如连接不够用时,时间过长将是灾难性的
clientHttpRequestFactory.setConnectionRequestTimeout(10 * 1000);
return clientHttpRequestFactory;
public static RestTemplate restTemplate()
//创建RestTemplate的时候,指定ClientHttpRequestFactory
return new RestTemplate(clientHttpRequestFactory());
3. 编写响应体
从浏览器中找到peomrtheus它获取服务指标的请求地址
然后根据这个地址在postman发get请求拿到它的响应体结构
接下来我们就可以根据这个结果来封装相应体了
@Data
public class PromResponceInfo
/**
* 状态
* 成功-- success
*/
private String status;
/**
* prometheus指标属性和值
*/
private PromDataInfo data;
这里只关注后面的resultType 和result参数
@Data
public class PromDataInfo
/**
* prometheus监控服务指表参数
*/
private List droppedTargets;
private List<PromResultInfo> activeTargets;
/**
* prometheus监控样本指标参数
*/
private String resultType;
private List<PromMetric> result;
@Data
public class PromMetric
/**
* metric name和描述当前样本特征的labelsets
*/
private PromMetricInfo metric;
/**
* 一个float64的浮点型数据表示当前样本的值。
*/
private String[] value;
@Data
public class PromMetricInfo
/**
* prometheus指标名称
*/
private String __name__;
/**
* prometheus实例名称
*/
private String instance;
/**
* prometheus任务名称
*/
private String job;
private String application;
private String exception;
private String method;
private String outcome;
private String status;
private String url;
到这里我们响应体的结构就写好了,还有一个指标参数,我这里写了一个类,后面需要查询指标或者一些聚合函数(PromQL)
package com.alibaba.bizworks.om.account.prometheus;
import lombok.Data;
/**
* @Title: prometheus常量信息
* @author gf
* @date 2022/10/19
*/
@Data
public class PromConstants
/**
* prometheus-查询SUCCESS
*/
public static final String SUCCESS = "success";
/**prometheus-查询参数*/
public static final String QUERY = "query";
/**系统CPU使用率*/
public static final String SYSTEM_CPU_USAGE= "system_cpu_usage";
/**Java虚拟机可用的处理器数量*/
public static final String SYSTEM_CPU_COUNT= "system_cpu_count";
/**JVM的CPU利用率*/
public static final String PROCESS_CPU_COUNT= "process_cpu_usage";
/**
* tomcat相关参数
*/
/**tomcat_当前活跃会话数*/
public static final String TOMCAT_SESSIONS_ACTIVE_CURRENT_SESSIONS = "tomcat_sessions_active_current_sessions";
/**
* jvm 相关参数
*/
/**Java虚拟机的正常运行时间*/
public static final String PROCESS_UPTIME_SECONDS = "process_uptime_seconds";
/**可供Java虚拟机使用的已提交的内存量*/
public static final String JVM_MEMORT_COMMITTED_BYTES = "jvm_memory_committed_bytes";
/**自Java虚拟机启动或重置峰值以来的活动线程峰值*/
public static final String JVM_THREADS_PEAK_THREADS= "jvm_threads_peak_threads";
/**在一个GC之后到下一个GC之前增加年轻代内存池的大小*/
public static final String JVM_GC_MEMORT_ALLOCATED_BYTES_TOTAL= "jvm_gc_memory_allocated_bytes_total";
/**进程的开始时间*/
public static final String PROCESS_START_TIME_SECONDS= "process_start_time_seconds";
/**最大内存*/
public static final String JVM_MEMORT_MAX_BYTES= "jvm_memory_max_bytes";
/**已使用内存*/
public static final String JVM_MEMORT_USED_BYTES= "jvm_memory_used_bytes";
/**请求次数*/
public static final String HTTP_SERVER_REQUEST_SECONDS_COUNT= "http_server_requests_seconds_count";
/**请求n次花费的时间*/
public static final String HTTP_SERVER_REQUEST_SECONDS_SUM= "http_server_requests_seconds_sum";
/**最长一次花了多长时间*/
public static final String HTTP_SERVER_REQUEST_SECONDS_MAX= "http_server_requests_seconds_max";
/**日志总数*/
public static final String LOGBACK_EVENTS_TOTAL = "logback_events_total";
4. 编写接口测试
参数说明:
- promURL:请求url
- promQL:指标参数
@Slf4j
public class TestController
public static PromDataInfo getDateInfo(String promURL, String promQL)
log.info("请求地址:,请求QL:", promURL, promQL);
JSONObject param = new JSONObject();
param.put(PromConstants.QUERY, promQL);
参考技术A
Prometheus 最开始是由 SoundCloud 开发的开源监控告警系统,是 Google BorgMon 监控系统的开源版本。在 2016 年,Prometheus 加入 CNCF,成为继 Kubernetes 之后第二个被 CNCF 托管的项目。随着 Kubernetes 在容器编排领头羊地位的确立,Prometheus 也成为 Kubernetes 容器监控的标配。
监控系统的总体架构大多是类似的,都有数据采集、数据处理存储、告警动作触发和告警,以及对监控数据的展示。下面是 Prometheus 的架构:
Prometheus Server 负责定时从 Prometheus 采集端 Pull(拉) 监控数据。Prometheus 采集端可以是实现了 /metrics 接口的服务,可以是从第三方服务导出监控数据的 exporter,也可以是存放短生命周期服务监控数据的 Pushgateway。相比大多数采用 Push(推) 监控数据的方式,Pull 使得 Promethues Server 与被采集端的耦合度更低,Prometheus Server 更容易实现水平拓展。对于采集的监控数据,Prometheus Server 使用内置时序数据库 TSDB 进行存储。同时也会使用这些监控数据进行告警规则的计算,产生的告警将会通过 Prometheus 另一个独立的组件 Alertmanager 进行发送。Alertmanager 提供了十分灵活的告警方式,并且支持高可用部署。对于采集到的监控数据,可以通过 Prometheus 自身提供的 Web UI 进行查询,也可以使用 Grafana 进行展示。
以上是关于Java获取Prometheus监控指标数据的主要内容,如果未能解决你的问题,请参考以下文章
prometheus以监控Pod TCP连接数为例删除一个或多个metrics指标