一、缓存简介
-
什么是缓存
-
程序经常要调⽤的对象存在内存中,⽅便其使⽤时可以快速调⽤,不必去数据库或者其他持久化设备中查询,主要就是提⾼性能;
-
DNS缓存、前端缓存、代理服务器缓存Nginx、应⽤程序缓存(本地缓存、分布式缓存)、数据库缓存。
-
-
分布式缓存
-
与应⽤分离的缓存组件或服务,与本地应⽤隔离⼀个独⽴的应⽤,多个应⽤可直接的共享缓存;
-
常⻅的分布式缓存 Redis、Memcached等。
-
-
本地缓存
-
和业务程序⼀起的缓存,例如myabtis的⼀级或者⼆级缓存,本地缓存⾃然是最快的,但是不能在多个节点共享
-
常⻅的本地缓存:ssm基础课程myabtis ⼀级缓存、mybatis⼆级缓存;框架本身的缓存; redis本地单机服务;ehchche;guava cache、Caffeine等
-
-
选择本地缓存和分布式缓存
-
和业务数据结合去选择;
-
⾼并发项⽬⾥⾯⼀般都是有本地缓存和分布式缓存共同存在的。
-
二、Guava使用
Guava Cache 是Google Fuava
中的一个内存缓存模块,用于将数据缓存到JVM内存中。
-
添加依赖
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>19.0</version>
</dependency> -
封装api
@Component
public class BaseCache {
// 创建10分钟的缓存容器
private Cache<String,Object> tenMinuteCache = CacheBuilder.newBuilder()
// 初始缓存值
.initialCapacity(10)
// 最大缓存值
.maximumSize(100)
// 最大线程
.concurrencyLevel(5)
// 过期时间,10分钟
.expireAfterWrite(600, TimeUnit.SECONDS)
// 统计缓存命中率
.recordStats()
.build();
// 创建1小时的缓存容器
private Cache<String,Object> oneHourCache = CacheBuilder.newBuilder()
.initialCapacity(10)
.maximumSize(100)
.concurrencyLevel(5)
.expireAfterWrite(600, TimeUnit.SECONDS)
.recordStats()
.build();
public Cache<String, Object> getTenMinuteCache() {
return tenMinuteCache;
}
public void setTenMinuteCache(Cache<String, Object> tenMinuteCache) {
this.tenMinuteCache = tenMinuteCache;
}
public Cache<String, Object> getOneHourCache() {
return oneHourCache;
}
public void setOneHourCache(Cache<String, Object> oneHourCache) {
this.oneHourCache = oneHourCache;
}
} -
开发缓存key管理类
/**
* 缓存key管理类
*/
public class CacheKeyManager {
/**
* 首页轮播图缓存
*/
public static final String INDEX_BANNER_LIST = "index:banner:list";
/**
* 首页视频列表缓存
*/
public static final String INDEX_VIDEO_LIST = "index:video:list";
/**
* 视频详情缓存,视频id:%s
*/
public static final String VIDEO_DETAIL = "video:detail:%s";
} -
缓存功能调用
public List<VideoBanner> listBanner() {
try {
Object cacheObj = baseCache.getTenMinuteCache().get(CacheKeyManager.INDEX_BANNER_LIST, () -> {
List<VideoBanner> bannerList = videoMapper.listVideoBanner();
return bannerList;
});
if(cacheObj instanceof List){
List<VideoBanner> bannerList = (List<VideoBanner>)cacheObj;
return bannerList;
}
} catch (ExecutionException e) {
e.printStackTrace();
}
return null;
}
三、性能提升
我们对次方法使用前后进行压力测试,比较前后qps。
-
压测工具:Jmeter5.x
-
使用前,线程数:200,循环次数:1000,吞吐量:4823.8/s
-
使用后,线程数:200,循环次数:1000,吞吐量:22575.9/s