Caffeine--缓存组件

2023-12-28 13:36
文章标签 组件 缓存 caffeine

本文主要是介绍Caffeine--缓存组件,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Caffeine

  • 概念
  • 缓存
    • 手动加载
    • 自动加载
    • 手动异步加载
    • 自动异步加载
  • 驱逐策略
    • 基于容量
    • 基于时间
    • 基于引用
  • 移除
    • 显式移除

概念

Caffeine是一个基于Java8开发的提供了近乎最佳命中率的高性能的缓存库。与ConcurrentMap有点相似。最根本的区别是ConcurrentMap将会持有所有加入到缓存当中的元素,直到它们被从缓存当中手动移除。Caffeine的缓存Cache 通常会被配置成自动驱逐缓存中元素,以限制其内存占用。在某些场景下,LoadingCacheAsyncLoadingCache尤为重要。

Caffeine提供了灵活的构造器去创建一个拥有下列特性的缓存:
(1)自动加载元素到缓存当中,异步加载的方式也可供选择
(2)当达到最大容量的时候可以使用基于就近度和频率的算法进行基于容量的驱逐
(3)将根据缓存中的元素上一次访问或者被修改的时间进行基于过期时间的驱逐
(4)当向缓存中一个已经过时的元素进行访问的时候将会进行异步刷新
(5)key将自动被弱引用所封装
(6)value将自动被弱引用或者软引用所封装
(7)驱逐(或移除)缓存中的元素时将会进行通知
(8)写入传播到一个外部数据源当中
(9)持续计算缓存的访问统计指标

缓存

Caffeine提供了四种缓存添加策略:手动加载自动加载手动异步加载自动异步加载

手动加载

		Cache<String, String> cache = Caffeine.newBuilder().expireAfterWrite(10, TimeUnit.MINUTES).maximumSize(10000).build();// 查找一个缓存元素, 没有查找到的时候返回nullString s=cache.getIfPresent("xiaohei");// 查找缓存,如果缓存不存在则生成缓存元素,  如果无法生成则返回nulls= cache.get("xiaohei", k -> new String("啥也没有"));// 添加或者更新一个缓存元素cache.put("xiaohei1", new String());// 移除一个缓存元素cache.invalidate("xiaohei");

Cache 接口提供了显式搜索查找、更新和移除缓存元素的能力。
推荐使用cache.get(key, k -> value)操作来在缓存中不存在该key对应的缓存元素的时候进行计算生成并直接写入至缓存内,而当该key对应的缓存元素存在的时候将会直接返回存在的缓存值。一次 cache.put(key, value) 操作将会直接写入或者更新缓存里的缓存元素,在缓存中已经存在的该key对应缓存值都会直接被覆盖。也可以使用Cache.asMap()所暴露出来的ConcurrentMap的方法对缓存进行操作。

自动加载

LoadingCache<String, String> cache = Caffeine.newBuilder().maximumSize(10000).expireAfterWrite(10, TimeUnit.MINUTES).build(key -> new String("啥也没有"));
// 查找缓存,如果缓存不存在则生成缓存元素,  如果无法生成则返回nullString s = cache.get("xiaohei");
// 批量查找缓存,如果缓存不存在则生成缓存元素Map<String, String> map = cache.getAll(Arrays.asList(new String[]{"xiaohei1", "xiaohei2"}));

一个LoadingCache是一个Cache 附加上CacheLoader能力之后的缓存实现。默认情况下,在getAll 方法中,将会对每个不存在对应缓存的key调用一次CacheLoader.load来生成缓存元素。

手动异步加载

		AsyncCache<String, String> cache = Caffeine.newBuilder().expireAfterWrite(10, TimeUnit.MINUTES).maximumSize(10000).buildAsync();// 查找一个缓存元素, 没有查找到的时候返回nullCompletableFuture<String> graph = cache.getIfPresent("xiaohei");// 查找缓存元素,如果不存在,则异步生成graph = cache.get("xiaohei", k -> new String("xiaoheissss"));// 添加或者更新一个缓存元素cache.put("xiaobai", graph);// 移除一个缓存元素cache.synchronous().invalidate("xiaohei");

一个AsyncCache是Cache的一个变体,AsyncCache提供了在Executor上生成缓存元素并返回 CompletableFuture的能力。这给出了在当前流行的响应式编程模型中利用缓存的能力。
synchronous()方法给Cache提供了阻塞直到异步缓存生成完毕的能力。也可以使用 AsyncCache.asMap()所暴露出来的ConcurrentMap的方法对缓存进行操作。默认的线程池实现是 ForkJoinPool.commonPool() ,也可以通过覆盖并实现 Caffeine.executor(Executor)方法来自定义线程池选择。

自动异步加载

		AsyncLoadingCache<String, String> cache = Caffeine.newBuilder().maximumSize(10000).expireAfterWrite(10, TimeUnit.MINUTES)// 你可以选择: 去异步的封装一段同步操作来生成缓存元素.buildAsync(key -> new String(key));// 你也可以选择: 构建一个异步缓存元素操作并返回一个future
//                .buildAsync((key, executor) -> createExpensiveGraphAsync(key, executor));// 查找缓存元素,如果其不存在,将会异步进行生成CompletableFuture<String> graph = cache.get("xiaohei");
// 批量查找缓存元素,如果其不存在,将会异步进行生成CompletableFuture<Map<String, String>> graphs = cache.getAll(Arrays.asList(new String[]{"xiaohei1", "xiaohei2"}));

一个 AsyncLoadingCache是一个AsyncCache加上AsyncCacheLoader能力的实现。在需要同步的方式去生成缓存元素的时候,CacheLoader是合适的选择。而在异步生成缓存的场景下,AsyncCacheLoader则是更合适的选择并且它会返回一个 CompletableFuture。默认情况下,在getAll 方法中,将会对每个不存在对应缓存的key调用一次 AsyncCacheLoader.asyncLoad 来生成缓存元素。 可以通过实现一个 AsyncCacheLoader.asyncLoadAll并在其中为没有在参数中请求的key也生成对应的缓存元素。如果对应某个key生成的缓存元素与包含这个key的一组集合剩余的key所对应的元素一致,那么在asyncLoadAll中也可以同时加载剩下的key对应的元素到缓存当中。

驱逐策略

基于容量

Caffeine提供了三种驱逐策略,分别是基于容量,基于时间和基于引用三种类型。

// 基于缓存内的元素个数进行驱逐
LoadingCache<String, String> graphs = Caffeine.newBuilder().maximumSize(10000).build(key -> new String(key));
// 基于缓存内元素权重进行驱逐
LoadingCache<String, String> graphs = Caffeine.newBuilder().maximumWeight(10000).weigher((String s, String s1) -> s1.length()).build(key -> new String(key));

基于缓存内的元素个数进行驱逐策略中,使用Caffeine.maximumSize(long)。缓存将会尝试通过基于就近度和频率的算法来驱逐掉不会再被使用到的元素。
缓存中的元素可能有不同的内存占用–需要借助Caffeine.weigher(Weigher)方法来界定每个元素的权重并通过 Caffeine.maximumWeight(long)方法来界定缓存中元素的总权重来实现上述的场景。在基于权重驱逐的策略下,一个缓存元素的权重计算是在其创建和更新时,此后其权重值都是静态存在的,在两个元素之间进行权重的比较的时候,并不会根据进行相对权重的比较。

基于时间

// 基于固定的过期时间驱逐策略LoadingCache<String, String> graphs1 = Caffeine.newBuilder().expireAfterAccess(5, TimeUnit.MINUTES).build(key -> new String());LoadingCache<String, String> graphs2 = Caffeine.newBuilder().expireAfterWrite(10, TimeUnit.MINUTES).build(key -> new String());// 基于不同的过期驱逐策略LoadingCache<String, String> graphs = Caffeine.newBuilder().expireAfter(new Expiry<String, String>() {@Overridepublic long expireAfterCreate(@NonNull String s, @NonNull String s2, long l) {return 0;}@Overridepublic long expireAfterUpdate(@NonNull String s, @NonNull String s2, long l, @NonNegative long l1) {return 0;}@Overridepublic long expireAfterRead(@NonNull String s, @NonNull String s2, long l, @NonNegative long l1) {return 0;}}).build(key -> new String());

expireAfterAccess(long, TimeUnit): 一个元素在上一次读写操作后一段时间之后,在指定的时间后没有被再次访问将会被认定为过期项。在当被缓存的元素时被绑定在一个session上时,当session因为不活跃而使元素过期的情况下,这是理想的选择。
expireAfterWrite(long, TimeUnit): 一个元素将会在其创建或者最近一次被更新之后的一段时间后被认定为过期项。在对被缓存的元素的时效性存在要求的场景下,这是理想的选择。
expireAfter(Expiry): 一个元素将会在指定的时间后被认定为过期项。当被缓存的元素过期时间收到外部资源影响的时候,这是理想的选择。

基于引用

		// 当key和缓存元素都不再存在其他强引用的时候驱逐LoadingCache<String, String> graphs1 = Caffeine.newBuilder().weakKeys().weakValues().build(key -> new String());// 当进行GC的时候进行驱逐LoadingCache<String, String> graphs2 = Caffeine.newBuilder().softValues().build(key -> new String());

Caffeine 允许去让GC去帮助清理缓存当中的元素,其中key支持弱引用,而value则支持弱引用和软引用。AsyncCache不支持软引用和弱引用。
Caffeine.weakKeys():在保存key的时候将会进行弱引用。这允许在GC的过程中,当key没有被任何强引用指向的时候去将缓存元素回收。由于GC只依赖于引用相等性。这导致在这个情况下,缓存将会通过引用相等(==)而不是对象相等 equals()去进行key之间的比较。

Caffeine.weakValues():在保存value的时候将会使用弱引用。这允许在GC的过程中,当value没有被任何强引用指向的时候去将缓存元素回收。由于GC只依赖于引用相等性。这导致在这个情况下,缓存将会通过引用相等(==)而不是对象相等 equals()去进行value之间的比较。

Caffeine.softValues():在保存value的时候将会使用软引用。为了相应内存的需要,在GC过程中被软引用的对象将会被通过LRU算法回收。由于使用软引用可能会影响整体性能,我们还是建议通过使用基于缓存容量的驱逐策略代替软引用的使用。同样的,使用 softValues() 将会通过引用相等(==)而不是对象相等equals()去进行value之间的比较。

移除

驱逐:缓存元素因为策略被移除
失效:缓存元素被手动移除
移除:由于驱逐或者失效而最终导致的结果

显式移除

可以手动去让某个缓存元素失效而不是只能等待其因为策略而被驱逐。

// 失效key
cache.invalidate("小黑");
// 批量失效key
cache.invalidateAll(Arrays.asList(new String[]{"xiaohei1", "xiaohei2"}));
// 失效所有的key
cache.invalidateAll();

这篇关于Caffeine--缓存组件的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/546115

相关文章

JS常用组件收集

收集了一些平时遇到的前端比较优秀的组件,方便以后开发的时候查找!!! 函数工具: Lodash 页面固定: stickUp、jQuery.Pin 轮播: unslider、swiper 开关: switch 复选框: icheck 气泡: grumble 隐藏元素: Headroom

如何在页面调用utility bar并传递参数至lwc组件

1.在app的utility item中添加lwc组件: 2.调用utility bar api的方式有两种: 方法一,通过lwc调用: import {LightningElement,api ,wire } from 'lwc';import { publish, MessageContext } from 'lightning/messageService';import Ca

缓存雪崩问题

缓存雪崩是缓存中大量key失效后当高并发到来时导致大量请求到数据库,瞬间耗尽数据库资源,导致数据库无法使用。 解决方案: 1、使用锁进行控制 2、对同一类型信息的key设置不同的过期时间 3、缓存预热 1. 什么是缓存雪崩 缓存雪崩是指在短时间内,大量缓存数据同时失效,导致所有请求直接涌向数据库,瞬间增加数据库的负载压力,可能导致数据库性能下降甚至崩溃。这种情况往往发生在缓存中大量 k

vue2 组件通信

props + emits props:用于接收父组件传递给子组件的数据。可以定义期望从父组件接收的数据结构和类型。‘子组件不可更改该数据’emits:用于定义组件可以向父组件发出的事件。这允许父组件监听子组件的事件并作出响应。(比如数据更新) props检查属性 属性名类型描述默认值typeFunction指定 prop 应该是什么类型,如 String, Number, Boolean,

kubelet组件的启动流程源码分析

概述 摘要: 本文将总结kubelet的作用以及原理,在有一定基础认识的前提下,通过阅读kubelet源码,对kubelet组件的启动流程进行分析。 正文 kubelet的作用 这里对kubelet的作用做一个简单总结。 节点管理 节点的注册 节点状态更新 容器管理(pod生命周期管理) 监听apiserver的容器事件 容器的创建、删除(CRI) 容器的网络的创建与删除

Redis中使用布隆过滤器解决缓存穿透问题

一、缓存穿透(失效)问题 缓存穿透是指查询一个一定不存在的数据,由于缓存中没有命中,会去数据库中查询,而数据库中也没有该数据,并且每次查询都不会命中缓存,从而每次请求都直接打到了数据库上,这会给数据库带来巨大压力。 二、布隆过滤器原理 布隆过滤器(Bloom Filter)是一种空间效率很高的随机数据结构,它利用多个不同的哈希函数将一个元素映射到一个位数组中的多个位置,并将这些位置的值置

火语言RPA流程组件介绍--浏览网页

🚩【组件功能】:浏览器打开指定网址或本地html文件 配置预览 配置说明 网址URL 支持T或# 默认FLOW输入项 输入需要打开的网址URL 超时时间 支持T或# 打开网页超时时间 执行后后等待时间(ms) 支持T或# 当前组件执行完成后继续等待的时间 UserAgent 支持T或# User Agent中文名为用户代理,简称 UA,它是一个特殊字符串头,使得服务器

防止缓存击穿、缓存穿透和缓存雪崩

使用Redis缓存防止缓存击穿、缓存穿透和缓存雪崩 在高并发系统中,缓存击穿、缓存穿透和缓存雪崩是三种常见的缓存问题。本文将介绍如何使用Redis、分布式锁和布隆过滤器有效解决这些问题,并且会通过Java代码详细说明实现的思路和原因。 1. 背景 缓存穿透:指的是大量请求缓存中不存在且数据库中也不存在的数据,导致大量请求直接打到数据库上,形成数据库压力。 缓存击穿:指的是某个热点数据在

PHP APC缓存函数使用教程

APC,全称是Alternative PHP Cache,官方翻译叫”可选PHP缓存”。它为我们提供了缓存和优化PHP的中间代码的框架。 APC的缓存分两部分:系统缓存和用户数据缓存。(Linux APC扩展安装) 系统缓存 它是指APC把PHP文件源码的编译结果缓存起来,然后在每次调用时先对比时间标记。如果未过期,则使用缓存的中间代码运行。默认缓存 3600s(一小时)。但是这样仍会浪费大量C

缓存策略使用总结

缓存是提高系统性能的最简单方法之一。相对而言,数据库(or NoSQL数据库)的速度比较慢,而速度却又是致胜的关键。 如果使用得当,缓存可以减少相应时间、减少数据库负载以及节省成本。本文罗列了几种缓存策略,选择正确的一种会有很大的不同。缓存策略取决于数据和数据访问模式。换句话说,数据是如何写和读的。例如: 系统是写多读少的吗?(例如基于时间的日志)数据是否是只写入一次并被读取多次?(例如用户配