本地缓存
(1)将数据缓存在应用服务器上,性能最好。
(2)常用缓存工具:Ehcache、Guava、Caffein等。
分布式缓存
(1)将数据缓存在NoSQL数据库上,跨服务器。
(2)常用缓存工具:MemCache、Redis等。
多级缓存
(1)>一级缓存(本地缓存)>二级缓存(分布式缓存)>DB
(2)避免缓存雪崩(缓存失效,大量请求直达DB,提高系统的可用性。
本地缓存和redis缓存的示意图(本地缓存更普适,效率更高)
在github上搜Caffeine,第一个就是。在mvn库里搜caffeine,把com.github.ben-manes.caffeine粘贴到pom.xml。在application-properties里添加
# caffeine
# 15页,不一定是前15页,例如缓存热门帖子的15页,没必要缓存所有(浪费内存空间)
caffeine.posts.max-size=15
# 3分钟过期
caffeine.posts.expire-seconds=180
在DiscussPostService类里,添加
@Value("${caffeine.posts.max-size}")
private int maxSize;
@Value("${caffeine.posts.expire-seconds}")
private int expireSeconds;
//Caffeine核心接口:Cache,子接口LoadingCache(排队等),AsyncLoadingCache(异步,支持并发,不着急返回)
//帖子列表缓存
private LoadingCache<String,List<DiscussPost>> postListCache;
// 帖子总数缓存
private LoadingCache<Integer, Integer> postRowsCache;
@PostConstruct
public void init(){
//初始化帖子列表缓存
postListCache = Caffeine.newBuilder() //先用caffine
.maximumSize(maxSize)
.expireAfterWrite(expireSeconds, TimeUnit.SECONDS)
.build(new CacheLoader<String, List<DiscussPost>>() {
@Nullable
@Override
public List<DiscussPost> load(@NonNull String key) throws Exception {
if(key==null||key.length()==0){
throw new IllegalArgumentException("参数错误!");
}
String[] params = key.split(":");
if(params==null||params.length!=2){
throw new IllegalArgumentException("参数错误!");
}
int offset = Integer.valueOf(params[0]);
int limit = Integer.valueOf(params[1]);
//若有二级缓存:Redis -> mysql,而这里是直接就访问数据库了
logger.debug("load post list from DB.");
return discussPostMapper.selectDiscussPosts(0,offset,limit,1);
//只缓存不针对用户的所有帖子,且是“最热”模式
}
});
//初始化帖子总数缓存
postRowsCache = Caffeine.newBuilder()
.maximumSize(maxSize)
.expireAfterWrite(expireSeconds, TimeUnit.SECONDS)
.build(new CacheLoader<Integer,Integer>() {
@Nullable
@Override
public Integer load(@NonNull Integer key) throws Exception {
logger.debug("load post rows from DB.");
return discussPostMapper.selectDiscussPostRows(key);
}
});
}
并修改findDiscussPosts和findDiscussPostRows方法为
public List<DiscussPost> findDiscussPosts(int userId,int offset,int limit,int orderMode) {
if(userId==0&&orderMode==1){
return postListCache.get(offset+":"+limit);
}
logger.debug("load post list from DB.");
return discussPostMapper.selectDiscussPosts(userId,offset,limit,orderMode);
}
public int findDiscussPostRows(int userId) {
if(userId==0){
return postRowsCache.get(userId);
}
logger.debug("load post rows from DB.");
return discussPostMapper.selectDiscussPostRows(userId);
}
新建 CaffeineTests类,
@Test
public void initDataForTest(){ //这个先初始化好
for(int i=0;i<300000;i++){
DiscussPost post = new DiscussPost();
post.setUserId(111);
post.setTitle("互联网求职暖春计划");
post.setContent("今年的就业形势,确实不容乐观,21届要加油啊!");
post.setCreateTime(new Date());
post.setScore(Math.random()*2000);
postService.addDiscussPost(post);
}
}
@Test
public void testCache(){
System.out.println(postService.findDiscussPosts(0,0,10,1));
System.out.println(postService.findDiscussPosts(0,0,10,1));
System.out.println(postService.findDiscussPosts(0,0,10,1));
System.out.println(postService.findDiscussPosts(0,0,10,0));//不走缓存
}
到jmeter.apache.org官网下载JMeter二进制包,解压缩即能用。进入安装目录的bin,双击jmeter.bat即能使用。
首先添加线程组
设置线程组的名字、线程数量、是否无限循环、明确线程生命时间。
添加取样器
设置取样器
添加统一随机定时器
设置随机定时器的随机时间间隔为1000(即0~1000)
添加聚合报告监听器
点击开始,弹出窗口中设置聚合报告的保存路径和文件名字,开始测试。看到不加Caffeine缓存访问首页的吞吐量为12.9/sec。
把caffeine加上,先清理掉上次的聚合报告,再次点击绿色箭头开始测试。
可以看到,把caffeine加上之后首页的吞吐量为193.9/sec,性能提升不少。另外,对于性能欠佳的服务器,因为访问请求压力大,响应不过来的时候,可能会报异常。