高并发处理 --- Caffeine内存缓存库

目录

一.什么是Caffeine?

使用场景:

 二.如何使用Caffeine?

1.导入依赖:

2.在java项目中使用:

 三.对缓存项的驱逐:

1.容量驱逐(Maximum Size):

2.过期驱逐(Expire After Write / Access):

3.驱逐指定缓存项(主动驱逐):

(1)使用 invalidate 方法驱逐指定缓存项:

(2)使用 invalidateAll 方法驱逐所有缓存项:

(3)使用 invalidate 方法并批量驱逐多个缓存项:

(4)使用 invalidate 方法与条件驱逐:

4.驱逐回调(Eviction Listener):

(1)注册驱逐监听器:

(2)缓存项因过期被驱逐时执行回调:

四.在 Spring Boot 项目中使用 Caffeine 作为缓存:

1.添加 Caffeine 依赖:

2.创建配置类:

3.在 Controller 层注入 Cache 实例:

五.Caffeine与Redis的区别:

何时使用 Caffeine,何时使用 Redis?


一.什么是Caffeine?

Caffeine 是一个高性能的 Java 缓存库,它被设计用于提供快速、可靠的缓存服务。它基于 Google Guava 的缓存系统,但进行了许多优化,旨在提升性能、减少内存消耗,并为缓存提供更多的灵活性。Caffeine 的设计目标是创建一个高效、低延迟的内存缓存系统,能够在高并发的场景下提供卓越的表现。

Caffeine 通过优化缓存的存储和访问机制,在 CPU 缓存和垃圾回收方面做了大量改进,从而能够在高并发下实现高效的缓存管理。

Caffeine 是一个 本地缓存,它的缓存存储在应用服务器的内存中。每个实例都有自己的缓存空间,因此缓存是 本地的,仅对当前的应用实例可见。如果我们有多个应用实例或多个服务,Caffeine 缓存不会自动共享,它的作用范围限制在当前的应用进程中。这种缓存通常用于加速对本地应用数据的访问,减少对数据库的频繁查询。

使用场景:

Caffeine 是一个通用的内存缓存库,适用于多种场景,包括但不限于:

  • Web 应用缓存:缓存数据库查询结果、HTTP 请求的响应数据等。
  • 分布式系统中的本地缓存:例如,在分布式系统中,每个服务的本地缓存。
  • 计算密集型操作的缓存:例如缓存计算结果,避免重复计算。
  • API 请求缓存:缓存通过远程服务调用得到的数据,避免重复请求相同的数据。

 二.如何使用Caffeine?

1.导入依赖:

<dependency>
    <groupId>com.github.ben-manes.caffeine</groupId>
    <artifactId>caffeine</artifactId>
    <version>3.1.0</version>
</dependency>

2.在java项目中使用:

Caffeine 提供了丰富的 API 来创建和管理缓存,下面是一个简单的示例。

import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;

import java.util.concurrent.TimeUnit;

public class CaffeineExample {
    public static void main(String[] args) {
        // 创建一个缓存实例
        Cache<String, String> cache = Caffeine.newBuilder()
                .expireAfterWrite(10, TimeUnit.MINUTES) // 设置写入后10分钟过期
                .maximumSize(100) // 设置最大缓存条目数
                .build();

        // 存入缓存
        cache.put("key1", "value1");
        cache.put("key2", "value2");

        // 获取缓存
        String value = cache.getIfPresent("key1");  // 返回value1
        System.out.println("Cached value for key1: " + value);

        // 如果缓存中没有数据,使用一个加载函数填充缓存
        String loadedValue = cache.get("key3", key -> "loadedValue");
        System.out.println("Loaded value for key3: " + loadedValue);
    }
}
  • Caffeine.newBuilder():用于构建 Caffeine 缓存的构建器。
  • expireAfterWrite(10, TimeUnit.MINUTES):指定缓存项在写入后的 10 分钟过期。
  • maximumSize(100):指定最大缓存容量为 100 个条目,超过这个限制的缓存项会被逐出。
  • getIfPresent(key):如果缓存存在,则返回对应的缓存值。
  • get(key, function):如果缓存不存在,会通过提供的加载函数自动加载并缓存。

 三.对缓存项的驱逐:

在 Caffeine 缓存中,驱逐(Eviction)指的是当缓存达到一定容量限制或过期时,自动移除缓存项的过程。Caffeine 提供了多种方式来控制缓存项的驱逐,包括基于缓存容量限制、缓存过期时间以及自定义驱逐策略

Caffeine 提供了以下几种常见的驱逐策略:

  • 容量限制驱逐:当缓存的大小超过指定的最大容量时,Caffeine 会移除最不常用的缓存项。
  • 过期时间驱逐:当缓存项过期后,Caffeine 会自动移除该项。
  • 主动驱逐:可以根据需求主动驱逐特定缓存项。

1.容量驱逐(Maximum Size):

通过设置最大缓存容量,Caffeine 会根据缓存的容量进行驱逐,移除不常用的缓存项(通常是 LRU 策略,即最少使用的项会先被移除)。

Cache<String, String> cache = Caffeine.newBuilder()
        .maximumSize(100)  // 设置最大缓存容量为100
        .build();

当缓存的条目数超过最大容量时,Caffeine 会自动驱逐最少使用的条目。

2.过期驱逐(Expire After Write / Access):

Caffeine 提供了基于时间的缓存驱逐策略,可以指定缓存项的失效时间:

  • expireAfterWrite:缓存项在写入后的指定时间后失效。
  • expireAfterAccess:缓存项在访问后的指定时间后失效。
Cache<String, String> cache = Caffeine.newBuilder()
        .expireAfterWrite(10, TimeUnit.MINUTES)  // 写入后10分钟失效
        .expireAfterAccess(5, TimeUnit.MINUTES)  // 访问后5分钟失效
        .maximumSize(100)
        .build();

 当缓存项超过指定的过期时间后,Caffeine 会自动移除这些缓存项。

3.驱逐指定缓存项(主动驱逐):

Caffeine 允许在运行时主动驱逐缓存中的某个指定项。这对于一些特殊情况非常有用,比如在缓存项的数据发生变化时,主动移除某个缓存项。

(1)使用 invalidate 方法驱逐指定缓存项:

我们可以使用 invalidate 方法来驱逐指定的缓存项。如果需要移除一个特定的缓存项,可以直接传入键名。

cache.invalidate("key1");  // 移除指定的缓存项

(2)使用 invalidateAll 方法驱逐所有缓存项:

如果需要清空缓存中的所有项,可以使用 invalidateAll 方法。

cache.invalidateAll();  // 移除所有缓存项

(3)使用 invalidate 方法并批量驱逐多个缓存项:

cache.invalidate("key1", "key2", "key3");  // 移除多个指定的缓存项

(4)使用 invalidate 方法与条件驱逐:

我们还可以根据特定条件来选择性地驱逐缓存项。例如,您可以实现一个条件判断逻辑来决定是否驱逐某个缓存项。

cache.invalidateIf((key, value) -> key.startsWith("prefix"));  // 根据条件驱逐缓存项

4.驱逐回调(Eviction Listener):

Caffeine 提供了一个强大的驱逐监听器功能,允许在缓存项被驱逐时执行回调。这个功能对于缓存管理非常有用,特别是需要记录缓存被移除的原因,或者需要清理与缓存相关的资源。

(1)注册驱逐监听器:

我们可以使用 removalListener 方法来注册一个驱逐监听器。当缓存项被移除时,监听器会被触发。

Cache<String, String> cache = Caffeine.newBuilder()
        .maximumSize(100)
        .removalListener((key, value, cause) -> {
            System.out.println("Removed key: " + key + ", cause: " + cause);
        })
        .build();

回调参数说明

  • key:被驱逐的缓存项的键。
  • value:被驱逐的缓存项的值。
  • cause:驱逐的原因(如容量满、过期、手动移除等)。

驱逐的原因(cause)可以是以下几种:

  • EXPIRED:缓存项过期。
  • SIZE:因为达到容量限制而被移除。
  • MANUAL:手动驱逐。
  • REPLACED:被替代的缓存项。
  • COLLECTED:由于垃圾回收导致的移除。

(2)缓存项因过期被驱逐时执行回调:

Cache<String, String> cache = Caffeine.newBuilder()
        .expireAfterWrite(5, TimeUnit.MINUTES)
        .removalListener((key, value, cause) -> {
            if (cause == RemovalCause.EXPIRED) {
                System.out.println("Cache item expired: " + key);
            }
        })
        .build();

Caffeine 缓存提供了灵活且强大的驱逐机制,允许开发者根据不同的需求进行缓存项的移除和清理。常见的驱逐方式包括基于容量的驱逐、过期时间的驱逐、主动驱逐以及驱逐监听器。

  • 最大容量maximumSize 设定缓存的最大容量,超过容量时会自动驱逐最不常用的缓存项。
  • 过期策略expireAfterWriteexpireAfterAccess 提供了基于时间的缓存项失效机制。
  • 主动驱逐:可以使用 invalidate 方法手动移除缓存项。
  • 驱逐监听器:通过 removalListener 监听缓存项的驱逐事件,以便做进一步的处理。

四.在 Spring Boot 项目中使用 Caffeine 作为缓存:

假设我们正在开发一个 Spring Boot 项目,其中包含一个频繁查询数据库的 UserService,为了提升性能,我们决定在缓存中存储用户信息。对于某些高频率访问的数据(如用户基本信息),使用内存缓存可以显著提高响应速度。为了避免频繁地访问数据库,我们使用 Caffeine 来缓存用户数据。 

1.添加 Caffeine 依赖:

pom.xml 中添加 Caffeine 依赖:

<dependency>
    <groupId>com.github.ben-manes.caffeine</groupId>
    <artifactId>caffeine</artifactId>
    <version>3.1.0</version>
</dependency>

2.创建配置类:

package cn.mybatisplus.redis_mq.config;


import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.concurrent.TimeUnit;

@Configuration
public class CaffeineConfig {

    @Bean
    public Cache<Long,Object> ObjectCache(){
        return Caffeine.newBuilder()
                .expireAfterAccess(5, TimeUnit.MINUTES)  // 5 分钟后过期
                .refreshAfterWrite(10, TimeUnit.MINUTES) // 每10分钟自动刷新缓存
                .maximumSize(100)
                .build();
    }
}

3.在 Controller 层注入 Cache 实例:

Controller 中,使用 @Autowired 注解将 Cache<Long, Object> 缓存实例注入进来,直接使用缓存进行操作。

import com.github.benmanes.caffeine.cache.Cache;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/products")
public class ProductsController {

    @Autowired
    private Cache<Long, Object> objectCache;

    // 模拟一个从缓存中获取数据的接口
    @GetMapping("/getUserInfo")
    public String getUserInfo(@RequestParam Long userId) {
        // 检查缓存中是否存在该用户数据
        Object cachedData = objectCache.getIfPresent(userId);

        if (cachedData != null) {
            return "Cache hit: " + cachedData;
        } else {
            // 模拟从数据库获取用户数据
            String userInfo = "User Info for " + userId;

            // 将查询到的数据放入缓存中
            objectCache.put(userId, userInfo);

            return "Cache miss: " + userInfo;
        }
    }
}

如果希望在缓存失效或需要手动控制缓存刷新时使用更多功能,Caffeine 提供了丰富的 API,可以在代码中进行进一步的定制。例如:

objectCache.invalidate(userId);  // 删除缓存
objectCache.refresh(userId);     // 刷新缓存

五.Caffeine与Redis的区别:

Caffeine 和 Redis 都是常见的缓存解决方案,但它们各自有不同的优势和适用场景:

特性CaffeineRedis
存储类型内存缓存分布式缓存(存储在外部内存中,如内存、磁盘等)
性能本地内存缓存,速度非常快,低延迟由于需要网络请求,相较于 Caffeine 较慢
适用范围单机应用,内存容量较小的缓存,低延迟缓存访问分布式系统,跨机器的缓存,支持持久化存储
缓存容量受限于 JVM 内存(可配置最大容量)可配置持久化存储,容量几乎无限
缓存失效策略支持过期时间、LRU/LFU 淘汰策略支持过期时间、LRU、LRU + 分布式缓存持久化策略
持久化支持不支持持久化,只在 JVM 中缓存支持持久化(内存、磁盘、备份等)
分布式支持仅适用于单机应用支持分布式缓存,多个节点可以共享缓存
内存使用内存缓存,适合小规模、高性能访问内存/磁盘结合,适合大规模、高可用的分布式缓存

何时使用 Caffeine,何时使用 Redis?

①使用 Caffeine:如果你的应用只需要单机缓存,数据量相对较小,且要求极低的延迟(例如,数据库查询、网页请求缓存),Caffeine 是一个很好的选择。

场景

  • 单机应用,数据存储量较小(例如,用户的最近访问信息、缓存一些经常访问的配置数据等)。
  • 对缓存响应时间要求非常严格,需要高性能低延迟的缓存。
  • 不需要跨服务器共享缓存,且缓存数据可以在应用关闭后丢失。

②使用 Redis:如果你需要跨多个应用共享缓存,或者需要缓存的数据需要持久化,或者系统是分布式的,Redis 是更适合的选择。

场景

  • 分布式系统或微服务架构中需要共享缓存(例如,用户会话、订单状态等)。
  • 数据缓存需要持久化,即便系统重启,缓存数据也要保留。
  • 需要高可用和高扩展性的缓存解决方案,Redis 支持集群、复制、持久化等特性。

在实际项目中,我们可以根据业务需求选择合适的缓存解决方案,甚至结合 Caffeine 和 Redis 使用,例如使用 Caffeine 缓存本地数据,使用 Redis 缓存跨应用的数据。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/942082.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

美国加州房价数据分析01

1.项目简介 本数据分析项目目的是分析美国加州房价数据&#xff0c;预测房价中值。 环境要求&#xff1a; ancondajupyter notebookpython3.10.10 虚拟环境&#xff1a; pandas 2.1.1 numpy 1.26.1 matplotlib 3.8.0 scikit-learn1.3.1 2. 导入并探索数据集 通用的数据分析…

PPO算法基础(一)

PPO近端策略优化算法 我们今天还是主要来理解PPO算法的数学原理。PPO是一种策略梯度方法&#xff0c;简单的策略梯度对每个样本&#xff08;或者一组样本&#xff09;进行一次梯度更新&#xff0c;对单个样本执行多个梯度步骤会导致一些问题&#xff0c;因为梯度偏差太大&…

LabVIEW软件开发的未来趋势

LabVIEW软件开发的未来趋势可以从以下几个方面来分析&#xff1a; ​ 1. 与AI和机器学习的深度结合 趋势&#xff1a;LabVIEW正在向集成AI和机器学习方向发展&#xff0c;尤其是在数据处理、预测性维护和自动化控制领域。 原因&#xff1a;AI技术的普及使得实验和工业场景中的…

H3C MPLS跨域optionB

实验拓扑 实验需求 如图,VPN1 和 VPN2 分别通过运营商 MPLS VPN 连接各自分支机构按照图示配置 IP 地址,VPN1 和 VPN2 连接同一个 PE 设备的私网 IP 网段存在地址复用,使用多 VRF 技术来防止 IP 冲突AS 100 和 AS 200 内部的公共网络中各自运行 OSPF 使 AS 内各设备的 Loo…

【数据结构练习题】链表与LinkedList

顺序表与链表LinkedList 选择题链表面试题1. 删除链表中等于给定值 val 的所有节点。2. 反转一个单链表。3. 给定一个带有头结点 head 的非空单链表&#xff0c;返回链表的中间结点。如果有两个中间结点&#xff0c;则返回第二个中间结点。4. 输入一个链表&#xff0c;输出该链…

细说STM32F407单片机轮询方式读写SPI FLASH W25Q16BV

目录 一、工程配置 1、时钟、DEBUG 2、GPIO 3、SPI2 4、USART6 5、NVIC 二、软件设计 1、FALSH &#xff08;1&#xff09;w25flash.h &#xff08;2&#xff09; w25flash.c 1&#xff09;W25Q16基本操作指令 2&#xff09;计算地址的辅助功能函数 3&#xff09;器…

框架程序设计-简答以及论述

目录 maven的pom作用&#xff1a; Pointcut("execution(*com.example.dome.*.*(……))") 缓存的作用&#xff0c;redis配置过程 Redis配置过程&#xff1a; SpringBoot缓存配置过程&#xff1a; AOP的五种增强注解&#xff1a; 论述题&#xff1a;包结构作用、…

如何在谷歌浏览器中启用语音搜索

想象一下&#xff0c;你正在拥挤的地铁上&#xff0c;双手都拿着沉重的购物袋&#xff0c;突然你想搜索附近的咖啡馆。此时如果你能通过语音而不是打字来进行搜索&#xff0c;那将多么的便利&#xff01;在谷歌浏览器中&#xff0c;启用语音搜索功能就是这么简单而高效&#xf…

C语言从入门到放弃教程

C语言从入门到放弃 1. 介绍1.1 特点1.2 历史与发展1.3 应用领域 2. 安装2.1 编译器安装2.2 编辑器安装 3. 第一个程序1. 包含头文件2. 主函数定义3. 打印语句4. 返回值 4. 基础语法4.1 注释4.1.1 单行注释4.1.2 多行注释 4.2 关键字4.2.1 C语言标准4.2.2 C89/C90关键字&#xf…

实力认可 | 通付盾入选《ISC.AI 2024创新能力全景图谱》五项领域

近日&#xff0c;ISC.AI 2024创新能力百强&#xff08;以下简称“创新百强”&#xff09;正式发布《ISC.AI 2024创新能力全景图谱》。该全景图谱是由政企、资本、高校、行业力量共同完成了领域划分、综合创新等标准的制定&#xff0c;整合梳理了参评的300余家数字安全厂商、120…

Vue3项目中引入TailwindCSS(图文详情)

Vue3项目中引入TailwindCSS&#xff08;图文详细&#xff09; Tailwind CSS 是一个实用工具优先的 CSS 框架&#xff0c;提供丰富的低级类&#xff08;如 text-center、bg-blue-500&#xff09;&#xff0c;允许开发者通过组合这些类快速构建自定义设计&#xff0c;而无需编写…

WordPress File Upload 插件 任意文件读取漏洞复现(CVE-2024-9047)

0x01 产品简介 WordPress File Upload插件是一款功能强大的WordPress站点文件上传插件,它允许用户在WordPress站点中的文章、页面、侧边栏或表单中轻松上传文件到wp-contents目录中的任何位置。该插件使用最新的HTML5技术,确保在现代浏览器和移动设备上都能流畅运行,同时也…

GFPS扩展技术原理(七)-音频切换消息流

音频切换消息流 Seeker和Provider通过消息流来同步音频切换能力&#xff0c;触发连接做切换&#xff0c;获取或设置音频切换偏好&#xff0c;通知连接状态等等。为此专门定义了音频切换消息流Message Group 为0x07&#xff0c;Message codes如下&#xff1a; MAC of Audio s…

Java开发经验——系统迁移经验

摘要 本文全面介绍了系统迁移的各个关键步骤和策略&#xff0c;包括需求分析、数据迁移、系统集成、功能优化、业务连续性保障、用户迁移、性能测试、切换与回滚机制、文档转移等。同时&#xff0c;探讨了通用迁移方案、挑战应对措施、不同规模系统的迁移策略&#xff0c;以及…

JavaWeb - ⭐ AOP 面相切面编程原理及用户校验功能实战

一、概述 定义&#xff1a; AOP (Aspect Oriented Programming 面向切面编程) &#xff0c;一种面向方法编程的思想 功能&#xff1a;管理 bean 对象的过程中&#xff0c;通过底层的动态代理机制对特定方法进行功能的增强或改变 实现方式&#xff1a;动态代理技术&#xff0c…

MFC案例:图片文件转图标(ico)格式

本案例程序目的是将一般图像文件转换成图标格式(ico)。实现起来不是很复杂&#xff0c;这里为了介绍MFC的具体使用方法&#xff0c;在程序界面上分成几个功能块&#xff0c;包括&#xff1a;打开图像文件、选择ICON大小、转换、预览、保存等。相关具体步骤如下&#xff1a; 一、…

Scala_【2】变量和数据类型

第二章 注释标识符的命名规范命名规则关键字 变量字符串输出数据类型关系变量和数据类型整数类型&#xff08;Byte、Short、Int、Long&#xff09;浮点类型&#xff08;Float、Double&#xff09;字符类型&#xff08;Char&#xff09;布尔类型&#xff08;Boolean&#xff09;…

R语言数据分析案例46-不同区域教育情况回归分析和探索

一、研究背景 教育是社会发展的基石&#xff0c;对国家和地区的经济、文化以及社会进步起着至关重要的作用。在全球一体化进程加速的今天&#xff0c;不同区域的教育发展水平呈现出多样化的态势。这种差异不仅体现在教育资源的分配上&#xff0c;还表现在教育成果、教育投入与…

8086汇编(16位汇编)学习笔记03.汇编指令

8086汇编(16位汇编)学习笔记03.汇编指令-C/C基础-断点社区-专业的老牌游戏安全技术交流社区 - BpSend.net 指令种类 数据传送指令算数运算类指令位操作类指令串操作类指令控制转移类指令处理器控制类指令 数据传送类指令 **传送类指令不影响标志位&#xff0c;**除了标志位传…

Antd react上传图片格式限制

限制分辨率&#xff08;像素&#xff09; <a-upload :before-upload"beforeUpload">// 上传图片宽高比例限制const beforeUpload file > {return new Promise((resolve, reject) > {// // 图片类型限制// let isJpgOrPng file.type image/png || fil…