三种方法
expireAfterWrite:代表着写了之后多久过期。(上面列子就是这种方式)
expireAfterAccess: 代表着最后一次访问了之后多久过期。
expireAfter:在expireAfter中需要自己实现Expiry接口,这个接口支持create,update,以及access了之后多久过期。注意这个API和前面两个API是互斥的。这里和前面两个API不同的是,需要你告诉缓存框架,他应该在具体的某个时间过期,也就是通过前面的重写create,update,以及access的方法,获取具体的过期时间。
expireAfterWrite、expireAfter两个都可以做到写入一段时间后数据过期。但是此时过期都是在第二次查询时执行以下步骤:
1.确定此数据已过期;
2.查询新的数据;
3.删除老数据;
4.添加新数据。
此时的问题是:当内存中数据量很大且QPS较高时,程序需要耗时间去判断数据是否到期,查出新数据,删除老数据和填入新数据。此时会有大量的性能消耗,影响接口响应速度。
AsyncCache 等异步方法也是同样的原理。所以当本地缓存的缓存数据量过大时应充分考虑此种情况避免接口响应时间下降。
解决此种问题的方法是增加一个专用线程池来淘汰过期数据:
方案一
.scheduler(Scheduler.systemScheduler()) 使用系统线程,此种方法在大流量时会影响系统运行状态 慎用 方案二 .scheduler(Scheduler.forScheduledExecutorService( newScheduledThreadPool(config.getIntProperty(MAX_CLEAN_THREAD_SIZE, 3))))
自定义线程。
单机QPS1000,平均接口耗时不到1MS。经过测试后发现,哪种情况都不能满足需求。caffeine的本地缓存方案不适合写入较多的场景(话说,没有哪几种本地缓存方案是优先考虑写入数据吧,都是先考虑查询)。
故方案设计改为,放弃本地缓存的命中率为代价,改为少部分流量的数据存入本地缓存。