文章目录
前言
老规矩哈,我们先从Micrometer、Spring Boot Actuator、Dropwizard等包中,找找看是否存在相关实现。
micrometer
- https://micrometer.io
- https://github.com/micrometer-metrics/micrometer
dropwizard
- https://metrics.dropwizard.io/4.2.0/index.html#
- https://github.com/dropwizard/metrics
spring boot actuator
看下面的2个包下代码即可
- org.springframework.boot.actuate.metrics
- org.springframework.boot.actuate.autoconfigure.metrics
由于Spring Boot与 micrometer高度集成,所以优先选择Spring Boot Actuator和Micrometer中的实现。
找到如下几个类
Spring Boot Actuator
- RestTemplateMetricsConfiguration.java
- HttpClientMetricsAutoConfiguration.java
Micrometer
- PoolingHttpClientConnectionManagerMetricsBinder.java
- MicrometerHttpRequestExecutor.java
首先Httpclient内部已经自带了一些监控指标都在PoolStats
对象,PoolingHttpClientConnectionManager.getTotalStats()
方法会返回PoolStats
对象,我们只需要把connectionManager
传递给PoolingHttpClientConnectionManagerMetricsBinder
即可。
new PoolingHttpClientConnectionManagerMetricsBinder(connectionManager, "my-pool")
.bindTo(registry);
其中PoolStats
对象包含以下指标。
-
leased
:正在执行请求的连接数。 -
pending
:排队获取连接的请求数量。注意:只有当有更多的工作线程争夺更少的连接时,才会发生这种情况。 -
available
:当前空闲的连接数。 -
max
:允许运行的最大连接数。
池中的连接总数等于available加上leased。
PoolingHttpClientConnectionManager(
org.apache.http.impl.conn.PoolingHttpClientConnectionManager
)是一个HttpClientConnection的连接池,可以为多线程提供并发请求服务。主要是分配连接,回收连接。同一个远程请求,会优先使用连接池提供的空闲的长连接。
监控
添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
使用示例
// 1.创建一个PoolingHttpClientConnectionManager
PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager();
poolingHttpClientConnectionManager.setMaxTotal(200);
poolingHttpClientConnectionManager.setDefaultMaxPerRoute(20);
HttpHost localhost = new HttpHost("locahost", 80);
// 特别指定Route(远程)请求最大的连接数,这里Route - localhost:80最大连接数为50
poolingHttpClientConnectionManager.setMaxPerRoute(new HttpRoute(localhost), 50);
// 2.给创建一个PoolingHttpClientConnectionManager加上监控
new PoolingHttpClientConnectionManagerMetricsBinder(poolingHttpClientConnectionManager, "laker-pool")
.bindTo(new LoggingMeterRegistry(new LoggingRegistryConfig() {
@Override
public String get(String key) {
return null;
}
@Override
public Duration step() {
return Duration.ofSeconds(10);
}
}, Clock.SYSTEM));
// 3.发起一个请求
CloseableHttpClient httpClient = HttpClientBuilder.create()
.setConnectionManager(poolingHttpClientConnectionManager)
// 启动线程,60秒钟从连接池中逐出空闲连接
.evictIdleConnections(60, TimeUnit.SECONDS)
.setDefaultRequestConfig(RequestConfig.custom().setConnectionRequestTimeout(2000)
.setConnectTimeout(2000)
.setSocketTimeout(2000)
.build())
.build();
HttpGet httpGet = new HttpGet("https://www.baidu.com");
//无论请求执行成功还是导致异常,HttpClient都会自动确保将连接释放回连接管理器。
String httpResponse = httpClient.execute(httpGet, response -> EntityUtils.toString(response.getEntity()));
System.out.println(httpResponse);
配置项解释
-
maxTotal
:连接池的最大连接数,默认:20
。 -
defaultMaxPreRount
:每个Rount(远程)请求最大的连接数,默认:2
。 -
setValidateAfterInactivity
:连接空闲多长时间(单位:毫秒)进行检查,默认:2000
。 -
connectTimeout
:与服务器连接超时时间,创建socket连接的超时时间。 -
connectionRequestTimeout
:从链接池获取连接的超时时间。 -
socketTimeout
:socket读取数据的超时时间,从服务器获取数据的超时时间。
结果:
httpcomponents.httpclient.pool.route.max.default{httpclient=laker-pool} value=20
httpcomponents.httpclient.pool.total.connections{httpclient=laker-pool,state=available} value=1
httpcomponents.httpclient.pool.total.connections{httpclient=laker-pool,state=leased} value=0
httpcomponents.httpclient.pool.total.max{httpclient=laker-pool} value=200
httpcomponents.httpclient.pool.total.pending{httpclient=laker-pool} value=0
从指标中可以看出,目前都是针对连接池的监控,没有连接请求耗时的监控,我们稍微等下给加上哈。
池中的连接总数等于available加上leased,即 1 + 0 = 1。
扩展 - 请求耗时统计
Micrometer提供了MicrometerHttpRequestExecutor
用于监控请求耗时。
// 加上监控
new PoolingHttpClientConnectionManagerMetricsBinder(poolingHttpClientConnectionManager, "laker-pool")
.bindTo(loggingMeterRegistry);
CloseableHttpClient httpClient = HttpClientBuilder.create()
.setConnectionManager(poolingHttpClientConnectionManager)
// 启动线程,60秒钟从连接池中逐出空闲连接
.evictIdleConnections(60, TimeUnit.SECONDS)
.setDefaultRequestConfig(RequestConfig.custom().setConnectionRequestTimeout(2000)
.setConnectTimeout(2000)
.setSocketTimeout(2000)
.build())
// 增加
.setRequestExecutor(MicrometerHttpRequestExecutor
.builder(loggingMeterRegistry)
.build())
.build();
结果:
httpcomponents.httpclient.pool.route.max.default{httpclient=laker-pool} value=20
httpcomponents.httpclient.pool.total.connections{httpclient=laker-pool,state=available} value=1
httpcomponents.httpclient.pool.total.connections{httpclient=laker-pool,state=leased} value=0
httpcomponents.httpclient.pool.total.max{httpclient=laker-pool} value=200
httpcomponents.httpclient.pool.total.pending{httpclient=laker-pool} value=0
// 这里哈
httpcomponents.httpclient.request{method=GET,status=200,uri=UNKNOWN} throughput=0.1/s mean=0.1761491s max=0.1761491s