解析springboot整合谷歌开源缓存框架Guava Cache原理

作者:sjgeng111 时间:2023-11-07 13:24:23 

Guava Cache:⾕歌开源缓存框架

Guava Cache是在内存中缓存数据,相比较于数据库或redis存储,访问内存中的数据会更加高效。Guava官网介绍,下面的这几种情况可以考虑使用Guava Cache:

愿意消耗一些内存空间来提升速度。

预料到某些键会被多次查询。

缓存中存放的数据总量不会超出内存容量。

github地址:https://github.com/google/guava/wiki/CachesExplained

解析springboot整合谷歌开源缓存框架Guava Cache原理

全内存的本地缓存实现,查询数据时先根据自定义索引判断Guava Cache中是否存在该数据,如果存在就从Guava Cache中取,不存在就从数据库中查询,再保存到Guava Cache中,减少数据库查询的压力

⾼性能且功能丰富

线程安全,操作简单 (底层实现机制类似ConcurrentMap)

Guava Cache使用

  •  添加依赖


<!--guava依赖包-->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>19.0</version>
</dependency>
  • 封装api工具类:


@Component
public class BaseCache {
   private Cache<String,Object> tenMinuteCache = CacheBuilder.newBuilder()
           //设置缓存初始大小,应该合理设置,后续会扩容
           .initialCapacity(10)
           //最大值
           .maximumSize(100)
           //并发数设置
           .concurrencyLevel(5)
           //缓存过期时间,写入后10分钟过期
           .expireAfterWrite(600,TimeUnit.SECONDS)
           //统计缓存命中率
           .recordStats()
           .build();

private Cache<String,Object> oneHourCache = CacheBuilder.newBuilder()
           //设置缓存初始大小,应该合理设置,后续会扩容
           .initialCapacity(30)
           //最大值
           .maximumSize(100)
           //并发数设置
           .concurrencyLevel(5)
           //缓存过期时间,写入后1小时 过期
           .expireAfterWrite(3600,TimeUnit.SECONDS)
           //统计缓存命中率
           .recordStats()
           .build();

public Cache<String, Object> getOneHourCache() {
       return oneHourCache;
   }
   public void setOneHourCache(Cache<String, Object> oneHourCache) {
       this.oneHourCache = oneHourCache;
   }
   public Cache<String, Object> getTenMinuteCache() {
       return tenMinuteCache;
   }
   public void setTenMinuteCache(Cache<String, Object> tenMinuteCache) {
       this.tenMinuteCache = tenMinuteCache;
   }
}
  • 实际开发中使用:(查询数据时先根据自定义索引判断Guava Cache中是否存在该数据,如果存在就从Guava Cache中取,不存在就从数据库中查询,再保存到Guava Cache中)

自定义索引:


/**
* 缓存key管理类
*/
public class CacheKeyManager {

/**
    * 首页轮播图缓存key
    */
   public static final String INDEX_BANNER_KEY = "index:banner:list";

/**
    * 首页视频列表缓存key
    */
   public static final String INDEX_VIDEL_LIST = "index:video:list";

/**
    * 视频详情缓存key, %s是视频id
    */
   public static final String VIDEO_DETAIL = "video:detail:%s";

}

如果存在就从Guava Cache中取,不存在就从数据库中查询,再保存到Guava Cache中


@Service
public class VideoServiceImpl implements VideoService {

@Autowired
   private VideoMapper videoMapper;
   @Autowired
   private BaseCache baseCache;
   @Override
   public List<Video> listVideo() {
       try{
         Object cacheObj =  baseCache.getTenMinuteCache().get(CacheKeyManager.INDEX_VIDEL_LIST,()->{
               List<Video> videoList = videoMapper.listVideo();
               return videoList;
           });
         if(cacheObj instanceof List){
             List<Video> videoList = (List<Video>)cacheObj;
             return videoList;
         }
       }catch (Exception e){
           e.printStackTrace();
       }
       //可以返回兜底数据,业务系统降级-》SpringCloud专题课程
       return null;
   }

@Override
   publc List<VideoBanner> listBanner() {
       try{
           Object cacheObj =  baseCache.getTenMinuteCache().get(CacheKeyManager.INDEX_BANNER_KEY, ()->{
               List<VideoBanner> bannerList =  videoMapper.listVideoBanner();
               System.out.println("从数据库里面找轮播图列表");
               return bannerList;
           });
           if(cacheObj instanceof List){
               List<VideoBanner> bannerList = (List<VideoBanner>)cacheObj;
               return bannerList;
           }
       }catch (Exception e){
           e.printStackTrace();
       }
       return null;
   }

@Override
   public Video findDetailById(int videoId) {
       //单独构建一个缓存key,每个视频的key是不一样的
       String videoCacheKey = String.format(CacheKeyManager.VIDEO_DETAIL,videoId);
       try{
        Object cacheObject = baseCache.getOneHourCache().get( videoCacheKey, ()->{
               // 需要使用mybaits关联复杂查询
               Video video = videoMapper.findDetailById(videoId);
               return video;
           });

if(cacheObject instanceof Video){
            Video video = (Video)cacheObject;
            return video;
        }
       }catch (Exception e){
           e.printStackTrace();
       }
       return null;
   }
}

使用压测⼯具Jmeter5.x进行接口压力测试:

压测⼯具本地快速安装Jmeter5.x

简介:GUI图形界⾯的安装 Jmeter5.x

需要安装JDK8 以上

建议安装JDK环境,虽然JRE也可以,但是压测https需要JDK⾥⾯的 keytool⼯具

快速下载:https://jmeter.apache.org/download_jmeter.cgi

⽂档地址:http://jmeter.apache.org/usermanual/get-started.html

解析springboot整合谷歌开源缓存框架Guava Cache原理

解jmeter解压⽂件⾥⾯的各个⽬录:

bin:核⼼可执⾏⽂件,包含配置
jmeter.bat: windows启动⽂件(window系统⼀定要配置显示⽂件拓展名)
jmeter: mac或者linux启动⽂件
jmeter-server:mac或者Liunx分布式压测使⽤的启动⽂件
jmeter-server.bat:window分布式压测使⽤的启动⽂件
jmeter.properties: 核⼼配置⽂件
extras:插件拓展的包
lib:核⼼的依赖包

Jmeter语⾔版本中英⽂切换

控制台修改 menu -> options -> choose language

配置⽂件修改

bin⽬录 -> jmeter.properties

默认 #language=en

改为 language=zh_CN

解析springboot整合谷歌开源缓存框架Guava Cache原理

新增聚合报告:线程组->添加-> * ->聚合报告(Aggregate Report)

解析springboot整合谷歌开源缓存框架Guava Cache原理 

解析springboot整合谷歌开源缓存框架Guava Cache原理 

解析springboot整合谷歌开源缓存框架Guava Cache原理 

解析springboot整合谷歌开源缓存框架Guava Cache原理

解析springboot整合谷歌开源缓存框架Guava Cache原理 

解析springboot整合谷歌开源缓存框架Guava Cache原理

lable: sampler的名称
Samples: ⼀共发出去多少请求,例如10个⽤户,循环10次,则是 100
Average: 平均响应时间
Median: 中位数,也就是 50% ⽤户的响应时间
90% Line : 90% ⽤户的响应不会超过该时间 (90% of the samples took no more than
this time. The remaining samples at least as long as this)
95% Line : 95% ⽤户的响应不会超过该时间
99% Line : 99% ⽤户的响应不会超过该时间
min : 最⼩响应时间
max : 最⼤响应时间
Error%:错误的请求的数量/请求的总数
Throughput: 吞吐量——默认情况下表示每秒完成的请求数(Request per Second) 可类⽐为
qps、tps
KB/Sec: 每秒接收数据量

启⽤缓存 压测热点数据接接⼝Throughput: 14000:

解析springboot整合谷歌开源缓存框架Guava Cache原理 

解析springboot整合谷歌开源缓存框架Guava Cache原理

不启⽤缓存 压测热点数据接⼝

视频轮播图接⼝ Throughput : 2700

解析springboot整合谷歌开源缓存框架Guava Cache原理 

解析springboot整合谷歌开源缓存框架Guava Cache原理

当数据访问量较大时,比如主页信息等,可以考虑使用Guava Cache,可以将程序频繁用到的少量数据存储到Guava Cache中,以改善程序性能!

来源:https://blog.csdn.net/sjgllllll/article/details/119709624

标签:springboot,Guava,Cache
0
投稿

猜你喜欢

  • c# 读取XML文件的示例

    2023-11-04 00:51:17
  • 从零开始Java实现Parser Combinator

    2023-06-18 18:52:04
  • Android中View的炸裂特效实现方法详解

    2022-07-25 17:59:28
  • Spring钩子接口汇总分析使用示例

    2022-09-24 23:29:56
  • MyBatis批量插入(insert)数据操作

    2023-09-21 00:03:54
  • 关于MyBatis模糊查询的几种实现方式

    2023-05-09 04:23:12
  • Java求最小生成树的两种算法详解

    2023-11-10 07:21:24
  • 关于Unity C# Mathf.Abs()取绝对值性能测试详解

    2022-01-28 04:47:58
  • C#执行存储过程并将结果填充到GridView的方法

    2022-08-08 06:25:38
  • Android实战教程第九篇之短信高效备份

    2022-02-14 12:59:20
  • 聊聊Springboot2.x的session和cookie有效期

    2022-09-11 10:17:20
  • Spring Boot插件spring tool suite安装及使用详解

    2021-12-15 03:29:23
  • Java递归遍历树形结构的实现代码

    2021-11-15 19:51:59
  • 在Flutter中制作翻转卡片动画的完整实例代码

    2023-06-23 23:31:21
  • Kafka常用命令之kafka-console-consumer.sh解读

    2022-06-11 00:20:32
  • Maven项目读取resources文件路径问题解决方案

    2023-04-21 15:05:11
  • Android 操作excel功能实例代码

    2021-07-02 23:48:23
  • Java基础知识之StringWriter流的使用

    2023-01-19 00:47:52
  • rocketmq client 日志的问题处理方式

    2023-07-15 08:10:32
  • C# 泛型集合的自定义类型排序的实现

    2022-11-18 20:35:32
  • asp之家 软件编程 m.aspxhome.com