不是!我之前真没发现Redis+Caffeine能这么用……(之前的我不是现在的我是什么哲学)

不是!我之前真没发现Redis+Caffeine能这么用……(之前的我不是现在的我是什么哲学)

目录

一、背景

二、为什么要使用本地缓存

三、设计一个本地内存需要有什么功能

四、本地缓存方案选型

1、使用ConcurrentHashMap实现本地缓存

2、基于Guava Cache实现本地缓存

3、Caffeine

4、Encache

五、本地缓存问题及解决

1、缓存一致性

2、如何提高本地缓存命中率

3、本地内存的技术选型问题

一、背景

在高性能的服务架构设计中,缓存是一个不可或缺的环节。在实际的项目中,我们通常会将一些热点数据存储到Redis或Memcached 这类缓存中间件中,只有当缓存的访问没有命中时再查询数据库。在提升访问速度的同时,也能降低数据库的压力。

随着不断的发展,这一架构也产生了改进,在一些场景下可能单纯使用Redis类的远程缓存已经不够了,还需要进一步配合本地缓存使用,例如Guava cache或Caffeine,从而再次提升程序的响应速度与服务性能。于是,就产生了使用本地缓存作为一级缓存,再加上远程缓存作为二级缓存的两级缓存架构。

在先不考虑并发等复杂问题的情况下,两级缓存的访问流程可以用下面这张图来表示:

二、为什么要使用本地缓存

  • 本地缓存基于本地环境的内存,访问速度非常快,对于一些变更频率低、实时性要求低的数据,可以放在本地缓存中,提升访问速度
  • 使用本地缓存能够减少和Redis类的远程缓存间的数据交互,减少网络I/O开销,降低这一过程中在网络通信上的耗时

三、设计一个本地内存需要有什么功能

  • 存储,并可以读、写;
  • 原子操作(线程安全),如ConcurrentHashMap
  • 可以设置缓存的最大限制;
  • 超过最大限制有对应淘汰策略,如LRU、LFU
  • 过期时间淘汰,如定时、懒式、定期;
  • 持久化
  • 统计监控

四、本地缓存方案选型

1、使用ConcurrentHashMap实现本地缓存

缓存的本质就是存储在内存中的KV数据结构,对应的就是jdk中线程安全的ConcurrentHashMap,但是要实现缓存,还需要考虑淘汰、最大限制、缓存过期时间淘汰等等功能;

优点是实现简单,不需要引入第三方包,比较适合一些简单的业务场景。缺点是如果需要更多的特性,需要定制化开发,成本会比较高,并且稳定性和可靠性也难以保障。对于比较复杂的场景,建议使用比较稳定的开源工具。

2、基于Guava Cache实现本地缓存

Guava是Google团队开源的一款 Java 核心增强库,包含集合、并发原语、缓存、IO、反射等工具箱,性能和稳定性上都有保障,应用十分广泛。Guava Cache支持很多特性:

  • 支持最大容量限制
  • 支持两种过期删除策略(插入时间和访问时间)
  • 支持简单的统计功能
  • 基于LRU算法实现

使用代码如下:

<dependency>

<groupId>com.google.guava</groupId>

<artifactId>guava</artifactId>

<version>31.1-jre</version>

</dependency>

@Slf4j

public class GuavaCacheTest {

public static void main(String[] args) throws ExecutionException {

Cache<String, String> cache = CacheBuilder.newBuilder()

.initialCapacity(5) // 初始容量

.maximumSize(10) // 最大缓存数,超出淘汰

.expireAfterWrite(60, TimeUnit.SECONDS) // 过期时间

.build();

String orderId = String.valueOf(123456789);

// 获取orderInfo,如果key不存在,callable中调用getInfo方法返回数据

String orderInfo = cache.get(orderId, () -> getInfo(orderId));

log.info("orderInfo = {}", orderInfo);

}

private static String getInfo(String orderId) {

String info = "";

// 先查询redis缓存

log.info("get data from redis");

// 当redis缓存不存在查db

log.info("get data from mysql");

info = String.format("{orderId=%s}", orderId);

return info;

}

}

3、Caffeine

Caffeine是基于java8实现的新一代缓存工具,缓存性能接近理论最优。可以看作是Guava Cache的增强版,功能上两者类似,不同的是Caffeine采用了一种结合LRU、LFU优点的算法:W-TinyLFU,在性能上有明显的优越性

使用代码如下:

<dependency>

<groupId>com.github.ben-manes.caffeine</groupId>

<artifactId>caffeine</artifactId>

<version>2.9.3</version>

</dependency>

@Slf4j

public class CaffeineTest {

public static void main(String[] args) {

Cache<String, String> cache = Caffeine.newBuilder()

.initialCapacity(5)

// 超出时淘汰

.maximumSize(10)

//设置写缓存后n秒钟过期

.expireAfterWrite(60, TimeUnit.SECONDS)

//设置读写缓存后n秒钟过期,实际很少用到,类似于expireAfterWrite

//.expireAfterAccess(17, TimeUnit.SECONDS)

.build();

String orderId = String.valueOf(123456789);

String orderInfo = cache.get(orderId, key -> getInfo(key));

System.out.println(orderInfo);

}

private static String getInfo(String orderId) {

String info = "";

// 先查询redis缓存

log.info("get data from redis");

// 当redis缓存不存在查db

log.info("get data from mysql");

info = String.format("{orderId=%s}", orderId);

return info;

}

}

4、Encache

Encache是一个纯Java的进程内缓存框架,具有快速、精干等特点,是Hibernate中默认的CacheProvider。同Caffeine和Guava Cache相比,Encache的功能更加丰富,扩展性更强:

  • 支持多种缓存淘汰算法,包括LRU、LFU和FIFO
  • 缓存支持堆内存储、堆外存储、磁盘存储(支持持久化)三种
  • 支持多种集群方案,解决数据共享问题

使用代码如下:

<dependency>

<groupId>org.ehcache</groupId>

<artifactId>ehcache</artifactId>

<version>3.9.7</version>

</dependency>

@Slf4j

public class EhcacheTest {

private static final String ORDER_CACHE = "orderCache";

public static void main(String[] args) {

CacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder()

// 创建cache实例

.withCache(ORDER_CACHE, CacheConfigurationBuilder

// 声明一个容量为20的堆内缓存

.newCacheConfigurationBuilder(String.class, String.class, ResourcePoolsBuilder.heap(20)))

.build(true);

// 获取cache实例

Cache<String, String> cache = cacheManager.getCache(ORDER_CACHE, String.class, String.class);

String orderId = String.valueOf(123456789);

String orderInfo = cache.get(orderId);

if (StrUtil.isBlank(orderInfo)) {

orderInfo = getInfo(orderId);

cache.put(orderId, orderInfo);

}

log.info("orderInfo = {}", orderInfo);

}

private static String getInfo(String orderId) {

String info = "";

// 先查询redis缓存

log.info("get data from redis");

// 当redis缓存不存在查db

log.info("get data from mysql");

info = String.format("{orderId=%s}", orderId);

return info;

}

}

五、本地缓存问题及解决

1、缓存一致性

两级缓存与数据库的数据要保持一致,一旦数据发生了修改,在修改数据库的同时,本地缓存、远程缓存应该同步更新。

解决方案1: MQ

一般现在部署都是集群部署,有多个不同节点的本地缓存; 可以使用MQ的广播模式,当数据修改时向MQ发送消息,节点监听并消费消息,删除本地缓存,达到最终一致性;

解决方案2:Canal + MQ

如果你不想在你的业务代码发送MQ消息,还可以适用近几年比较流行的方法:订阅数据库变更日志,再操作缓存。Canal 订阅Mysql的 Binlog日志,当发生变化时向MQ发送消息,进而也实现数据一致性。

2、如何提高本地缓存命中率

合理设置缓存过期时间、选择合适的缓存淘汰算法、优化数据存储等

3、本地内存的技术选型问题

  • 从易用性角度,Guava Cache、Caffeine和Encache都有十分成熟的接入方案,使用简单。
  • 从功能性角度,Guava Cache和Caffeine功能类似,都是只支持堆内缓存,Encache相比功能更为丰富
  • 从性能上进行比较,Caffeine最优、GuavaCache次之,Encache最差(下图是三者的性能对比结果)

对于本地缓存的方案中,我比较推荐Caffeine,性能上遥遥领先。

虽然Encache功能更为丰富,甚至提供了持久化和集群的功能,但是这些功能完全可以依靠其他方式实现。真实的业务工程中,建议使用Caffeine作为本地缓存,另外使用redis或者memcache作为分布式缓存,构造多级缓存体系,保证性能和可靠性。

作者丨Gimtom

来源丨网址:https://blog.csdn.net/One_hundred_nice/article/details/123950638

dbaplus社群欢迎广大技术人员投稿,投稿邮箱:editor@dbaplus.cn

特别声明:[不是!我之前真没发现Redis+Caffeine能这么用……(之前的我不是现在的我是什么哲学)] 该文观点仅代表作者本人,今日霍州系信息发布平台,霍州网仅提供信息存储空间服务。

猜你喜欢

由力:《亮剑》中的“孔捷”,演技精湛,一位非常低调的好演员(亮剑悠久)

1983年,他终于迈出了这一步,参演了自己人生中的第一部电影《生死树》。 时至今日,虽然由力已经远离了银幕多年,但他当年那份纯粹的演艺初心,依旧让人动容。由力的经历,也许并不是一部光辉灿烂的传奇,但他那份为梦…

由力:《亮剑》中的“孔捷”,演技精湛,一位非常低调的好演员(亮剑悠久)

抖音代运营机构哪家合作案例多?盘点合作多的抖音运营机构(抖音代运营机构哪家好)

逐天科技凭借多年的专业服务,在业内积累了良好口碑。 逐天科技以其在抖音运营领域丰富的合作案例、高性价比、一站式服务、专业内容编辑与运营规划以及良好口碑,成为企业抖音运营的不二之选。其优势不仅在于深厚的行业经…

抖音代运营机构哪家合作案例多?盘点合作多的抖音运营机构(抖音代运营机构哪家好)

王玉雯真的讨人喜欢,大大方方,甜妹御姐(王玉雯vlog)

在美女如云的娱乐圈中,王玉雯的美貌具有一种独特的辨识度——她将看似矛盾的两种特质完美融合:五官精致如江南水墨,身量却高挑似北国白杨;气质清新如校园初恋,气场却能驾驭性感深V。特别值得称道的是,这种性感装扮在她…

王玉雯真的讨人喜欢,大大方方,甜妹御姐(王玉雯vlog)

清鼻堂实地测评:5 款空气净化器对慢性鼻炎改善效果对比(清鼻堂是真的假的知乎)

A款采用HEPA+ 活性炭双层滤网,对PM2.5和甲醛的过滤效率达99%,但面对花粉等大颗粒过敏原时,吸附力稍显不足,慢性鼻炎者在春秋季可能仍有轻微不适。B款的复合滤网加入了抗过敏因子,实测在花粉浓度超标的环…

清鼻堂实地测评:5 款空气净化器对慢性鼻炎改善效果对比(清鼻堂是真的假的知乎)

《花儿与少年》第七季“剧本式”的真人秀,还叫真人秀吗?(《花儿与少年》同心季在线观看)

如此编排,难免让人觉得节目中的每一个环节都显得如此精心设计,丝毫没有“随性”的气息,倒像是一场彻底策划好的“表演”。所有这一切,仿佛预定好了的剧本,似乎并没有真正考虑到每个艺人内心的独立意志。最后,马思纯选择…

《花儿与少年》第七季“剧本式”的真人秀,还叫真人秀吗?(《花儿与少年》同心季在线观看)