多级缓存思想(面向gpt编程)

2,310 阅读4分钟

前言


之前看过有赞TMC框架多级缓存实现,写过一篇文章:参照有赞TMC框架原理简单实现多级缓存,对于里面一些精髓还是没有学习到位,今天借助阿里开源的JetCache来进一步了解。

多级缓存是什么


有请gpt来讲讲~ 这个开发配置一个好助手,它对于内容的筛选会更细,不像某度引擎直接把一堆博客丢出来,很多还是模棱两可的,关键还有广告,哈哈~

image.png

它分析很详细,内存型的速度非常快的,但是它不能共享资源,分布式缓存速度比前面的慢,但是可以保证分布式环境数据一致性,持久性一般就是mysql这些关系型,特点就是容量大,但是不足就是并发超过200多的时候性能就会下降。

多级缓存应用场景

我们应用中一般会使用分布式缓存redis,它的不足是什么,它也有脆弱的时候,常见的面试题:缓存击穿、缓存穿透,这些场景也会让系统崩溃,还有热点key也会对特定的节点产生巨大压力,从而影响redis读取性能,从而多级缓存登场。

多级缓存思路


读写逻辑

数据储存逻辑

MultiLevelCache

image.png

image.png

循环塞入值,顶层是本地缓存,然后再是分布式缓存,他们之间是CompletableFuture,通过thenCombine进行调控,比如说本地跟分布式缓存不一致的话,会返回异常信息。

image.png

数据读取逻辑

image.png

顺序还是从本地到分布式下来读取。

checkResultAndFillUpperCache(key, i, holder);

这段代码,是强行刷里面TTL,就是保证在ttl时间内缓存内部是一致的。

一致性保证

这里的一致性有几方面:多级缓存一致性,不同节点的一致性

多级缓存它是怎么保证一致性的呢?来gpt同学回答一下

image.png

什么叫读写更新策略呢?跟redis一样的旁路更新策略,就是get获取的时候,如果多级缓存没有,那么从db读取之后更新的多级缓存里面,这解决第一个问题:多级缓存一致性。

第二个问题:不同节点的一致性,其实是靠redis发布订阅来解决,就是缓存key put、remove操作都会通过redis管道进行通知,然后同步不同的节点。如果有网关延迟怎么办,进行重试~

缓存击穿


来gpt同学再次回答一下问题

image.png

不得不讲人工智能确实很聪明,列了很多点,然后我们人工再去筛选想要的东西。

里面第一点提到了会使用分布式锁来避免缓存击穿,什么意思呢,比如说2个节点,1w并发,那么多级缓存都没有数据,这时,节点1会拿到分布式锁更新数据,其他的请求先卡住,等更新完了,节点2去更新自己的数据,这样即使并发再高,其实就2个请求打到数据库。

其他请求怎么等待呢?参考栅栏CountDownload

热点key怎么监控


gpt同学:

image.png

public class HotKeyMonitor<K> implements CacheMonitor<K, Integer> {  
  
    private static final Logger logger = LoggerFactory.getLogger(HotKeyMonitor.class);  
  
    private final Map<K, AtomicInteger> counterMap = new ConcurrentHashMap<>();  
  
    private final Set<K> hotKeySet = new HashSet<>();  
  
    private final int threshold;  
  
    public HotKeyMonitor(int threshold) {  
        this.threshold = threshold;  
    }  
  
    @Override  
    public void onGet(String cacheName, K key, Integer value) {  
        if (value == null) {  
            return;  
        }  
        AtomicInteger counter = counterMap.computeIfAbsent(key, k -> new AtomicInteger());  
        if (counter.incrementAndGet() >= threshold) {  
            synchronized (hotKeySet) {  
                if (!hotKeySet.contains(key)) {  
                    hotKeySet.add(key);  
                    ![]()logger.info("Hot key detected, cache: {}, key: {}, count: {}", cacheName, key, counter.get());  
                }  
            }  
        }  
    }  
  
    @Override  
    public void onPut(String cacheName, K key, Integer value) {  
        counterMap.remove(key);  
        synchronized (hotKeySet) {  
            hotKeySet.remove(key);  
        }  
    }  
  
    public Set<K> getHotKeySet() {  
        synchronized (hotKeySet) {  
            return new HashSet<>(hotKeySet);  
        }  
    }  
  
}  

image.png

那这个值怎么更新的?

image.png

那这个监控会在集群同步吗?

image.png

它在哪些方法会监控呢?

image.png

onGet请求会进行累加,通过事件异步,onPut会删除热点key

热点key监控之后,其实应该放到本地缓存去命中这样效率是最高的,避免redis网络请求,特别是big key问题

总结


到这里我们从多级缓存的概念,到为什么要用多级缓存,然后从它的读写逻辑、一致性保证、缓存击穿、热点key监控,全面的对多级缓存有了深一层的理解,这里多亏了chatgpt同学的解答,还有我也去看了对应的源码,希望对各位读者也有帮助~

本文正在参加 人工智能创作者扶持计划