高并发-缓存击穿

1,877 阅读2分钟

本质

缓存击穿问题的本质是,高并发问题。

是什么?

所谓缓存击穿,就是缓存没有拦截住请求。最终走到了数据库。

为什么会这样?应用场景?

一般是流量很高的时候,这是第一。//因为流量很低,就算击穿缓存,直接访问数据库,也没啥。数据库能抗住。

另外,第二点,就是缓存没有拦截住流量。为什么没有拦截住?这个问题才是本质,要好好思考这个问题。

这个问题的本质是,什么时候,缓存会没有拦截请求?只有一个情况,那就是缓存没有数据,即读数据的时候,数据不存在,那么就去读数据库。

那么,为什么缓存没有数据?

举一个场景,缓存刚刚失效的那一刻,突然流量很高,这个时候就满足了上述的两个条件 1.流量很高 2.缓存没有数据 //因为数据到期

那这个时候,怎么解决?怎么解决这个问题?

解决方法

首先,我们来看一下,我们的最终目标是什么?就是不让高并发流量读数据库。

怎么做到?还是得用锁。单机就是使用同步关键字或显式锁。分布式服务,就是使用分布式锁。

分布式锁

不会影响速度吗?因为刚才的那种情况,是特殊场景,不会一直是那种情况。

所以,为了那片刻的短暂场景,是可以使用分布式锁的。

具体怎么使用?

代码

public String get(key) {
    String value = redis.get(key);
    if (value == null) { //代表缓存值过期
        //设置3min的超时,防止del操作失败的时候,下次缓存过期一直不能load db
        if (redis.setnx(key_mutex, 1, 3 * 60) == 1) {  //代表设置成功
            value = db.get(key);
                    redis.set(key, value, expire_secs);
                    redis.del(key_mutex);
            } else {  //这个时候代表同时候的其他线程已经load db并回设到缓存了,这时候重试获取缓存值即可
                    sleep(50);
                    get(key);  //重试
            }
        } else {
            return value;      
        }
}

注意,锁的使用,只在过期的代码里,才使用。只有这样,才不会影响正常情况下的高并发访问。

参考

tech.meituan.com/2016/12/02/…