我们栖息的桌子飘向麦地
我们安坐的灯火涌向星辰
某些热点数据在短时间内可能会被成千上万次访问,在使用Redis作为缓存的前面可以使用本地缓存(JAVA虚拟机JVM缓存)作为一级缓存,把数据放到本地内存,减少服务端到Redis取数据的网络开销,减少RedisServer压力,进一步提高性能。
本次场景是秒杀模块使用缓存对不可变的商品信息等进行预热。
我们可以使用google的guava cache组件实现本地缓存,之所以选择guava是因为它可以控制key和value的大小和超时时间,可以配置LRU策略且guava是线程安全的。
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>18.0</version>
</dependency>
public interface CacheService {
//存方法
void setCommonCache(String key,Object value);
//取方法
Object getFromCommonCache(String key);
//清除指定缓存
void removeCommonCache(String key);
//清除所有缓存
void removeAllCommonCache();
//清除多个缓存
void removeAssignCommonCache(String... keys);
}
@Service
public class CacheServerImpl implements CacheService {
private Cache<String, Object> commonCache = null;
//@PostConstruct---Spring会在bean加载的时候执行这个方法
@PostConstruct
public void init() {
commonCache = CacheBuilder.newBuilder()
//设置缓存容量的初始容量为10
.initialCapacity(10)
//设置缓存中最大可以存储100个key,超过100个之后会按照LRU的策略移除缓存项
.maximumSize(100)
//设置写缓存后多少秒过期
.expireAfterWrite(60, TimeUnit.SECONDS).build();
}
@Override
public void setCommonCache(String key, Object value) {
commonCache.put(key, value);
}
@Override
public Object getFromCommonCache(String key) {
//存在返回,不存在返回null
return commonCache.getIfPresent(key);
}
@Override
public void removeCommonCache(String key) {
//清除指定缓存
commonCache.invalidate(key);
}
@Override
public void removeAllCommonCache() {
//清除所有缓存
commonCache.invalidateAll();
}
@Override
public void removeAssignCommonCache(String... keys) {
//清除多个key缓存
commonCache.invalidateAll(Collections.singleton(keys));
}
}
其中需要注意的是删除缓存的问题
如果是在分布式环境下,nginx负载均衡访问到每个项目对应的虚拟机,这样每个虚拟机都会进行本地热点缓存,而如果单纯的调用其中一个remove cache方法,只是对应的这个虚拟机的本地缓存被清掉,其他虚拟机的缓存还是存在的,这时候当然有其他的解决办法,比如使用消息队列MQ,但无疑会有点违背提高性能,提高响应速度的需求。
因此建议使用热点缓存的数据具有不可变性,持久性,也可以把热点缓存的失效时间设置短点,避免出现数据不一致性,安全问题。
文章持续更新,可以微信搜索「 绅堂Style 」第一时间阅读,回复【资料】有我准备的面试题笔记。
GitHub https://github.com/dtt11111/Nodes 有总结面试完整考点、资料以及我的系列文章。欢迎Star。