使用Spring Boot时,通过Caffeine缓存获取指标时,可以使用Prometheus来获取
验证版本
Spring Boot 2.1.0.RELEASE 的释放版本。
使用Spring Boot来使用缓存
首先进行缓存的设置。要做的是
spring-boot-starter-cache の依存を入れる
Cacheableなmethodを書く。これはControllerに置かない。別のComponentに置く。
ConfigurationクラスかApplicationクラスに@EnableCachingをつける
三点
加入 spring-boot-starter-cache 的依赖
如果使用Gradle,可以在build.gradle文件的dependencies部分进行指定。为了创建一个简单的web布局,可以按照以下方式定义依赖关系。
dependencies {
implementation('org.springframework.boot:spring-boot-starter-actuator')
implementation('org.springframework.boot:spring-boot-starter-cache')
implementation('org.springframework.boot:spring-boot-starter-web')
compileOnly('org.projectlombok:lombok')
testImplementation('org.springframework.boot:spring-boot-starter-test')
}
定义可缓存的方法。
适当地准备一个Repository类,并按照以下方式实现,从缓存中取出一次回显的数值。 @Cacheable的value被设置为cacheName。
@Slf4j
@Repository
public class EchoRepository {
@Cacheable("echo")
public String echo(String value) {
log.info("no cache: {}", value);
return value;
}
}
此外,还需要实现调用此处理的RestController控制器。
@RequiredArgsConstructor
@RestController
public class EchoController {
private final EchoRepository repository;
@GetMapping("echo")
public String echo(@RequestParam String value) {
return repository.echo(value);
}
}
在Configuration类或Application类中加上@EnableCaching注解。
暂时将其附加在Application类中。
@EnableCaching
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
考试
使用两个参数进行两次调用。
$ curl http://localhost:8080/echo?value=test
test$
$ curl http://localhost:8080/echo?value=test
test$
$ curl http://localhost:8080/echo?value=test1
test1$
$ curl http://localhost:8080/echo?value=test1
test1$
查看日志
2018-10-31 23:41:26.824 INFO 3663 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 18 ms
2018-10-31 23:41:26.914 INFO 3663 --- [nio-8080-exec-1] c.k.demo.repository.EchoRepository : no cache: test
2018-10-31 23:41:34.690 INFO 3663 --- [nio-8080-exec-3] c.k.demo.repository.EchoRepository : no cache: test1
似乎已经缓存了
使用咖啡因
在这里,缓存实现是可以选择的。默认情况下,似乎会选择使用基于ConcurrentHashMap的简单实现,但我们这里使用Caffeine。
只需添加implementation(‘com.github.ben-manes.caffeine:caffeine’)到依赖项中,即可使用。
收集咖啡因的度量指标
在微测中实现了收集Caffeine指标的实现,我想要利用它。
使用Spring Boot actuator提供Prometheus的终端点。
首先,在dependencies中添加implementation(‘io.micrometer:micrometer-registry-prometheus’)。然后,在application.yml中添加management.endpoints.web.exposure.include: prometheus,以便可以访问prometheus的端点,并可以使用curl尝试发送请求,获取默认的指标和由AutoConfiguration注册的指标。请注意,actuator的基本路径由management.endpoints.web.base-path定义,默认为/actuator。
$ curl http://localhost:8080/actuator/prometheus 2>/dev/null | head
# HELP tomcat_global_request_seconds
# TYPE tomcat_global_request_seconds summary
tomcat_global_request_seconds_count{name="http-nio-8080",} 4.0
tomcat_global_request_seconds_sum{name="http-nio-8080",} 0.597
# HELP tomcat_threads_config_max_threads
# TYPE tomcat_threads_config_max_threads gauge
tomcat_threads_config_max_threads{name="http-nio-8080",} 200.0
# HELP tomcat_sessions_active_current_sessions
# TYPE tomcat_sessions_active_current_sessions gauge
tomcat_sessions_active_current_sessions 0.0
添加设置以收集咖啡因的度量标准。
在application.yml中定义spring.cache.caffeine.spec: maximumSize=500,expireAfterAccess=600s,recordStats可以将recordStats参数放入spring.cache.caffeine.spec中。在指标收集方面,只需要recordStats即可,但其他可配置的值可以参考CaffeineSpec.java。
我原本以为会从这里开始取得…
在调用先前实现的/echo后,调用prometheus的端点。
$ curl http://localhost:8080/echo?value=test
test$
$ curl http://localhost:8080/actuator/prometheus 2>/dev/null | grep cache
# HELP tomcat_cache_access_total
# TYPE tomcat_cache_access_total counter
tomcat_cache_access_total 0.0
# HELP tomcat_cache_hit_total
# TYPE tomcat_cache_hit_total counter
tomcat_cache_hit_total 0.0
…请将以下内容用中文进行改写,只需要一种选项:
…
spring.cache.cache-names 的配置
看起来,根据CacheMetricsRegistrar的实现,如果不事先将静态使用的缓存cache的名称写在application.yml中,就无法被Micrometer注册。因此,与缓存相关的设置应该在application.yml中进行。
spring.cache:
cache-names: echo
caffeine.spec: maximumSize=500,expireAfterAccess=600s,recordStats
确保如此。再次确认后可获得。
]$ curl http://localhost:8080/actuator/prometheus 2>/dev/null | grep cache
# HELP cache_eviction_weight The sum of weights of evicted entries. This total does not include manual invalidations.
# TYPE cache_eviction_weight gauge
cache_eviction_weight{cache="echo",cacheManager="cacheManager",name="echo",} 0.0
# HELP cache_gets_total the number of times cache lookup methods have returned an uncached (newly loaded) value, or null
# TYPE cache_gets_total counter
cache_gets_total{cache="echo",cacheManager="cacheManager",name="echo",result="miss",} 1.0
cache_gets_total{cache="echo",cacheManager="cacheManager",name="echo",result="hit",} 0.0
# HELP tomcat_cache_hit_total
# TYPE tomcat_cache_hit_total counter
tomcat_cache_hit_total 0.0
# HELP cache_size The number of entries in this cache. This may be an approximation, depending on the type of cache.
# TYPE cache_size gauge
cache_size{cache="echo",cacheManager="cacheManager",name="echo",} 1.0
# HELP cache_evictions_total cache evictions
# TYPE cache_evictions_total counter
cache_evictions_total{cache="echo",cacheManager="cacheManager",name="echo",} 0.0
# HELP cache_puts_total The number of entries added to the cache
# TYPE cache_puts_total counter
cache_puts_total{cache="echo",cacheManager="cacheManager",name="echo",} 0.0
# HELP tomcat_cache_access_total
# TYPE tomcat_cache_access_total counter
tomcat_cache_access_total 0.0
我想要动态注册由@Cachable指定的缓存的指标。
使用@SpringCacheable指定的缓存名称写在spring.cache.cache-names中会变得琐碎和繁琐,而且当缓存数量增加时容易出现遗漏。如果想要实现这样的功能,虽然有些笨拙,但可以创建一个继承自CaffeineCacheManager的派生类,在CaffeineCache创建时将其注册到MeterRegistry中。(但不建议这样做…)
@RequiredArgsConstructor
public class InstrumentedCaffeineCacheManager extends CaffeineCacheManager {
private final MeterRegistry meterRegistry;
@Override
protected Cache<Object, Object> createNativeCaffeineCache(String name) {
Cache<Object, Object> nativeCache = super.createNativeCaffeineCache(name);
CaffeineCacheMetrics.monitor(meterRegistry, nativeCache, name, Collections.emptyList());
return nativeCache;
}
}
将此注册为Bean。但是,在CaffeineCacheConfiguration中,除了简单地生成Bean之外,还需要进行其他处理,因此进行拷贝。
@EnableConfigurationProperties(CacheProperties.class)
@EnableCaching // Application classからこちらに移動した
@Configuration
@RequiredArgsConstructor
public class CacheConfig {
private final MeterRegistry meterRegistry;
private final CacheProperties cacheProperties;
// CaffeineCacheConfigurationの実装をcopy
@Bean
public CaffeineCacheManager cacheManager() {
CaffeineCacheManager cacheManager = createCacheManager();
List<String> cacheNames = cacheProperties.getCacheNames();
if (!CollectionUtils.isEmpty(cacheNames)) {
cacheManager.setCacheNames(cacheNames);
}
return cacheManager;
}
// ここで独自CaffeineCacheManagerを生成
private CaffeineCacheManager createCacheManager() {
CaffeineCacheManager cacheManager = new InstrumentedCaffeineCacheManager(meterRegistry);
setCacheBuilder(cacheManager);
return cacheManager;
}
private void setCacheBuilder(CaffeineCacheManager cacheManager) {
String specification = cacheProperties.getCaffeine().getSpec();
if (StringUtils.hasText(specification)) {
cacheManager.setCacheSpecification(specification);
}
}
}
这样,即使不在application.yml中写入spring.cache.cache-names,也能够动态地注册带有@Cacheable标记的缓存的指标。