缓存神器-JetCache

news/2024/9/22 17:30:30/

序言

今天和大家聊聊阿里的一款缓存神器 JetCache。

一、缓存在开发实践中的问题

1.1 缓存方案的可扩展性问题

谈及缓存,其实有许多方案可供选择。例如:Guava Cache、Caffine、Encache、Redis 等。

这些缓存技术都能满足我们的需求,但现在有一个问题是:技术是在不断发展的,若今后有更好的缓存技术出现,如果我们需要替换之前的缓存方案,该怎么办呢?

1.2 缓存的使用问题

之前,我们已经了解到缓存方案有许多,而这些缓存在项目中的使用方式又不尽相同。这无疑将增加我们的学习成本以及开发成本(即:开发人员需要了解并掌握所使用缓存技术的使用方式以及原理)。

现如今我们的项目大多都是分布式环境,在分布式环境中有三大经典的分布式缓存问题:

  1. 缓存穿透
  2. 缓存击穿
  3. 缓存雪崩

针对这些问题,具体的缓存技术似乎并不能解决。那么,这就意味着需要开发人员每次在使用缓存时,都需要手动解决这些问题。针对这些固定的问题,是否可以采用成熟、统一的方案解决呢?

二、JSR-107 规范

在开发过程中,我们经常会用到缓存来提高系统的性能和效率。然而,不同的缓存实现可能会有各自的接口和行为,这就导致了在切换缓存实现或者在不同的缓存实现之间共享数据时会遇到困难。

JSR-107,也被称为 JCache,是由 Java 定义的一项规范。JSR-107 规范定义了一套标准的 Java 缓存 API,使得开发者可以用一致的方式来使用和切换不同的缓存实现。这样,无论你使用哪种缓存技术,只要它们遵循 JSR-107 规范,你就可以用同样的方式来操作缓存

三、JetCache 方案

JetCache 是阿里推出的一个基于 Java 的缓存系统封装,提供统一的 API 和注解来简化缓存的使用。 JetCache提供了比 SpringCache 更加强大的注解,可以原生的支持 TTL、两级缓存、分布式自动刷新,还提供了 Cache接口用于手工缓存操作。 当前有四个实现,RedisCache、TairCache(此部分未在 github 开源)、CaffeineCache(in memory) 和一个简易的 LinkedHashMapCache(in memory),要添加新的实现也是非常简单的。

支持项SpringCacheJetCache
JSR-107支持支持
本地缓存支持支持
远程缓存支持支持
注解缓存支持支持
对象缓存——支持
分布式锁——支持
缓存穿透简单灵活方案支持
缓存击穿简单灵活方案支持
缓存雪崩——灵活方案支持
多级缓存简单灵活方案支持
扩展性支持支持
监控——支持
高级API(异步,原始特性)——支持

上表是由阿里技术提供的与 SpringCache 功能性相关的对比。可以看出 JetCache 功能更加强大,并在许多方面都有着显著的优势。

四、JetCache 快速入门

我们基于 jetcache-starter-redis 包,以注解缓存为例快速带大家体验 JetCache 在处理缓存时有多方便。

4.1 引入 maven 依赖包

<dependency><groupId>com.alicp.jetcache</groupId><artifactId>jetcache-starter-redis</artifactId><version>2.7.5</version>
</dependency>

4.2 编写配置

application.yml 配置文件中添加如下配置:

jetcache:statIntervalMinutes: 15areaInCacheName: falselocal:default:type: linkedhashmapkeyConvertor: fastjsonremote:default:type: rediskeyConvertor: fastjson2broadcastChannel: projectAvalueEncoder: javavalueDecoder: javapoolConfig:minIdle: 5maxIdle: 20maxTotal: 50host: 127.0.0.1port: 6379

4.3 使用 JetCache

  1. 启用注解缓存

    package com.company.mypackage;import com.alicp.jetcache.anno.config.EnableCreateCacheAnnotation;
    import com.alicp.jetcache.anno.config.EnableMethodCache;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
    // 激活 @Cached 注解
    @EnableMethodCache(basePackages = "com.company.mypackage")
    // 激活 @CreateCache 注解
    @EnableCreateCacheAnnotation
    public class MySpringBootApp {public static void main(String[] args) {SpringApplication.run(MySpringBootApp.class);}
    }
  2. 使用注解缓存

    @Service
    public class UserServiceImpl implements UserService {@Resourceprivate UserMapper userMapper;@Override@Cached(name = "cache:user:", key = "#id", expire = 3600, cacheType = CacheType.LOCAL)public User getUserById(Integer id) {return userMapper.selectUserById(id);}
    }
    
  3. 使用效果

    image.png

五、JetCache 功能

5.1 解决缓存穿透

针对缓存穿透,我们通常有两种解决方案:

  1. 缓存空对象
  2. 布隆过滤器

JetCache 采用了第一种方式(即:缓存空对象)来解决缓存穿透问题。我们只需在注解中加上一个属性即可:

@Cached(cacheNullValue = true)

5.2 解决缓存击穿

针对缓存击穿问题,JetCache 提供了两种方式解决:

  1. @CachePenetrationProtect:该注解提供的是 JVM 内存锁级别的保护,旨在将并发重建的请求限制在可控范围。这种方式的核心思想是缓存重建任务可控。
  2. @CacheRefresh:该注解是基于分布式锁的缓存重建,如果对系统的要求较高可采用此种方式。

5.3 解决缓存雪崩

针对缓存雪崩问题,一般在缓存层通过两种方式解决:

  1. 建立多级缓存,多级缓存设置不同过期时间从而形成重叠的数据滑动窗口
  2. 异步维护一块固定缓存,防止缓存失效(兜底方案)

JetCache 针对上面的两种解决方式也给出了对应的方案:

  1. JetCache 可以实现多级缓存
  2. 使用 @CacheRefresh + CacheLoader 维护固定缓存

5.4 实现多级缓存

多级缓存时 JetCache 一大特色,JetCache 多级缓存有以下特点:

  1. JetCache 多级缓存本身可以拥有不同的过期时间,从而构建出多级滑动窗口
  2. JetCache 多级缓存可以简单、直接的避免缓存击穿、缓存雪崩问题
  3. JetCache 默认的注解缓存只支持两级缓存(Local + Remote),但是可以自定义扩展至 N 级
  4. JetCache 缓存可以添加自定义实现的缓存
Cache multiLevelCache = MultiLevelCacheBuilder.createMultiLevelCacheBuilder().addCache(caffeineCache, memCache, redisCache).expireAfterWrite(100, TimeUnit.SECONDS).buildCache();

5.5 缓存失效/更新

有时缓存也是需要管理的。例如:当更新数据库时,使缓存失效或者同步更新缓存。JetCache 可以通过以下两个注解实现缓存失效/更新:

  1. @CacheInvalidate 缓存失效
  2. @CacheUpdate 缓存更新

5.6 编程式创建缓存

之前,我们一直采用注解声明式的创建缓存。但是在某些情况下,我们需要使用编程式创建缓存的方式。JetCache 中可以使用 CacheManager 手动创建缓存。例如:

@Autowired
private CacheManager cacheManager;
private Cache<String, UserDO> userCache;@PostConstruct
public void init() {QuickConfig qc = QuickConfig.newBuilder("userCache").expire(Duration.ofSeconds(100)).cacheType(CacheType.BOTH) // two level cache.syncLocal(true) // invalidate local cache in all jvm process after update.build();userCache = cacheManager.getOrCreateCache(qc);
}

5.7 缓存监控统计

当配置参数 jetcache.statIntervalMinutes 大于 0 时,使用 @CreateCache@Cached 生成的缓存将自带监控。JetCache 会按指定的时间定期通过 logger 输出统计信息。默认输出信息类似如下:
image.png

六、FAQ

本文只简单的介绍了 JetCache 的相关概念,若有特殊开发需求的小伙伴可以自行前去官方文档探索哦。

推荐阅读

  1. 为什么 MySQL 单表数据量最好别超过 2000w
  2. ConcurrentHashMap 源码分析(一)
  3. IoC 思想简单而深邃
  4. ThreadLocal
  5. JDK 动态代理

http://www.ppmy.cn/news/1443793.html

相关文章

图像哈希:DCT篇

Robust image hashing with dominant DCT coefficients 文章信息 作者&#xff1a;唐振军期刊&#xff1a;Optic&#xff08;Q2/3区&#xff09;题目&#xff1a;Robust image hashing with dominant DCT coefficients 目的、实验步骤及结论 目的&#xff1a;使用传统的DCT对…

医院挂号就诊|基于SprinBoot+vue医院挂号就诊系统(源码+数据库+文档)

医院挂号就诊目录 基于SprinBootvue医院挂号就诊系统 一、前言 二、系统设计 三、系统功能设计 1用户信息管理 2 医生信息管理 3公告类型管理 4公告信息管理 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 博主…

Swift字符串

在 Swift 中&#xff0c;Character 和 String 是用于处理文本数据的两个重要类型。 Character Character 是 Swift 中用于表示单个 Unicode 字符的类型。每个 Character 实例都代表一个可见的字符&#xff08;如字母、数字、标点符号等&#xff09;&#xff0c;或者一个不可见的…

IDEA主题美化【保姆级】

前言 一款好的 IDEA 主题虽然不能提高我们的开发效率&#xff0c;但一个舒适简单的主题可以使开发人员更舒适的开发&#xff0c;时常换一换主题可以带来不一样的体验&#xff0c;程序员的快乐就这么简单。话不多说&#xff0c;先上我自己认为好看的主题设置。 最终效果图: 原…

Java NIO概念

Java NIO是什么&#xff1f; Java NIO&#xff0c;全称为Java Non-blocking Input/Output或New IO&#xff0c;是Java平台从JDK 1.4版本开始引入的一套新的输入/输出API。它旨在提供一种更高效、可扩展性更强的IO操作方式&#xff0c;特别适合构建高性能的网络应用和进行大容量…

Linux_Ubuntu18.04安装过程

目录 1. 虚拟机安装2. 虚拟机创建3. Ubuntu x64安装4. 开启重启问题 1. 虚拟机安装 版本&#xff1a;VMware-workstation-full-16.0.exe 下一步 接受 下一步 下一步&#xff0c;注意安装位置。 下一步 下一步 点击安装 等待安装完成。 2. 虚拟机创建 创建新的虚拟机 典型 稍后…

springboot笔记一:idea社区版本创建springboot项目的方式

社区idea 手动maven 创建springboot项目 创建之后修改pom.xml <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:sc…

排序算法(2)快排

交换排序 思想&#xff1a;所谓交换&#xff0c;就是根据序列中两个记录键值的比较结果来对换这两个记录在序列中的位置&#xff0c;交换排序的特点是&#xff1a;将键值较大的记录向序列的尾部移动&#xff0c;键值较小的记录向序列的前部移动。 一、冒泡排序 public static…