Spring Cache监控配置与使用规范的建议
作者:仍在奔跑的男人
建议
- 程序中使用的缓存,请在cache-names里指明,如此,可以通过配置文件来明白程序中用到了哪些spring cache。
- 请尽量对每一个cache分别设置缓存策略,因为不用的cache其使用的场景与缓存对象大小都不一样。分别设置缓存请使用common-spring-cache-configuere。默认spring不支持。
- 缓存策略建议阅读缓存策略最佳配置
- Cacheable的sync无特殊情况都设置为true,这样,取数据时有类似LoadingCache的效果,同时利用computeIfAbsent方法实现了线程安全,也防止雪崩问题。
spring boot 2.x 监控设置
spring boot从1.x升级到2.x之后,原先在spring-boot-actuator里默认的一些metrics不在自动生效,而是将这些metrics的功能从spring-boot-actuator迁移到了micrometer.io项目里,作为一个独立的微服务监控项目维护。
为此,为了使spring cache的相关metrics生效,需要进行如下配置:
1.在management.endpoints.web里添加caches与metrics两个接口暴露
默认只暴露health、info。
management: endpoints: web: exposure: include: info, health, metrics, caches
2.在spring.cache里指定cache-names的配置
spring: cache: cache-names: books, rooms
如果不指定cache-names,spring cache metrics是不会生效的,因为spring是在加载的过程中来确认需要对哪些cache来监控,像Cacheable之类需要动态加入的cache,spring在加载过程中无法感知到。
3.对cache provider启动调用记录功能
以caffeine为例,在spec中加入recordStats,如下:
spring: cache: cache-names: books, rooms caffeine: spec: recordStats
4.相关url
- /actuator/caches 获取cache manager内的cache实例
- /actuator/metrics/cache.gets 获取cache内缓存对象的情况,包括hit/miss的情况,具体参考tags drillDown的使用方式https://docs.spring.io/spring-boot/docs/2.0.0.BUILD-SNAPSHOT/actuator-
- api//html/#metrics-drilling-down
- /actuator/metrics/cache.puts
- /actuator/metrics/cache.eviction
5.举例
curl localhost:8080/actuator/metrics/ 访问所有支持的metrics
{ "names":[ "jvm.memory.max", "jvm.threads.states", "process.files.max", "jvm.gc.memory.promoted", "cache.puts", "cache.size", "cache.evictions", "system.load.average.1m", "jvm.memory.used", "jvm.gc.max.data.size", "jvm.gc.pause", "jvm.memory.committed", "system.cpu.count", "logback.events", "http.server.requests", "tomcat.global.sent", "jvm.buffer.memory.used", "cache.eviction.weight", "tomcat.sessions.created", "jvm.threads.daemon", "system.cpu.usage", "jvm.gc.memory.allocated", "tomcat.global.request.max", "tomcat.global.request", "cache.gets", "tomcat.sessions.expired", "jvm.threads.live", "jvm.threads.peak", "tomcat.global.received", "process.uptime", "tomcat.sessions.rejected", "process.cpu.usage", "tomcat.threads.config.max", "jvm.classes.loaded", "jvm.classes.unloaded", "tomcat.global.error", "tomcat.sessions.active.current", "tomcat.sessions.alive.max", "jvm.gc.live.data.size", "tomcat.threads.current", "process.files.open", "jvm.buffer.count", "jvm.buffer.total.capacity", "tomcat.sessions.active.max", "tomcat.threads.busy", "process.start.time" ] }
curl localhost:8080/actuator/metrics/cache.gets 访问缓存get情况
{ "name":"cache.gets", "description":"The number of times cache lookup methods have returned a cached value.", "baseUnit":null, "measurements":[ { "statistic":"COUNT", "value":0 } ], "availableTags":[ { "tag":"result", "values":[ "hit", "miss" ] }, { "tag":"cache", "values":[ "rooms", "books" ] }, { "tag":"name", "values":[ "rooms", "books" ] }, { "tag":"cacheManager", "values":[ "cacheManager" ] } ] }
curl “localhost:8080/actuator/metrics/cache.gets?tag=result:hit&tag=cache:books” 获取名为books的cache的命中次数
{ "name":"cache.gets", "description":"The number of times cache lookup methods have returned a cached value.", "baseUnit":null, "measurements":[ { "statistic":"COUNT", "value":0 } ], "availableTags":[ { "tag":"name", "values":[ "books" ] }, { "tag":"cacheManager", "values":[ "cacheManager" ] } ] }
定制化配置
默认coffeine.spec的配置是对全体配置的,如果要分开配置可以自定义实现CacheManager,参见common-spring-cache-configurer. 使用时,直接引入该jar包即可。
<dependency> <groupId>com.iqiyi.intl.common</groupId> <artifactId>common-spring-cache-configurer</artifactId> <version>1.4.0-SNAPSHOT</version> </dependency>
使用配置如下(替换掉原先的spring.cache的配置):
cache.items: - name: books spec: recordStats,softValues, maximumSize=1,expireAfterWrite=100s - name: rooms spec: expireAfterWrite=50s, maximumSize=10000
CacheManager自定义实现如下:
@Configuration @ConditionalOnClass({ Caffeine.class, CaffeineCacheManager.class }) @EnableConfigurationProperties(CacheProperties.class) public class AutoCustomizedCaffeineCacheConfigurer { @Autowired private CacheProperties cacheProperties; @Bean @Primary public CacheManager caffeineCacheManager() { SimpleCacheManager cacheManager = new SimpleCacheManager(); List<CaffeineCache> caches = cacheProperties.getItems().stream() .map(item -> new CaffeineCache(item.getName(), Caffeine.from(item.getSpec()).build())) .collect(Collectors.toList()); cacheManager.setCaches(caches); return cacheManager; } }
缓存策略最佳配置
- 设置softvalues, 当JVM内存耗尽时,会触发GC,回收这些cache的内存,防止OOM。
- 设置size或weight,限定缓存的最大占用空间,保证系统正常运行。
- 设置ttl/tti,设置过期时间,根据业务实际场景决定时长。
可以这么理解:
首先通过size或者weight来确定缓存总共占用的最大空间,softValues是用于兜底策略,防止万一size/weight设置的不正确,导致的OOM。对于ttl/tti,则是针对业务场景,来保证数据的时效性,用于程序运行的正确性。
举例如下:
cache.items: - name: books spec: softValues, maximumSize=1,expireAfterWrite=100s
说明:
- 所有的配置都是针对每一个cache生效的,对于cacheManager, 也就是会有多个cache,所以占用的内容空间也会增加多份。所以cache不能设置过大。
- ttl/tti说明,ttl (time to live), 即expireAfterWrite;tti (time to idle), 即expireAfterRead, 如果设置tti,则意味着,只要这个key直接被读到,则缓存会一直不失效,所以请慎用tti。
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。