两级缓存实现分析之缓存设置


title: 两级缓存实现分析之缓存设置 tags:

  • J2Cache
  • 缓存
  • 雪崩
  • 缓存击穿
  • 缓存失效 categories: 工作日志 date: 2017-06-25 18:18:54

上篇描述了缓存过期的代码两级缓存实现分析之缓存过期

本次讨论一下两级缓存如何获取缓存设置,移除,获取

正如文章描述缓存读取顺序

读取顺序  -> L1 -> L2 -> DB
复制代码

先描述一下缓存读取代码:

    /**
     * 获取缓存中的数据
     *
     * @param region : Cache Region name
     * @param key    : Cache key
     * @return cache object
     */
    public CacheObject get(String region, Object key) {
        CacheObject obj = new CacheObject();
        obj.setRegion(region);
        obj.setKey(key);
        if (region != null && key != null) {
            obj.setValue(CacheManager.get(LEVEL_1, region, key));
            if (obj.getValue() == null) {
                obj.setValue(CacheManager.get(LEVEL_2, region, key));
                if (obj.getValue() != null) {
                    obj.setLevel(LEVEL_2);
                    CacheManager.set(LEVEL_1, region, key, obj.getValue());
                }
            } else
                obj.setLevel(LEVEL_1);
        }
        return obj;
    }
复制代码

首先在localcache中查询,如果可以获得缓存直接返回,

如果不能则去remotecache获取如果可以获得缓存 将localcache设置缓存后直接返回,

如果不能则返回空(CacheObject中的value为null)===》可以实现更多级缓存

这边隐含一个条件(高一级缓存必定拥有比第一级缓存更多并且准确的数据)

此处存在一个缓存击穿的问题:

我们在项目中使用缓存通常都是先检查缓存中是否存在,如果存在直接返回缓存内容,如果不存在就直直接查询然后再缓存查询结果返回。这个时候如果我们查询的某一个数据在缓存中一直不存在,就会造成每一次请求都查询DB,这样缓存就失去了意义,在流量大时,可能DB就挂掉了。

无论多级缓存都存在此问题,对于此处的解决方案建议对使用缓存的返回结果包装(Optional)可以使用google或者java8的可选对象,如果db查询或者计算结果为空,显示的返回Absent对象,可以避免大量无效的key导致的缓存击穿问题

下面介绍缓存的设置实现

    public void set(String region, Object key, Object value, Integer expireInSec) {
        if (region != null && key != null) {
            if (value == null)
                evict(region, key);
            else {
                // 分几种情况
                // Object obj1 = CacheManager.get(LEVEL_1, region, key);
                // Object obj2 = CacheManager.get(LEVEL_2, region, key);
                // 1. L1 和 L2 都没有
                // 2. L1 有 L2 没有(这种情况不存在,除非是写 L2 的时候失败
                // 3. L1 没有,L2 有
                // 4. L1 和 L2 都有
                _sendEvictCmd(region, key);// 清除原有的一级缓存的内容
                CacheManager.set(LEVEL_1, region, key, value, expireInSec);
                CacheManager.set(LEVEL_2, region, key, value, expireInSec);
            }
        }
        // log.info("write data to cache region="+region+",key="+key+",value="+value);
    }
复制代码

正如上文所述,高级缓存(L2)必然承载更多低级缓存所不存在的数据

首先发起命令清除所有一级缓存的对应key(保证其他一级缓存的值已被清除,不会出现缓存不一致)

分别在各级缓存设置对应的key和value

对于db或者其他计算资源来说如果过载会发生较为严重的后果,比如无返回,超时甚至宕机。

缓存雪崩就是可能出现的原因之一。

如果出现某个缓存在一段时间后过期了,同时出现高并发获取该缓存将会出现缓存雪崩,

首先查询该缓存发现不存在后立刻去向db获取数据,该处可能将一瞬间的流量完全打到db上

导致db负债过高使得应用超时乃至宕机

通常解决方案只能通过getCache时如果key不存在就增加一把锁,使得其他线程必须等待到锁释放

当然还有缓存失效问题

用户在初次使用系统时,可能要针对该用户存储大量缓存,设想场景均为24h,那么当24h后所有缓存过期

同样可能出现大量流量打到db出现异常。

通常解决方案是在过期时间上加上一定长度的随机数,使得缓存不至于一刹那全部过期导致db流量过大

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值