尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

拆解Caffeine源码:BoundedLocalCache如何用环形缓冲与双端队列实现高并发

拆解Caffeine源码:BoundedLocalCache如何用环形缓冲与双端队列实现高并发 拆解Caffeine源码BoundedLocalCache如何用环形缓冲与双端队列实现高并发【免费下载链接】caffeineA high performance caching library for Java项目地址: https://gitcode.com/gh_mirrors/ca/caffeineCaffeine 是 Java 生态中性能最强的高性能缓存库之一其核心实现位于 BoundedLocalCache.java。这个类靠两大武器实现高并发**环形缓冲Ring Buffer**负责异步吸收海量读操作**双端队列Deque**负责管理缓存条目的淘汰顺序。本文带你通俗地拆解这套设计理解它为什么读起来快、扛得住并发、命中率还高。Caffeine 核心组件全景一张图看懂 BoundedLocalCache先看官方架构图图中自上而下就是 Caffeine 缓存的完整数据流图中信息量很大先记住四个区域区域组件作用左上get/load读请求入口命中数据后顺手记一笔左下Read Buffer / Write Buffer环形缓冲与无锁队列异步记录读与写中间Window / Probation / Protected三个双端队列即 W-TinyLFU 淘汰策略的核心右下countMinSketch频率草图估算每个条目的热度关键思想一句话读请求从不直接改动淘汰策略的数据结构而是先扔进缓冲区由后台维护任务批量处理。这就是高并发的秘密所在。环形缓冲设计让读操作近乎零成本在BoundedLocalCache中每次缓存命中都会执行类似afterRead的动作把节点offer进读缓冲 BoundedLocalCache.java。读缓冲的实际实现是 BoundedBuffer.java它是一个多生产者、单消费者的无锁环形缓冲。它的几个设计决策非常值得新手理解非阻塞 允许失败多个线程竞争同一个写位置时只尝试一次 CAS失败就放弃FAILED绝不重试、不阻塞。缓存策略允许偶尔漏记一次访问这是用最终一致性换取零等待。有损但可接受缓冲满时FULL直接拒绝新元素。访问顺序只是淘汰策略的参考丢一两个不影响正确性。内存可见性精确控制生产者用 release 语义写元素消费者用 acquire 语义读取再配合 release 清空槽位保证多线程下数据不乱序、不丢。防虚假共享false sharing读、写两个计数器之间垫了上百字节的填充字段BBHeader中的 padding让两个高频写变量落在不同的 CPU 缓存行上避免互相踩缓存。分带Striped设计StripedBuffer.java 在检测到竞争时会动态增加缓冲条带进一步摊薄热点。与之对应写缓冲用的是 MpscGrowableArrayQueue.java——一个可增长的无锁多生产者单消费者队列。因为写操作插入、删除不能丢所以写缓冲与有损的读缓冲形成了鲜明对比。双端队列三空间Window、Probation 与 Protected缓冲区里攒下的读事件最终会被维护任务应用到三个按访问顺序排列的双端队列上实现 AccessOrderDeque.java 提供基础双向链表能力Window准入窗口约 1% 容量新条目从这里入门按 LRU 顺序排列。刚被频繁访问的新贵待在这里。Probation试跑区约 19% 容量条目从窗口滑入此处接受考验再次被访问就升级否则就是被淘汰的头号候选。Protected保护区约 80% 容量久经考验的热门条目安居于此按访问顺序排队。淘汰时并不盲选FrequencySketchFrequencySketch.java会先比较新候选者与受害者的历史访问频率频率更高者才能留下——这就是W-TinyLFU策略让 Caffeine 在扫描型负载下依然保持高命中率。更妙的是窗口与主空间的比例不是写死的WindowClimber.java 通过爬山法根据命中率曲线动态调整两者比例让缓存自动适应负载变化。异步维护任务把维护成本摊到每次写入上缓冲区和队列都不是攒着不处理。BoundedLocalCache采用了一套巧妙的调度每次写操作put/remove之后线程顺手检查是否需要执行维护任务如果需要就自愿认领执行而不会专门启动新线程抢占锁。维护周期内依次完成drainReadBuffer → drainWriteBuffer → drainKeyReferences → drainValueReferences → expireEntries → evictEntries → PerformCleanupTask这样访问顺序的更新、过期检查、容量淘汰都在后台批量完成且维护开销被平摊到所有写线程身上。读路径因此极短查 HashMap、更新统计、往环形缓冲里扔个引用三步完事。高并发吞吐表现基准测试数据说话官方 JMH 基准jmh 目录显示得益于环形缓冲、无锁队列和批量维护的设计Caffeine 在读、写、读写混合场景下的吞吐都保持在很高水位对比一下纯读与纯写场景的表现总结三点记住 Caffeine 的高并发之道环形缓冲异步化读事件读不锁化、不阻塞、允许丢失把淘汰策略的更新延迟到后台批量执行BoundedBuffer.java。双端队列分区管理热度Window / Probation / Protected 三个访问顺序队列 频率草图实现 W-TinyLFU 高命中淘汰AccessOrderDeque.java。⚙️维护成本人人分摊写操作后自愿执行维护任务配合无锁写缓冲MpscGrowableArrayQueue.java整体架构以最终一致换极致并发。理解这套环形缓冲 双端队列的组合拳你就不难明白为什么 Caffeine 能在高并发场景下同时兼顾低延迟与高命中率了。【免费下载链接】caffeineA high performance caching library for Java项目地址: https://gitcode.com/gh_mirrors/ca/caffeine创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表