逐出元素 Caffeine具有三种元素逐出策略:基于容量,基于时间和基于引用。 基于容量的逐出 这种逐出发生在超过配置的缓存容量大小限制时。...build(k -> DataObject.get("Data for " + k)); assertEquals(0, cache.estimatedSize()); 当我们添加一个值时,大小显然会增加...这是因为缓存逐出是异步执行的,并且此方法有助于等待逐出操作的完成。...此逐出策略基于元素的到期时间,并具有三种类型: Expire after access — 自上次读取或写入发生以来,经过过期时间之后该元素到期。...前者当请求过期元素时,执行将阻塞,直到build()计算出新值为止。 但是后者将返回旧值并异步计算出新值并插入缓存中,此时被刷新的元素的过期时间将重新开始计时计算。
1、简介 在本文中,我们将了解Caffeine,一个用于Java的高性能缓存库。 缓存和Map之间的一个根本区别是缓存会清理存储的项目。...一个清理策略会决定在某个给定时间哪些对象应该被删除,这个策略直接影响缓存的命中率——缓存库的一个关键特性。 Caffeine使用Window TinyLfu清理策略,它提供了接近最佳的命中率。...4、缓存值的清理 Caffeine有三种缓存值的清理策略:基于大小、基于时间和基于引用。 4.1、基于大小的清理 这种类型的清理设计为在超出缓存配置的大小限制时发生清理。...,分为三种: 访问后过期——自上次读取或写入以来,条目在经过某段时间后过期 写入后过期——自上次写入以来,条目在经过某段时间后过期 自定义策略——由Expiry的实现来为每个条目单独计算到期时间 让我们使用....build(k -> DataObject.get("Data for " + k)); 在这里,我们应该明白expireAfter和refreshAfter的一个区别:当请求过期条目时,执行会阻塞
Size-based 逐出 如果你的缓存不应该超出一定的大小,请使用CacheBuilder.maximum(long),缓存将尝试驱逐最近或者最不常使用的条目,需要注意的是,缓存可能会在达到内存限制之前逐出条目...由CacheBuilder构建的缓存不会自动执行cleanup和驱逐值,或者在值到期后立即执行或者逐出任何类型。相反,在写入期间执行少量维护,或者在写入很少的情况下偶尔执行读取操作。...相反,选择在你自己手中,如果缓存是高吞吐量的,那么不必担心执行缓存维护以清理过期的条目,如果缓存很少写入并且不希望清除阻止缓存读取,可能希望创建自己的维护线程,定期调用Cache.cleanUp() 如果要为很少写入的告诉缓存安排常规高速缓存维护...在刷新的过程中,旧的值仍然会被返回,在逐出值时,会强制检索等待,直到重新加载该值。 在刷新时如果抛出了异常,那么保存旧值,记录并吞下异常。...这些方法本来支持,但是我们的支持不完整,会导致所有用户付出代价,但是部分用户获益。 get调用请求未缓存的值被分为两大类,加载值以及那些等待另一个线程正在加载的。
如果将其扩展到多个节点,会发生什么情况?如果请求层扩展到多个节点,那么每个节点仍然有可能拥有自己的缓存。但是,如果负载平衡器在节点间随机分配请求,则相同的请求将转到不同的节点,从而增加缓存未命中。...缓存的数据允许快速检索,而且,由于相同的数据被写入永久存储器,我们将在缓存和存储器之间拥有完全的数据一致性。此外,此方案还确保在发生崩溃、电源故障或其他系统中断时不会丢失任何东西。...对于写密集型应用程序,这会导致低延迟和高吞吐量,但是,在发生崩溃或其他不利事件时,这种速度会带来数据丢失的风险,因为写数据的唯一副本在缓存中。...image.png read-through 读取数据时,先尝试从缓存中取得,如果缓存中没有,那么再从数据库中读取,而后也将数据放入缓存中,以便下次读取。这个也是普遍使用的方案。...缓存淘汰策略 以下是一些最常见的缓存逐出策略: 1.先进先出(FIFO):缓存逐出首先访问的第一个块不考虑以前访问它的频率或次数。
,包括当前缓存条目的数量和当前缓存的大小。...如果降低了缓存大小限制,XCom将删除已经确定并交付的最老的条目,直到当前大小低于限制值为止。在删除最老的条目过程进行期间,XCom可能会暂时超过缓存大小限制。...但要注意,虽然成员处于超级只读模式,不能对成员执行写操作,但是可以执行读操作,并且随着时间的推移,读取到陈旧数据的可能性会越来越大(因为此时并不能同步组中的最新数据)。...、或者无法自动重新加入组、或者尝试自动加入组次数耗尽时,组复制会执行什么操作(这里指的是组成员退出组时需要做的操作)。...当成员处于超级只读模式时,客户端不能执行任何更新操作,即使他们拥有super权限。但是,客户端仍然可以读取数据,由于数据不再更新,所以,随着时间的推移,读取到陈旧的数据的概率会大大增加。
当我们提到缓存的时候,第一时间就会想到Redis、memcached缓存中间件,他们支持分布式的缓存,还有一种是基于单机内存的缓存方式,例如最简单的java中的局部变量、java中的ConcurrentHashMap...当我们添加新数据的时候,会把新数据放到队尾(假设新数据最大概率被再次访问),当我们长度到达阈值需要淘汰数据的时候,会从队首进行淘汰。...: [{}] -> [{}]", k, asyncCache.get(k, this::buildLoader).get()); } 过期策略 Caffeine的缓存清除是惰性的,可能发生在读请求后或者写请求后...基于大小过期:当缓存超出后,使用W-TinyLFU算法进行缓存淘汰处理 基于缓存条目过期 maximumSize()方法,参数是缓存中存储的最大缓存条目,当添加缓存时达到条目阈值后,将进行缓存淘汰操作...一方面这个组件可以代替上面提到的RemovalListener移除事件监听,不同之处在于这个是同步执行的,且是一个原子操作,写入缓存完成之前会阻塞后续更新缓存的操作,但是读缓存不会阻塞;另一方面,可以当作是维持和外部资源的一个纽带
接下来,我们会详细介绍 Caffeine Cache 的特性和应用,并将这个高效的缓存工具无缝集成到你的项目中。淘汰算法在解析Caffeine Cache之前,我们首先要理解缓存淘汰算法。...maximumSize:设置缓存的最大条目数。当缓存达到这个大小时,它会开始进行清除。maximumWeight:设置缓存的最大权重。需要同时定义一个Weigher来如何计算缓存条目的权重。...当调用被注解的方法时,如果对应的键已经存在缓存,则不再执行方法体,而从缓存中直接返回。当方法返回null时,将不进行缓存操作。@CachePut:表示执行该方法后,其值将作为最新结果更新到缓存中。...,如数据库查询,API调用等 }}在这个例子中,无论有多少线程尝试使用相同的ISBN查找相同的书,只有一个线程会实际执行findBook方法并将结果存储在名为"books"的缓存中。...在不同的Caffeine配置下,同步模式表现不同:Caffeine缓存类型是否开启同步多线程读取不存在/已驱逐的key 多线程读取待刷新的key
接下来,我们会详细介绍 Caffeine Cache 的特性和应用,并将这个高效的缓存工具无缝集成到你的项目中。 淘汰算法 在解析Caffeine Cache之前,我们首先要理解缓存淘汰算法。...并且LFU需要维护所有对象的访问计数,这可能会消耗比较多的存储空间和计算资源。...当调用被注解的方法时,如果对应的键已经存在缓存,则不再执行方法体,而从缓存中直接返回。当方法返回null时,将不进行缓存操作。 @CachePut:表示执行该方法后,其值将作为最新结果更新到缓存中。...,如数据库查询,API调用等 } } 在这个例子中,无论有多少线程尝试使用相同的ISBN查找相同的书,只有一个线程会实际执行findBook方法并将结果存储在名为"books"的缓存中。...在不同的Caffeine配置下,同步模式表现不同: Caffeine缓存类型 是否开启同步 多线程读取不存在/已驱逐的key 多线程读取待刷新的key Cache 否 各自独立执行被注解方法。
@Cacheable:根据方法的请求参数对其结果进行缓存,下次同样的参数来执行该方法时可以直接从缓存中获取结果,而不需要再次执行该方法; @CachePut:根据方法的请求参数对其结果进行缓存,它每次都会触发真实方法的调用...当我们在Controller层调用 getUserById方法时,调试的时候,配置mybatis日志级别为DEBUG,方便监控方法是否会缓存。...执行完成之后,控制台里可以看到:列表整体直接被缓存起来,用户列表缓存和用户条目缓存并没有共享,他们是平行的关系。 这种情况下,缓存的颗粒度控制也没有那么细致。...写到这里,相信大家对缓存抽象有了更进一步的理解。当我们想实现更复杂的缓存功能时,需要对Spring Cache做一定程度的扩展。...- 从一级缓存查询key:1 等待30s , 再执行一次,因为本地缓存会失效,所以执行的时候会查询二级缓存 - 从一级缓存查询key:1 - 从二级缓存查询key:1 一个简易的二级缓存就组装完了。
而本地缓存一般会配置自动剔除策略,为了保护应用程序,限制内存占用情况,防止内存溢出 Caffeine提供了灵活的构造方法,从而创建可以满足如下特性的本地缓存: 自动把数据加载到本地缓存中,并且可以配置异步...CleanUp 一个Scheduler可能被用来开启对失效键值对的迅速删除。调度中使用批次来减少执行次数。调度会尽最大努力,但是不确保一个键值对失效时被删除。...通过调度,会批量执行过期事件,以在短时间内最大程度的减少执行次数。调度会尽力删除过期条目,但不能对何时删除做任何保证。...在这个获取过程中,Caffeine发现时间已经过了10秒,然后会将v2加载到本地缓存中,下一次获取时才能拿到v2。...这就意味着,如果不读取本地缓存中的数据的话,无论刷新时间间隔是多少,本地缓存中的数据永远是旧的数据!
因此,包含大量修改的事务最终可能会使用大于配置的顶点缓存。 2.2 Index缓存 索引缓存包含在此事务的上下文中执行的索引查询的结果。随后的相同索引调用将从此缓存提供,因此明显更便宜。...如果同一个索引调用在同一个事务中永远不会发生两次,则索引缓存没有区别。 索引高速缓存中的每个条目的权重等于,2 + result set size并且高速缓存的总权重不会超过事务高速缓存大小的一半。...3.1 缓存到期时间 性能和查询行为最重要的设置是通过配置的缓存过期时间cache.db-cache-time。缓存将保存图形元素最多几毫秒。如果元素到期,则在下次访问时将从存储后端重新读取数据。...这允许缓存无限期地保存元素(除非它们由于空间限制或更新而被逐出),这提供了最佳的缓存性能。由于没有其他JanusGraph实例正在修改图形,因此不存在保持过时数据的危险。...配置太大的缓存可能导致内存不足异常和过多的GC。 3.3 清理等待时间 当本地修改顶点(例如添加边)时,所有顶点的相关数据库级缓存条目都被标记为已过期并最终被逐出。
这个缓存应用于java 方法级别缓存,通过缓存中的数据来减少方法执行次数。每当目标方法被调用,spring cache会执行一个缓存行为来检查这个相同参数的方法是否已经被执行。...如果被执行过了,那么不执行方法直接返回缓存中的结果。 通过这样,代价高的方法(CPU或IO依赖)可以只执行一次,相同参数的结果会复用而不是真正的执行这个方法。...缓存一个指定的条目直接等价于获取-如果-不存在-然后-执行-并且-最好放入缓存的程序逻辑的代码块:不会阻塞并且多线程可以并发地加载相同的条目。...想要使用这个抽象的缓存,开发者需要关心两个方面: 缓存声明 - 定义需要被缓存的方法以及对应的缓存策略。 缓存配置 - 数据存储和读取的实现。...1.基于注解的声明式缓存 缓存抽象提供了一系列的java注解: @Cacheable 触发缓存逻辑 @CacheEvict 触发缓存逐出逻辑 @CachePut 不干涉方法执行地更新缓存 @Caching
这一章节我们会从 Caffeine 的使用引入,并提出一些问题,之后分析其源代码解决这些问题来让我们更好的去了解 Caffeine 的原理,更好的使用与优化,并且会对于我们之后的编码有所裨益。...创建一个自定义权重限制容量的 Cache Cache> stringListCache = Caffeine.newBuilder() //最大weight值,当所有entry的weight和快达到这个限制的时候会发生缓存过期...build(); 那么就引出了如下几个问题: 如果回调发生异常,会怎么处理?..., value); //批量加入 syncCache.putAll(keyValueMap); //读取缓存,如果不存在,则执行后面的mappingFunction读取并放入缓存 syncCache.get...syncCache.cleanUp(); 这里只提了同步缓存,异步缓存的 API 类似,只是取值变成了 CompletableFuture 包装的 接下来的章节,我们会深入研究 Caffeine
而缓存则位于主存和处理器之间,作为一个更快、更小的存储器。当处理器需要访问数据时,它首先会查找缓存。如果数据存在于缓存中,就可以快速获取并提供给处理器,这样就避免了读取主存的延迟时间。...Caffeine提供灵活的结构来创建缓存,并且有以下特性: 自动加载条目到缓存中,可选异步方式 可以基于大小剔除 可以设置过期时间,时间可以从上次访问或上次写入开始计算 异步刷新 keys自动包装在弱引用中...key // 参数二:Lambda表达式,表达式参数就是缓存的key,方法体是查询数据库的逻辑 // 优先根据key查询JVM缓存,如果未命中,则执行参数二的Lambda...如果没有强引用这个key,则GC时允许回收该条目 Caffeine.weakValues() 使用弱引用存储value。...如果没有强引用这个value,则GC时允许回收该条目 Caffeine.softValues() 使用软引用存储value, 如果没有强引用这个value,则GC内存不足时允许回收该条目 引用类型 被垃圾回收时间
内存管理:Caffeine 提供了灵活的内存管理选项,可以通过设置缓存的最大大小、最大条目数或最大权重来控制缓存的大小。它还支持基于容量、时间或引用等策略来自动清理过期的缓存条目。...异步加载:Caffeine 支持异步加载缓存条目的功能。当缓存中不存在所需的条目时,它可以自动触发加载过程,并在加载完成后将结果放入缓存。...* 在获取缓存值时,如果想要在缓存值不存在时,原子地将值写入缓存,则可以调用get(key, k -> value)方法,该方法将避免写入竞争。...其和普通缓存不同的地方在于,当缓存不存在/缓存已过期时,若调用get()方法,则会自动调用CacheLoader.load()方法加载最新值。...* * 基于容量的驱逐需要指定缓存容量的最大值,当缓存容量达到最大时,Caffeine将使用LRU策略对缓存进行淘汰;基于时间的驱逐策略如字面意思,可以设置在最后访问/写入一个缓存经过指定时间后
我们可以通过cache.getIfPresent(key) 方法来获取一个key的值,通过cache.put(key, value)方法显示的将数控放入缓存,但是这样子会覆盖缓原来key的数据。...如果缓存中不存在该键,则调用这个 Function 函数,并将返回值作为该缓存的值插入缓存中。get 方法是以阻塞方式执行调用,即使多个线程同时请求该值也只会调用一次Function方法。...在build Cache的时候会提供一个createExpensiveGraph函数。...(RemovalListener) 为缓存指定一个删除侦听器,以便在删除数据时执行某些操作。...Cache.stats() 方法返回提供统计信息的CacheStats,如: hitRate():返回命中与请求的比率 hitCount(): 返回命中缓存的总数 evictionCount():缓存逐出的数量
蓝线是项列表中的每个项都与频率列表中的祖先有关的指针。 那么,如果再次访问项E会发生会发生什么?让我们完成以下步奏:1. 从哈希表中检索项很容易(并且很好地扩展)O(1)。 2....如果没有,我们将不得不在频率列表中创建一个新的频率节点(并设置其所有合理的默认值),然后将该项添加到其条目列表中 第三,一旦我们检测到FrequencyParent,我们的函数就必须将新的父项设置为正在递增的项...由于频率列表是按升序排列的,因此它将开始从第一个频率节点开始删除条目,直到它删除与传入的任意数字一样多的项目。 如果频率节点由于逐出而不包含条目,则Evict函数也必须从频率列表中移除频率节点。...此外,Set函数在实际缓存它们时访问缓存的项目。...任何缓存的一个关键组件是,当新项目添加到缓存时,它应该知道如何逐出项目(释放空间)。对于LFU缓存,当缓存达到容量时,需要删除最不常用的项。
客户端缓存的Redis实现 Redis客户端缓存支持称为跟踪,有两种模式: 在默认模式下,服务器会记住给定客户机访问的密钥,并在修改相同的密钥时发送无效消息。...当某个客户端修改了某个密钥,或者因为该密钥具有相关的过期时间而被逐出,或者由于maxmemory策略而被逐出时,所有启用了跟踪且可能缓存了该密钥的客户端都将收到一条无效消息。...这样的无效表可以包含最大数量的条目,如果插入了一个新的键,服务器可以通过假装该键被修改(即使没有修改),并向客户端发送无效消息来逐出旧条目。...什么跟踪记录 默认情况下,客户机不需要告诉服务器它们正在缓存哪些密钥。服务器会跟踪只读命令上下文中提到的每个键,因为它可以被缓存。 这样做的明显优点是不需要客户机告诉服务器它在缓存什么。...一般情况下,当服务器假定我们得到的东西也要缓存时,我们正在权衡: 当客户机倾向于用一个欢迎新对象的策略缓存许多东西时,这种方法更有效。 服务器将被迫保留有关客户端密钥的更多数据。
领取专属 10元无门槛券
手把手带您无忧上云