Caffeine Cache解析(一):接口设计与TinyLFU

news2024/10/21 12:28:41

Caffeine is a high performance Java caching library providing a near optimal hit rate.

  • 自动加载value, 支持异步加载
  • 基于size的eviction:frequency and recency
  • 基于时间的过期策略:last access or last write
  • 异步更新value
  • key支持weak reference
  • value支持weak reference和soft reference
  • 淘汰(或移除)通知
  • 缓存获取数据统计

Caffeine的性能benchmark可参考Caffeine Benchmarks,
可以看到Caffeine在不同读写比的情况下, 吞吐量比Guava Cache和Jdk内置的HashMap都有较大提升。
接下来了解下Caffeine的使用、接口设计和TinyLFU简介。

使用

        // manual cache,Cache-Aside模式
        Cache<String, String> cache = Caffeine.newBuilder()
                                          .expireAfterWrite(Duration.ofHours(1))
                                          .build();
        
        // null表示不存在key
        @Nullable String val = cache.getIfPresent("hello");
        if (val == null) {
            cache.put("hello", "world");
        }
        
        // key不存在则走后面的loading function
        String val2 = cache.get("hello", key -> "world");


        // loading cache,Read-Through模式
        LoadingCache<String, String> loadingCache = Caffeine.newBuilder()
                                                 .expireAfterAccess(Duration.ofMinutes(10))
                                                 .maximumSize(2000)
                                                 .build(new CacheLoader<String, String>() {
                                                     @Override
                                                     public @Nullable String load(@NonNull String s) throws Exception {
                                                         // your loading logic
                                                         return "";
                                                     }
                                                 });
        // 不存在会自动loading
        String val3 = loadingCache.get("hello");

接口设计

CacheCache按不同维度划分:

  • kv是否有限:Bounded or Unbounded,判断参见方法com.github.benmanes.caffeine.cache.Caffeine#isBounded,大部分场景都使用BoundedCache
  • 是否自动loading: ManualCache和LoadingCache
  • 是否异步: Cache和AsyncCache

对应接口UML如下(实现类只画出了BoundedCache),其接口和类均位于com.github.benmanes.caffeine.cache包下:

可以看到,核心的kv存储是放在了LocalCache接口(本质是一个ConcurrentMap)下,而其他的Loading和Async接口在存储基础上附加了自动加载value和异步加载的能力,以同步接口为例,接口能力如下:

  • Cache: 提供缓存基础能力,包含设置、读取、失效、获取缓存统计数据等功能;
  • LoadingCache: 提供自动加载能力,在Cache基础上新增不存在则loading value的读取以及refresh方法;
  • LocalCache: 提供核心存储能力,线程安全和原子能力保证,继承自java.util.concurrent.ConcurrentMap
  • LocalManualCache: 基于LocalCache做存储的非自动Loading Cache;
  • LocalLoadingCache: 继承自LocalManualCache,新增Loading功能。

关于以上接口的一个关键抽象实现类BoundedLocalCache,其作用解释如下:

This class performs a best-effort bounding of a ConcurrentHashMap using a page-replacement algorithm to determine which entries to evict when the capacity is exceeded.

TinyLFU & W-TinyLFU

在看BoundedLocalCache类前先来了解下TinyLFU & W-TinyLFU算法,
算法出自论文:TinyLFU: A Highly Efficient Cache Admission Policy

  • admission policy:控制一个元素是否能进入缓存
  • eviction policy:当缓存满了时选择哪一个元素剔除缓存

论文中提出的TinyLFU指的是admission policy,
TinyLFU可以和 LRU 、SLRU 的eviction policy组合。

比如 论文中使用W-TinyLFU + LRU + SLRU的组合进行实验:

Window Tiny LFU (W-TinyLFU) … consists of two cache areas.
The main cache employs the SLRU eviction policy and TinyLFU admission policy
while the window cache employs an LRU eviction policy without any admission policy.

可以看到 W-TinyLFU 的main cache area 使用 TinyLFU 作为 admission policy。

TinyLFU 在 LFU的基础上 加了Tiny,而Tiny体现在counter计数(和frequency正相关) 的记录上。
通常大部分缓存的元素访问频率都会很小,如果使用integer来记录counter计数,会导致空间浪费,因此
TinyLFU 借助 approximate counting scheme 来记录counter计数,其原理和bloom filter类似,而 schema的具体实现有:

  • Counting Bloom Filter
  • CM-Sketch : Caffeine中使用该实现,参见类com.github.benmanes.caffeine.cache.FrequencySketch,论文可参考:An Improved Data Stream Summary: The Count-Min Sketch and its Applications

Caffeine中的CM-Sketch使用4bit记录counter次数,最大只能到15,
并使用long[]类型存储,一个元素可存储16个计数器,long[]即相当于论文中的二维数组。

此外还增加了一个DoorKeeper即一个Bloom Filter来优先存储counter计数为1的元素,大于1的才会进入CM-Sketch结构中。

此外,TinyLFU利用Freshness Mechanism保证TinyLFU计数器记录的次数不会无限制扩大:

Every time we add an item to the approximation sketch, we increment a counter.
Once this counter reaches the sample size (W), we divide it and all other counters in the
approximation sketch by 2.

对应的可以在FrequencySketch类的increment方法中找到reset方法的调用:

// This class maintains a 4-bit CountMinSketch.
// The maximum frequency of an element is limited to 15 (4-bits) 
// and an aging process periodically halves the popularity of all elements.
final class FrequencySketch<E> {
  ...
  int sampleSize;
  int size;

  public void ensureCapacity(@NonNegative long maximumSize) {
    ...
    sampleSize = (maximumSize == 0) ? 10 : (10 * maximum);
    if (sampleSize <= 0) {
      sampleSize = Integer.MAX_VALUE;
    }
    size = 0;
  }

  // 计数器次数小于15时才会增加计数器
  public void increment(@NonNull E e) {
    ...
    boolean added = ...
    if (added && (++size == sampleSize)) {
      reset();
    }
  }
  ...
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

RK3588部署及其RKNPU工具链使用学习

文章目录 RKNPU 推理框架推理软件框架RKNPU 硬件层&#xff1a;RKNPU 驱动层&#xff1a;RKNPU 应用层 RKNN 模型RKNN 的工具链介绍RKNN 软件栈整体介绍RKNN-Toolkit2 功能介绍RKNPU2-SDK总结 开发环境搭建PC 端采用 虚拟机上的 Ubunt20.04 系统安装 anconda通过 conda 创建虚拟…

机器学习“捷径”:自动特征工程全面解析

引言 在机器学习项目中&#xff0c;特征工程是影响模型性能的关键步骤。它通过从原始数据中提取出更有用的特征&#xff0c;帮助模型更好地捕捉数据中的模式。然而&#xff0c;传统的特征工程过程往往需要大量的领域知识和实验调整&#xff0c;是一项耗时费力的工作。 近年来…

关于modbus与HMI车载侧屏通信的错误机制处理

目录 1.关于6个人机交互功能按钮逻辑图设计 2.错误处理机制 1.关于6个人机交互功能按钮逻辑图设计 初次的设计想法是按钮亮表示大家能按&#xff0c;但要是想在按一次&#xff0c;发送有效数据&#xff0c;就得先按亮&#xff0c;在按灭。这里以上料区为例&#xff0c;其它区…

Midjourney中文版:创意无界,绘梦成真

在数字艺术的浩瀚宇宙中&#xff0c;Midjourney中文版如同一颗璀璨的新星&#xff0c;以其独特的魅力和无限可能&#xff0c;引领着每一位创作者探索创意的无限边界。作为专为国内用户打造的AI绘画工具&#xff0c;Midjourney中文版不仅继承了原版的核心优势&#xff0c;更在本…

基于cloudreve(Docker应用)搭建网盘服务,用于目录的分享和在线预览。

文章目录 I 基于cloudreve(Docker应用)搭建网盘服务安装主要功能设置角色最大容量II 知识扩展:网盘类的文件预览需求背景: iOS可以直接预览PDF等常见格式文件,但是Android浏览器需要先下载文件,才能查看文件内容,因此需要搭建支持目录的分享和在线预览的MinIO文件服务提供…

【Redis】Zset类型常用命令

文章目录 一. Zset有序集合简介.二. 添加元素相关命令.2.1 向有序集合中添加元素(zadd) 三. 查询元素相关操作.3.1 查询有序集合中的元素个数( zcard zcount)3.2 查询指定区间内的元素(zrange zrevrange zrangebyscore)3.3 查询有序集合中指定成员的排名(zrank zrevrank )3.4 查…

AI大模型学习路线路径,巨详细!

大模型技术已经成为推动人工智能发展的关键力量。无论你是初学者还是有经验的开发者&#xff0c;想要掌握大模型应用&#xff0c;都需要遵循一定的学习路线。 从核心技术解析到模型微调与私有化部署&#xff0c;逐步深入大模型应用的世界。 这份学习路线图详细的介绍了那年每…

规划控制复现:Apollo LQR横向控制(算法原理推导与流程)

本文在前文已经搭建好的规划控制验证平台中进行LQR算法的复现&#xff1a; 1.车辆动力学建模 汽车轨迹跟踪误差模型示意图如下&#xff1a; 为车辆横向速度,为车辆纵向速度;和 分别为质心到前、 后轴的距离 ; 为车辆的横 摆角 ; 和 分别为车辆前 、 后轮的侧偏角。并设车辆…

【C++】哈希表的模拟实现

目录 一、闭散列&#xff08;开放定址定法&#xff09; 1、哈希表的结构&#xff1a; 2、哈希表的插入&#xff1a; 3、哈希表的查找&#xff1a; 4、哈希表的删除&#xff1a; 二、开散列&#xff08;哈希桶&#xff09; 1、哈希表的结构&#xff1a; 2、构造与析构&a…

若依前后分离版集成积木报表进行token传递

若依分离板集成积木报表就不说了需要的请移步&#xff1a;若依前后分离版集成积木报表-CSDN博客 考虑到前端摸鱼不干活,所以一般都是前后端都干&#xff0c;我这里前后端都搞上&#xff0c;你们直接抄&#xff0c;抄完接着去摸鱼&#xff0c;代码不美观&#xff0c;轻喷 一、…

【JavaEE】【多线程】synchronized和死锁

目录 一、synchronized详解1.1 互斥1.2 可重入 二、死锁2.1 死锁成因2.2 避免死锁 一、synchronized详解 1.1 互斥 synchronized 会起到互斥效果, 某个线程执行到某个对象的 synchronized 中时, 其他线程如果也执行到 同一个对象 synchronized 就会阻塞等待. 语法&#xff1…

AI时代程序员何去何从?提升自我还是被淘汰出局!

AI 在编程界的使用变得越来越普遍了。随着 ChatGPT 的横空出世&#xff0c;各种大语言模型如雨后春笋不断出现。国外如谷歌 Bard、Anthropic 的 Claude&#xff0c;国内如百度文心一言、阿里通义千问、讯飞星火认知大模型、昆仑万维天工大模型等。 想想看&#xff0c;以前得花好…

支持国密算法的数字证书-国密SSL证书详解

在互联网中&#xff0c;数字证书作为标志通讯各方身份信息的数字认证而存在&#xff0c;常见的数字证书大都采用国际算法&#xff0c;比如RSA算法、ECC算法、SHA2算法等。随着我国加强网络安全技术自主可控的大趋势&#xff0c;也出现了支持国密算法的数字证书-国密SSL证书。那…

【网络安全】缓存欺骗问题之查看个人资料接口

未经许可,不得转载。 文章目录 正文正文 目标网站 target.com,查看个人资料页面时,API 端点为/get_user,完整的 URL 是 https://target.com/web-api/v1/get_user?timestamp=123456(其中 timestamp 是一个易受攻击的参数)。 我注意到响应中有一个 cf-cache-status= MISS…

k8s部署Kafka集群超详细讲解

准备部署环境 Kubernetes集群信息 NAMEVERSIONk8s-masterv1.29.2k8s-node01v1.29.2k8s-node02v1.29.2 Kafka&#xff1a;3.7.1版本&#xff0c;apche版本 Zookeeper&#xff1a;3.6.3版本 准备StorageClass # kubectl get sc NAME PROVISIONER RECLA…

Docker安装ActiveMQ镜像以及通过Java生产消费activemq示例

拉取镜像 docker pull docker.io/webcenter/activemq 启动容器 docker run -d --name myactivemq -p 61616:61616 -p 8162:8161 docker.io/webcenter/activemq:latest 这样就代表启动成功了 浏览器访问 http://localhost:8162/ admin admin 开启验证 修改配置文件/opt/ac…

关于k8s集群高可用性的探究

1. k8s的高可用的核心是什么&#xff1f; 说到核心、本质 意味着要从物理层来考虑技术 k8s是一个容器编排管理工具&#xff0c;k8s受欢迎的时机 是docker容器受欢迎时&#xff0c;因为太多的docker容器&#xff0c;管理起来是一个大工程 那么刚好k8s是google自己用了十来年…

STM32L031F6P6基于CubeMX的串口通信调试笔记

用CubeMX创建项目 本实例用的PA14、PA13两个引脚&#xff0c;LPUART1。 对串口参数进行设置&#xff1a; 开启串口中断&#xff1a; 时钟源设置成内部高频时钟&#xff1a; 对项目进行设置&#xff1a; 生成代码&#xff1a; 在串口初始化函数中加入 __HAL_UART_ENA…

Asp.net Core MVC 动态路由

动态路由 asp.net core 3.0 就支持了 // 映射关系public class TranslationDatabase{private static Dictionary<string, Dictionary<string, string>> Translations new Dictionary<string, Dictionary<string, string>>{{"en", new Dictio…

《Vue3 踩坑》expose 和 defineExpose 暴露属性或方法注意事项

选项式写法 使用 选项式API - 状态选项 - expose 一定要注意&#xff1a; 接下来&#xff0c;进一步看示例说明&#xff1a; 设置 expose 仅显示列出的属性/方法才能被父组件调用&#xff1b;代码第 2 行&#xff0c;父组件可访问属性 a 和 方法 myFunc01&#xff0c;不可访…