我们公司的微服务去年已经开始使用metrics来收集应用运行指标,结合prometheus和grafana来统一收集和可视化。服务间的调用我们是使用Feign来进行调用的,但是发现springboot应用没法收集Feign调用得metrics信息,特此,记录一下怎么收集Feign调用的metrics信息。
首先我们来看一下springboot2.X默认使用的metrics指标工具micrometer,查看它的官方文档,我们发现它对okhttp做了支持,如下:
既然如此,那么我们可以调整Feign的默认底层调用实现,使其使用okhttp来调用,从而解决Feign的metrics指标问题。
在此,我们需要注意的是OkHttpClient Metrics
使用的okhttp的eventListener
功能,这个功能在早期的okhttp没有提供。我查看了一下okhttp文档,发现如下:
Version 3.11.0
...
New: The EventListener API previewed in OkHttp 3.9 has graduated to a stable API. Use this interface to track metrics and monitor HTTP requests’ size and duration.
表明,在3.11.0版本,该功能已经稳定。所以我们需要的版本>=3.11.0
下面,开始演示。
项目搭建
1. pom.xml
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-okhttp</artifactId>
<version>10.7.4</version>
<exclusions>
<exclusion>
<artifactId>okhttp</artifactId>
<groupId>com.squareup.okhttp3</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>3.14.4</version>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
<version>1.2.0</version>
</dependency>
</dependencies>
2. Feign底层使用okhttp
- 配置文件
feign: httpclient: enabled: false okhttp: enabled: true
- springboot配置
我们可以直接将FeignAutoConfiguration里面的okhttp配置拿出来
配置如下:
@Configuration
public class FeignConfig {
@Configuration
@ConditionalOnClass(OkHttpClient.class)
@ConditionalOnMissingClass("com.netflix.loadbalancer.ILoadBalancer")
@ConditionalOnProperty("feign.okhttp.enabled")
protected static class OkHttpFeignConfiguration {
private okhttp3.OkHttpClient okHttpClient;
@Bean
@ConditionalOnMissingBean(ConnectionPool.class)
public ConnectionPool httpClientConnectionPool(
FeignHttpClientProperties httpClientProperties,
OkHttpClientConnectionPoolFactory connectionPoolFactory) {
int maxTotalConnections = httpClientProperties.getMaxConnections();
long timeToLive = httpClientProperties.getTimeToLive();
TimeUnit ttlUnit = httpClientProperties.getTimeToLiveUnit();
return connectionPoolFactory.create(maxTotalConnections, timeToLive, ttlUnit);
}
@Bean
public okhttp3.OkHttpClient client(OkHttpClientFactory httpClientFactory,
ConnectionPool connectionPool,
FeignHttpClientProperties httpClientProperties,
OkHttpMetricsEventListener okHttpMetricsEventListener) {
this.okHttpClient = httpClientFactory.createBuilder(httpClientProperties.isDisableSslValidation())
.eventListener(okHttpMetricsEventListener) // 配置metrics监听器
.connectTimeout(httpClientProperties.getConnectionTimeout(), TimeUnit.MILLISECONDS)
.followRedirects(httpClientProperties.isFollowRedirects())
.connectionPool(connectionPool)
.build();
return this.okHttpClient;
}
@PreDestroy
public void destroy() {
if (this.okHttpClient != null) {
this.okHttpClient.dispatcher().executorService().shutdown();
this.okHttpClient.connectionPool().evictAll();
}
}
@Bean
public OkHttpMetricsEventListener okHttpMetricsEventListener(MeterRegistry meterRegistry) {
return OkHttpMetricsEventListener.builder(meterRegistry, "ok")
.uriMapper(request -> request.url().encodedPath()) // 默认也支持URI_PATTERN header支持uri tag
.tags(Collections.emptyList()) // 这里可以指定自定义的tag
.build();
}
@Bean
@ConditionalOnMissingBean(Client.class)
public Client feignClient(okhttp3.OkHttpClient client) {
return new OkHttpClient(client);
}
}
}
主要是增加了
...
.eventListener(okHttpMetricsEventListener) // 配置metrics监听器
...
@Bean
public OkHttpMetricsEventListener okHttpMetricsEventListener(MeterRegistry meterRegistry) {
return OkHttpMetricsEventListener.builder(meterRegistry, "ok")
.uriMapper(request -> request.url().encodedPath())
.tags(Collections.emptyList())
.build();
}
3. Feign请求代码
@FeignClient(name = "test", url = "http://localhost:8080")
public interface TestClient {
@GetMapping("/api/test")
BaseResp<String> test();
}
@RestController
public class FeignTestController {
@Autowired
private TestClient testClient;
@GetMapping("/test")
public String test() {
BaseResp<String> test = testClient.test();
System.out.println(test);
return "ok";
}
}
然后通过web暴露出这个接口给外部调用。
4. 观察metrics信息
如下,是一段相关的信息
# HELP ok_seconds Timer of OkHttp operation
# TYPE ok_seconds summary
ok_seconds_count{host="localhost",method="GET",status="200",uri="/api/test",} 8.0
ok_seconds_sum{host="localhost",method="GET",status="200",uri="/api/test",} 0.109059855
# HELP ok_seconds_max Timer of OkHttp operation
# TYPE ok_seconds_max gauge
ok_seconds_max{host="localhost",method="GET",status="200",uri="/api/test",} 0.004678218
到此,我们就可以获取到相关的Feign调用信息,然后就可以进行相关的监控和可视化展示。