Guava Cache是一款非常优秀的本地缓存框架,提供简洁易用的 API 供开发者使用。

这篇文章,我们聊聊如何使用 Guava Cache 异步刷新技巧带飞系统性能 。

1 基本用法

首先,在 Java 应用中添加 maven 依赖:

<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>31.0.1-jre</version>
</dependency>

然后编写测试用例:

LoadingCache 是本地缓存工具,支持配置加载函数定时失效等功能。

例子中配置了基于容量进行回收策略,缓存最大容量设置为 100,配置了定时失效刷新函数

  1. 定时失效

配置 expireAfterWrite 后,缓存项在被创建或最后一次更新后的指定时间内会过期。

  1. 刷新函数

配置 refreshAfterWrite 设置刷新时间,当缓存项过期的同时可以重新加载新值 。

我们模拟过期执行 load 方法 / 重新加载执行 reload 方法的流程,执行结果见下图:

执行结果表明:Guava Cache 并没有后台任务线程异步的执行 load 或者 reload 方法。

  1. expireAfterWrite 允许一个线程执行 load 方法,其他线程阻塞等待 。

    当大量线程用相同的 key 获取缓存值时,只会有一个线程进入 load 方法,而其他线程则等待,直到缓存值被生成。这样也就避免了缓存击穿的危险。高并发场景下 ,这样还是会阻塞大量线程。

  2. refreshAfterWrite 允许一个线程执行 load 方法,其他线程返回旧的值。

    单个 key 并发下,使用 refreshAfterWrite ,虽然不会阻塞了,但是如果恰巧同时多个 key 同时过期,还是会给数据库造成压力。

为了提升系统性能,我们可以从如下两个方面来处理 :

  1. 减少过期的频率 ,也就是减少执行 load 方法的频率 ,配置 refresh < expire 。
  2. 采用异步刷新的策略,也就是线程异步加载数据,期间所有请求返回旧的缓存值

2 两种方式实现异步刷新

2.1 重写 reload 方法

2.2 实现 asyncReloading 方法

不管使用哪种方案, 都需要定义单独的线程池来执行刷新任务 。

3 异步刷新 + 多级缓存

2018 年,笔者服务的一家电商公司需要进行 app 首页接口的性能优化。笔者花了大概两天的时间完成了整个方案,采取的是两级缓存模式,同时采用了 Guava 的异步刷新机制。

整体架构如下图所示:

缓存读取流程如下 :

1、业务网关刚启动时,本地缓存没有数据,读取 Redis 缓存,如果 Redis 缓存也没数据,则通过 RPC 调用导购服务读取数据,然后再将数据写入本地缓存和 Redis 中;若 Redis 缓存不为空,则将缓存数据写入本地缓存中。

2、由于步骤1已经对本地缓存预热,后续请求直接读取本地缓存,返回给用户端。

3、Guava 配置了 refresh 机制,每隔一段时间会调用自定义 LoadingCache 线程池(5个最大线程,5个核心线程)去导购服务同步数据到本地缓存和 Redis 中。

优化后,性能表现很好,平均耗时在 5ms 左右,同时大幅度的减少应用 GC 的频率。

该方案依然有瑕疵,一天晚上我们发现 app 端首页显示的数据时而相同,时而不同。

也就是说: 虽然 LoadingCache 线程一直在调用接口更新缓存信息,但是各个服务器本地缓存中的数据并非完成一致。

这说明了两个很重要的点:

1、惰性加载仍然可能造成多台机器的数据不一致;

2、LoadingCache 线程池数量配置的不太合理, 导致了任务堆积。

最终,我们的解决方案是:

1、异步刷新结合消息机制来更新缓存数据,也就是:当导购服务的配置发生变化时,通知业务网关重新拉取数据,更新缓存。

2、适当调大 LoadingCache 的线程池参数,并在线程池埋点,监控线程池的使用情况,当线程繁忙时能发出告警,然后动态修改线程池参数。

4 总结

Guava Cache 非常强大,但它并没有后台任务线程异步的执行 load 或者 reload 方法,而是通过请求线程来执行相关操作。

为了提升系统性能,我们可以从如下两个方面来处理 :

  1. 减少过期的频率 ,也就是减少执行 load 方法的频率 ,配置 refresh < expire 。
  2. 采用异步刷新的策略,也就是线程异步加载数据,期间所有请求返回旧的缓存值

笔者曾经优化过某电商网站的首页接口,使用的方案是: Guava 的异步刷新机制 + 多级缓存 ,取得了非常好得优化效果。

当然,我们在使用这种方式时,依然需要考虑的数据的一致性问题。


参考资料:

https://albenw.github.io/posts/df42dc84/

如果我的文章对你有所帮助,还请帮忙点赞、在看、转发一下,你的支持会激励我输出更高质量的文章,非常感谢!

Guava Cache 异步刷新技巧,你值得拥有!的更多相关文章

  1. Guava Cache在实际项目中的应用

    对于Guava Cache本身就不多做介绍了,一个非常好用的本地cache lib,可以完全取代自己手动维护ConcurrentHashMap. 背景 目前需要开发一个接口I,对性能要求有非常高的要求 ...

  2. Guava Cache,Java本地内存缓存使用实践

    Guava Cache,网上介绍很多,我就不赘述了. 分享一篇好的文章: Guava Cache内存缓存使用实践-定时异步刷新及简单抽象封装 Google Guava 3-缓存 在原作者基础上,我做了 ...

  3. Guava Cache 原理分析与最佳实践

    前言 目前大部分互联网架构 Cache 已经成为了必可不少的一环.常用的方案有大家熟知的 NoSQL 数据库(Redis.Memcached),也有大量的进程内缓存比如 EhCache .Guava ...

  4. 重新认识下JVM级别的本地缓存框架Guava Cache(2)——深入解读其容量限制与数据淘汰策略

    大家好,又见面了. 本文是笔者作为掘金技术社区签约作者的身份输出的缓存专栏系列内容,将会通过系列专题,讲清楚缓存的方方面面.如果感兴趣,欢迎关注以获取后续更新. 通过<重新认识下JVM级别的本地 ...

  5. Spring cache简单使用guava cache

    Spring cache简单使用 前言 spring有一套和各种缓存的集成方式.类似于sl4j,你可以选择log框架实现,也一样可以实现缓存实现,比如ehcache,guava cache. [TOC ...

  6. [Java 缓存] Java Cache之 Guava Cache的简单应用.

    前言 今天第一次使用MarkDown的形式发博客. 准备记录一下自己对Guava Cache的认识及项目中的实际使用经验. 一: 什么是Guava Guava工程包含了若干被Google的 Java项 ...

  7. Guava学习笔记:Guava cache

    缓存,在我们日常开发中是必不可少的一种解决性能问题的方法.简单的说,cache 就是为了提升系统性能而开辟的一块内存空间. 缓存的主要作用是暂时在内存中保存业务系统的数据处理结果,并且等待下次访问使用 ...

  8. Ehcache与Guava Cache的区别浅谈

    最近在做一些缓存改造的场景,有如下一些经验总结: 缓存版本: Ehcache:2.8.3 Guava:17.0 Ehcache支持持久化到本地磁盘,Guava不可以: Ehcache有现成的集群解决方 ...

  9. guava cache

    适用场景 缓存在很多场景下都是相当有用的.例如,计算或检索一个值的代价很高,并且对同样的输入需要不止一次获取值的时候,就应当考虑使用缓存. Guava Cache与ConcurrentMap很相似,但 ...

  10. 第七章 企业项目开发--本地缓存guava cache

    1.在实际项目开发中,会使用到很多缓存技术,而且数据库的设计一般也会依赖于有缓存的情况下设计. 常用的缓存分两种:本地缓存和分布式缓存. 常用的本地缓存是guava cache,本章主要介绍guava ...

随机推荐

  1. stm32开发笔记

    STM32F103C8T6单片机简介 标准库与HAL库区别 寄存器 寄存器众多,需要经常翻阅芯片手册,费时费力: 更大灵活性,可以随心所欲达到自己的目的: 深入理解单片机的运行原理,知其然更知其所以然 ...

  2. 前端三件套系例之JQuery——JQuery基础、JQuery选择器、JQuery文本属性样式操作、JQuery操作DOM

    文章目录 1 JQuery基础 1. 了解jQuery 1.1 什么是jQuery 1.2 什么事JS类库 1.3 常见JS类库 1.4 jQuery的优势 1.5 jQuery的版本 1.6 jQu ...

  3. WebKit Insie: Active 样式表

    WebKit Inside: CSS 样式表的匹配时机介绍了当 HTML 页面有不同 CSS 样式表引入时,CSS 样式表开始匹配的时机.后续文章继续介绍 CSS 样式表的匹配过程,但是在匹配之前,首 ...

  4. ORACLE错误代码一览表,方便大家查询!

    ORACLE错误一览表,方便大家查询! ORA-00001: 违反唯一约束条件 (.) ORA-00017: 请求会话以设置跟踪事件 ORA-00018: 超出最大会话数 ORA-00019: 超出最 ...

  5. pip install numpy -i https://pypi.tuna.tsinghua.edu.cn/simple

    pip install numpy -i https://pypi.tuna.tsinghua.edu.cn/simpleLooking in indexes: https://pypi.tuna.t ...

  6. oauth2单点登录集成

    单点登陆 概念: 单点登录其实就是在多个系统之间建立链接, 打通登录系统, 让同一个账号在多个系统中通用 举个例子: 登录Gmail的时候可以用账号密码登录, 也可以用google账号登录, 而使用g ...

  7. 数据结构与算法(LeetCode) 第二节 链表结构、栈、队列、递归行为、哈希表和有序表

    一.链表结构 1.单向链表节点结构 public class Node{ public int value; public Node next; public Node(int data){ valu ...

  8. 实用的命令行终端增强软件:Tabby

    还是那句话:出众的软件有很多,适合自己的才是最好的. 一.软件介绍 Tabby是一个开源免费软件,支持Windows.macOS和Linux系统.它提供了一个高度可定制的终端界面,可以通过多种方式添加 ...

  9. umich cv-6-2 注意力机制

    这节课中介绍了循环神经网络的第二部分,主要引入了注意力机制,介绍了注意力机制的应用以及如何理解,在此基础上建立了注意力层以及transformer架构 注意力机制 注意力机制 应用与理解 注意力层 t ...

  10. 工控机中部署Ubuntu 22.04 系统

    1.下载Ubuntu系统服务器版本 获取Ubuntu服务器版 | Ubuntu 2.下载启动盘制作工具 UltralSO(试用就可以) 文件 > 打开(Ubuntu.ISO) > 启动 & ...