redis || 本地进程缓存和 Caffeine

本地进程缓存

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

1、分布式缓存,例如Redis:

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

缺点:访问缓存有网络开销
场景:缓存数据量较大、可靠性
要求较高、需要在集群间共享

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

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

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

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

Caffeine介绍

Caffeine是一个基于Java8开发的,提供了近乎最佳命中率的高性能的本地缓存库。

Caffeine相当于一个缓存工厂,可以创建出多个缓存实例 Cache。

这些缓存实例都继承了 Caffeine 的参数配置,Caffeine 是如何配置的,这些缓存实例就具有什么样的特性和功能。

Caffeine 是目前性能最好的本地缓存,目前Spring内部的缓存使用的就是Caffeine。

GitHub地址:https://github.com/ben-manes/caffeine

Caffeine缓存属性

1. initialCapacity 缓存初始容量

整数,表示能存储多少个缓存对象。

为什么要设置初始容量呢?

如果提前能预估缓存的使用大小,那么可以设置缓存的初始容量,以免缓存不断地进行扩容,致使效率不高。

2. maximumSize 最大容量

如果缓存中的数据量超过这个数值,Caffeine 会有一个异步线程来专门负责清除缓存,按照指定的清除策略来清除掉多余的缓存。

3. maximumWeight 最大权重

存入缓存的每个元素都要有一个权重值,当缓存中所有元素的权重值超过最大权重时,就会触发异步清除。

缓存状态收集器

默认的缓存状态收集器(CacheStats)

缓存的状态会用一个 CacheStats 对象记录下来,通过访问 CacheStats 对象就可以知道当前缓存的各种状态指标。

什么是加载?

当查询缓存时,缓存未命中,那就需要去第三方数据库中查询,然后将查询出的数据先存入缓存,再返回给查询者,这个过程就是加载。

Caffeine过期策略

在Caffeine中分为两种缓存,一个是有界缓存,一个是无界缓存,无界缓存不需要过期并且没有界限。

在有界缓存中提供了三个过期API:

1. expireAfterWrite:代表着写了之后多久过期

2. expireAfterAccess:代表着最后一次访问了之后多久过期

3. expireAfter:在expireAfter中需要自己实现Expiry接口,这个接口支持create,update,以及access了之后多久过期。注意这个API和前面两个API是互斥的。

Caffeine更新策略

设定多长时间后会自动刷新缓存。

Caffeine提供了refreshAfterWrite()方法来实现多久更新策略。

Caffeine打点监控

通过 'recordStats()Api' 开启,在`StatsCounter`接口中,定义了打点监控的方法。

例如:

1. recordHits:记录缓存命中

2. recordMisses:记录缓存未命中

3. recordLoadSuccess:记录加载成功(指的是CacheLoader加载成功)

4. recordLoadFailure:记录加载失败

5. recordEviction:记录淘汰数据

通过上面的监听,我们可以实时监控缓存当前的状态,以评估缓存的健康程度以及缓存命中率等,方便后续调整参数。

Caffeine淘汰监听

编写一个监听器

Cache<String, String> cache = Caffeine.newBuilder().removaListener(((key, value, cause) -> {
    System.out.println(cause);
})).build();

淘汰原因如下:

1. EXPLICIT:用户造成的,通过调用remove方法删除。

2. REPLACED: 更新的时候,相当于把之前的value给删了。

3. COLLECTED: 用于垃圾收集器,也就是减少的软引用,弱引用。

4. EXPIRED:过期淘汰。

5. SIZE: 大小淘汰,当超过最大的时候就会进行淘汰。

Caffeine示例

@Test
void testBasicOps() {
    // 构建cache对象
    Cache<String, String> cache = Caffeine.newBuilder().build();

    // 存数据
    cache.put("gf", "西施");

    // 取数据
    String gf = cache.getIfPresent("gf");
    System.out.println("gf = " + gf);

    // 取数据,包含两个参数:
    // 参数一:缓存的key
    // 参数二:Lambda表达式,表达式参数就是缓存的key,方法体是查询数据库的逻辑
    // 优先根据key查询JVM缓存,如果未命中,则执行参数二的Lambda表达式
    String defaultGF = cache.get("defaultGF", key -> {
        // 根据key去数据库查询数据
        return "貂蝉";
    });
    System.out.println("defaultGF = " + defaultGF);
}

Caffeine既然是缓存的一种,肯定需要有缓存的清除策略,不然的话内存总会有耗尽的时候。

Caffeine提供了三种缓存驱逐策略:

1、基于容量:设置缓存的数量上限

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

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

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

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

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

redis和caffeine的区别?

相同点:都是缓存的方式

不同点:

1. redis是将数据存储到内存里;caffeine是将数据存储在本地应用里

2. caffeine和redis相比,没有了网络IO上的消耗

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

韩未零

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值