首页 > 其他分享 >多级缓存

多级缓存

时间:2023-11-10 23:32:23浏览次数:30  
标签:cache Cache Caffeine gf 多级 缓存 id

传统缓存的问题

传统的缓存策略一般是请求到达Tomcat后,先查询Redis,如果未命中则查询数据库,存在下面的问题:

●请求要经过Tomcat处理,Tomcat的性能成为整个系统的瓶颈

●Redis缓存失效时,会对数据库产生冲击

多级缓存_数据库

多级缓存方案

多级缓存就是充分利用请求处理的每个环节,分别添加缓存,减轻Tomcat压力,提升服务性能:

多级缓存_多级缓存_02

JVM进程缓存

本地进程缓存

缓存在日常开发中启动至关重要的作用,由于是存储在内存中,数据的读取速度是非常快的,能大量减少对数据库的访问,减少数据库的压力。我们把缓存分为两类:

●分布式缓存,例如Redis:

优点:存储容量更大、可靠性更好、可以在集群间共享

缺点:访问缓存有网络开销

场景:缓存数据量较大、可靠性要求较高、需要在集群间共享

●进程本地缓存,例如HashMap、GuavaCache:

优点:读取本地内存,没有网络开销,速度更快

缺点:存储容量有限、可靠性较低、无法共享

场景:性能要求较高,缓存数据量较小

Caffeine

Caffeine是一个基于Java8开发的,提供了近乎最佳命中率的高性能的本地缓存库。目前Spring内部的缓存使用的就是Caffeine。GitHub地址: https://github.com/ben-manes/caffeine/wiki/Home-zh-CN

多级缓存_多级缓存_03

Caffeine简单测试
public class CaffeineTest {

    /*
      基本用法测试
     */
    @Test
    void testBasicOps() {
        // 创建缓存对象
        Cache<String, String> cache = Caffeine.newBuilder().build();

        // 存数据
        cache.put("gf", "迪丽热巴");

        // 取数据,不存在则返回null
        String gf = cache.getIfPresent("gf");
        System.out.println("gf = " + gf);

        // 取数据,不存在则去数据库查询
        String defaultGF = cache.get("defaultGF", key -> {
            // 这里可以去数据库根据 key查询value
            return "柳岩";
        });
        System.out.println("defaultGF = " + defaultGF);
    }

    /*
     基于大小设置驱逐策略:
     */
    @Test
    void testEvictByNum() throws InterruptedException {
        // 创建缓存对象
        Cache<String, String> cache = Caffeine.newBuilder()
        // 设置缓存大小上限为 1
        .maximumSize(1)
        .build();
        // 存数据
        cache.put("gf1", "柳岩");
        cache.put("gf2", "范冰冰");
        cache.put("gf3", "迪丽热巴");
        // 延迟10ms,给清理线程一点时间
        Thread.sleep(10L);
        // 获取数据
        System.out.println("gf1: " + cache.getIfPresent("gf1"));
        System.out.println("gf2: " + cache.getIfPresent("gf2"));
        System.out.println("gf3: " + cache.getIfPresent("gf3"));
    }

    /*
     基于时间设置驱逐策略:
     */
    @Test
    void testEvictByTime() throws InterruptedException {
        // 创建缓存对象
        Cache<String, String> cache = Caffeine.newBuilder()
        .expireAfterWrite(Duration.ofSeconds(1)) // 设置缓存有效期为 10 秒
        .build();
        // 存数据
        cache.put("gf", "柳岩");
        // 获取数据
        System.out.println("gf: " + cache.getIfPresent("gf"));
        // 休眠一会儿
        Thread.sleep(1200L);
        System.out.println("gf: " + cache.getIfPresent("gf"));
    }
}
Caffeine提供了三种缓存驱逐策略:

●基于容量:设置缓存的数量.上限

//创建缓存对象
Cache<String, String> cache = Caffeine .newBuilder()
. maximumSize(1) //设置缓存大小上限为1
. build() ;

●基于时间:设置缓存的有效时间

//创建缓存对象
Cache<String,String> cache = Caffeine .newBuilder()
. expireAfterWrite (Durati on. ofSeconds(10)) //设置缓存有效期为10秒,从最后一次写入开始计时
.build() ;

●基于引用:设置缓存为软引用或弱引用,利用GC来回收缓存数据。性能较差,不建议使用。

在默认情况下,当一个缓存元素过期的时候,Caffeine不会 自动立即将其清理和驱逐。而是在一-次读或写操作后, 或者在空闲时间完成对失效数据的驱逐。

案例

多级缓存_redis_04

添加缓存配置类

Configuration
public class CacheConfig {

    /**
     * 创建一个缓存对象,用于存储商品信息
     * 缓存初始容量为100,最大容量为10000
     *
     * @return 返回Cache<Long, Item>类型的缓存对象
     */
    @Bean
    public Cache<Long, Item> itemCache() {
        return Caffeine.newBuilder()
        .initialCapacity(100)
        .maximumSize(10_000)
        .build();
    }

    /**
     * 创建一个缓存对象,用于存储商品库存信息
     * 缓存初始容量为100,最大容量为10000
     *
     * @return 返回Cache<Long, ItemStock>类型的缓存对象
     */
    @Bean
    public Cache<Long, ItemStock> stockCache() {
        return Caffeine.newBuilder()
        .initialCapacity(100)
        .maximumSize(10_000)
        .build();
    }
}

测试代码

@Autowired
private Cache<Long, Item> itemCache;

@Autowired
private Cache<Long, ItemStock> stockCache;

@GetMapping("/{id}")
public Item findById(@PathVariable("id") Long id) {
    return itemCache.get(id, key -> itemService.query()
                         .ne("status", 3).eq("id", key)
                         .one());
}

@GetMapping("/stock/{id}")
public ItemStock findStockById(@PathVariable("id") Long id) {
    return stockCache.get(id, key -> stockService.getById(key));
}

第一次查询访问了数据库

多级缓存_代码优化_05

第二次查询没有访问数据库

多级缓存_代码优化_06

多级缓存_代码优化_07

标签:cache,Cache,Caffeine,gf,多级,缓存,id
From: https://blog.51cto.com/AmbitionGarden/8310227

相关文章

  • 文件缓存的读写
     文件系统的读写,其实就是调用系统函数read和write。下面的代码就是read和write的系统调用,在内核里面的定义。SYSCALL_DEFINE3(read,unsignedint,fd,char__user*,buf,size_t,count){structfdf=fdget_pos(fd);......loff_tpos=file_pos_read(f.file)......
  • ubuntu 20.04运行内存(缓存)定时清理
    ubuntu 20.04运行内存(缓存)定时清理数据处理过程,buffer/cache占用过大,降低了运行速度解决方法定时释放缓存缓存释放脚本vimclear_caches.sh输入echo"开始清除缓存"sync;sync;syncsleep20echo1>/proc/sys/vm/drop_cachesecho2>/proc/sys/vm/drop_cachesecho......
  • linux内核 快速分片,技术|Linux slabtop命令——显示内核片缓存信息
    Linux内核需要为临时对象如任务或者设备结构和节点分配内存,缓存分配器管理着这些类型对象的缓存。现代Linux内核部署了该缓存分配器以持有缓存,称之为片。不同类型的片缓存由片分配器维护。本文集中讨论slabtop命令,该命令显示了实时内核片缓存信息。1.命令用法:该命令用起来很简单......
  • c# webapi swagger Area 多级层次分组 添加header参数
    nuget安装Swashbuckle安装完成后会在App_Start中生成SwaggerConfig.cs 项目右键属性生成xml文件 在SwaggerConfig中的Register中进行配置//在内部的GlobalConfiguration.Configuration.EnableSwagger中进行配置c.SingleApiVersion("v1","API");varbaseDiretory=S......
  • 智慧工地平台源码:支持PC端、手机端,支持项目级、公司级、集团级多级权限划分,
    智慧工地管理平台实现对人员管理、施工进度、安全管理、材料管理、设备管理、环境监测等方面的实时监控和管理,提高施工效率和质量,降低安全风险和环境污染。智慧工地平台支持项目级、公司级、集团级多级权限划分,可根据企业的组织架构进行项目权限、功能权限、数据权限设定。支持PC端......
  • Spring 缓存注解这样用,太香了!
    作者最近在开发公司项目时使用到Redis缓存,并在翻看前人代码时,看到了一种关于@Cacheable注解的自定义缓存有效期的解决方案,感觉比较实用,因此作者自己拓展完善了一番后分享给各位。Spring缓存常规配置SpringCache框架给我们提供了@Cacheable注解用于缓存方法返回内容。但......
  • Keepalived 提高吞吐量、负载均衡 ip_hash、负载均衡 url_hash 与 least_conn、Nginx
    Keepalived提高吞吐量keepalived:设置长连接处理的数量proxy_http_version:设置长连接http版本为1.1proxy_set_header:清除connectionheader信息upstreamtomcats{ #server192.168.1.173:8080max_fails=2fail_timeout=1s; server192.168.1.190:8080; #server......
  • 小景的Dba之路--压力测试和Oracle数据库缓存
    小景最近在做系统查询接口的压测相关的工作,其中涉及到了查询接口的数据库缓存相关的内容,在这里做一个汇总和思维发散,顺便简单说下自己的心得:针对系统的查询接口,首次压测执行的时候TPS较低,平均响应时间较高,后续的查询中,TPS和平均相应时间较第一次比有较为明显的提升,这里考虑到时Or......
  • 【Cpp 基础】主动刷新 cout 缓存区
    使用额外的“刷新”功能(<<flush)来确保根据我们的要求显示输出。//C++程序演示flush函数的使用#include<iostream>#include<thread>#include<chrono>usingnamespacestd;intmain(){ for(inti=1;i<=5;++i) { cout<<i<<""<&......
  • Asp.Net Core webapi+net6 使用资源筛选器(过滤器) 做缓存
    写一个特性类,用来做标记[AttributeUsage(AttributeTargets.Method)]//只对方法有效publicclassResourceFilterAttribute:Attribute{}我这里使用了MemoryCache来做缓存,也可以使用字典来做,但一定要加上static,否则字典每一次请求都会new一个实例,缓存的东西就丢了private......