关于内存缓存的设计

1 篇文章 0 订阅

关于缓存的设计

一、背景

随着流量的增加,DB压力增大,读写能力也随之下降,甚至造成DB故障,服务不可用,缓存应运而生。

二、内存缓存框架的比较

比较项ConcurrentHashMapLRUMapEhcacheGuava CacheCaffeine
读写性能很好,分段锁一般,全局加锁好,需要做淘汰操作很好
淘汰算法LRU,一般支持多种淘汰算法,LRU,LFU,FIFOLRU,一般W-TinyLFU, 很好
功能丰富程度功能比较简单功能比较单一功能很丰富功能很丰富,支持刷新和虚引用等功能和Guava Cache类似
工具大小jdk自带类,很小基于LinkedHashMap,较小很大,最新版本1.4MB是Guava工具类中的一个小部分,较小一般,最新版本644KB
是否持久化
是否支持集群

三、选择合适的内存缓存

  1. 对于ConcurrentHashMap来说,比较适合缓存比较固定不变的元素,且缓存的数量较小的。虽然从上面表格中比起来有点逊色,但是其由于是jdk自带的类,在各种框架中依然有大量的使用,比如我们可以用来缓存我们反射的Method,Field等等;也可以缓存一些链接,防止其重复建立。在Caffeine中也是使用的ConcurrentHashMap来存储元素。
  2. 对于LRUMap来说,如果不想引入第三方包,又想使用淘汰算法淘汰数据,可以使用这个。
  3. 对于Ehcache来说,由于其jar包很大,较重量级。对于需要持久化和集群的一些功能的,可以选择Ehcache。笔者没怎么使用过这个缓存,如果要选择的话,可以选择分布式缓存来替代Ehcache。
  4. 对于Guava Cache来说,Guava这个jar包在很多Java应用程序中都有大量的引入,所以很多时候其实是直接用就好了,并且其本身是轻量级的而且功能较为丰富,在不了解Caffeine的情况下可以选择Guava Cache。
  5. 对于Caffeine来说,笔者是非常推荐的,其在命中率,读写性能上都比Guava Cache好很多,并且其API和Guava cache基本一致,甚至会多一点。在真实环境中使用Caffeine,取得过不错的效果。
  6. 总结一下: 如果不需要淘汰算法则选择ConcurrentHashMap,如果需要淘汰算法和一些丰富的API,这里推荐选择Caffeine

四、缓存的写入以及更新

1、缓存的写入

内存缓存是如何写入的呢,tomcat在启动时spring容器会进行依赖注入,@PostConstruct注解修饰的方法可以依赖注入后执行,我们需要在这个时候把数据加载到缓存种。不过这个时候要做到接口没有对外提供服务,否则流量大的例如秒杀活动会直接打到数据库,造成故障。

public class CaffeineConfiguration {

    @PostConstruct
    public void init() {
        Cache<Long, Object> cache = Caffeine.newBuilder()
                .expireAfterWrite(1, TimeUnit.MINUTES)
                .maximumSize(100)
                .build();
        List<Order> result = listFromDb();
        result.forEach(order -> cache.put(order.getOrderNo(), order));
    }
}
2、缓存的更新

缓存的更新涉及3方面:
基于大小,基于时间和基于引用自动删除
监听自生产自消费的mq消息(广播模式)进行删除
监听MySQL binlog进行删除

  1. 基于大小,基于时间和基于引用自动删除
// 基于大小回收
LoadingCache<Long, Order> cache = Caffeine.newBuilder()
         .maximumSize(1)
         .build(k -> new Order());

 // 基于时间回收
 LoadingCache<Long, Order> cache = Caffeine.newBuilder()
         .expireAfterAccess(2, TimeUnit.SECONDS)
         .build(Order::getKey);

 // 基于引用回收
 LoadingCache<Long, Order> cache = Caffeine.newBuilder()
         .expireAfterWrite(10, TimeUnit.SECONDS)
         .weakKeys()
         .weakValues()
         .build(Order::getKey);
  1. 监听mq消息
    监听mq消息实现自发自消来删除内存缓存在这里插入图片描述
  2. 监听MySQL binlog
    监听binlog实现自发自消来删除内存缓存,删除失败则使用mq进行重试删除。
    在这里插入图片描述
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值