本地缓存:为什么要用本地缓存?用它会有什么问题

编程开发   © 文章版权由 admin 解释,禁止匿名转载

#楼主# 2022-6-30

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

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

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

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

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

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

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

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

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

代码实现

com.google.guava
guava
31.1-jre


@Slf4j
public class GuavaCacheTest {
public static void main(String[] args) throws ExecutionException {
Cache 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;
}
}

成为第一个回答人

评论

登录后才可发表内容
  • 主题

    1

  • 帖子

    13

  • 关注者

    0

Copyright © 2019 凯特网.   Powered by HYBBS 2.3.4  

Runtime:0.0890s Mem:2051Kb