分布式系统中缓存常见问题与解决方案(1)

缓存做为DB前的一道防线,过滤了绝大部分DB请求,保障业务系统的高性能与高可用。redis

一样的,特别是高度依赖缓存的分布式系统,缓存设计若是不合理,轻则浪费机器资源,重则 1.缓存污染,即缓存与DB数据不一致,影响数据正常展现,如果在交易链路,则会形成资损;2.难以承载大流量,致使服务雪崩。数据库

下面总结了分布式系统中,缓存设计的常见问题与相应解法。缓存

1.缓存穿透

缓存穿透,即请求了缓存中不存在的数据,致使请求打到DB,形成DB负载变高。若是出现大量缓存穿透请求,一是说明缓存命中率低,浪费机器资源;二是会存在将DB链接打满、服务宕机的风险。bash

应对缓存击穿有两种经常使用方案:(1)对于无效数据,缓存中使用占位符存储;(2)使用布隆过滤器进行前置拦截。网络

1.1 缓存占位符

简单来讲,当数据无效 or 不存在时,使用特殊占位符进行缓存。下一次请求来时,不须要走到DB,直接返回。并发

1.2 布隆过滤器(Bloom Filter)

若是无效数据量比较大,使用占位符的策略,会浪费大量内存资源。这种状况可使用布隆过滤器。异步

布隆过滤器的原理:使用bitMap进行数据存储,使用多个hash函数计算数据位。hash计算出入参的下标,并标记为1。当计算出来的下标对应的bitMap都为1时,则认为该数据存在。反之,则不存在。分布式

布隆过滤器的特性:函数

  • 使用bitMap存储数据,内存占用极低;
  • 能肯定一个值必定不存在,但不能肯定一个值必定存在(小几率事件,由于存在hash碰撞的因素)。知足缓存过滤的需求。

以下图所示,入参为商品productId,使用3个hash函数(H1,H2,H3)计算其hash值,做为bitMap的下标。性能

productId1,标志位为[0,4,7],product2标志位为[2,4,10]

这时查询请求进来,查productId3,假设计算出bitMap下标为[2,4,9],对应占位为[1,1,0],则productId3不存在。

使用布隆过滤器做为缓存的前置过滤,能够有效过滤掉无效数据请求。

两种方案对比

占位符:代码实现简单,数据时效性高,内存占用较高,适用于无效数据量小的场景。

布隆过滤器:代码实现复杂,数据时效性低,内存占用低,适用于无效数据量大,且数据时效性要求不高的场景。

2.缓存击穿

缓存击穿,即某个热点缓存失效后(缓存过时),该热点key的请求直接打到DB,形成DB压力瞬间增大。

解决方案:(1)热点缓存永不过时;(2)加互斥锁

2.1热点缓存永不过时

通常是经过计算出逻辑上的过时时间,好比活动、商品过时时间endTime,再设置缓存过时时间为endTime,保证在逻辑过时时间内,缓存一直有效。

固然若是内存满了,缓存会启动淘汰机制,视状况会可能会淘汰永久缓存。相应解法以下:

方案一:作热点缓存隔离,热点缓存与普通缓存放在不一样集群,内存容量不受普通缓存数据影响;

方案二:缓存不作永不过时设置,而是设置过时时间,同时业务代码加入缓存更新逻辑,在缓存过时前,更新缓存。实现方式能够是mq、延时mq、异步线程等。

2.2 互斥锁

查DB操做前加锁,同一时刻只能有一个请求打到DB,其余请求等待重试。该方案引入分布式锁,将DB压力转移到分布式锁上,实现简单,但存在请求过大时,等待时间过长,线程被打满的风险。

示例代码:

private finial static String QUERY_LOCK = "lock_"

public Object getDate(String key){
    Object value = redis.get(key);
    if (value == null) {
        //设置分布式锁
        if (redis.setnx(QUERY_LOCK + key, 1, time)) {
            value = db.get(key);
            redis.set(key, value, time);
            redis.delete(QUERY_LOCK + key);
        } else {
            sleep(500);
            return getDate(key);
        }
    }
    return value;
}
复制代码

3.缓存雪崩

缓存雪崩,即大量key在同一时间内同时过时,形成大量请求打到DB。

解法比较简单,在设置缓存时,在基础过时时间上,随机浮动加减时间,避免缓存在同一时间失效。同时能够在DAO层 or DB中间件 加入限流,避免瞬时大流量打垮DB。

4.缓存一致性

缓存一致性,即缓存数据与DB数据的一致性。引入缓存后,同一份数据分布在两处,因为网络IO、数据库事物、并发操做等因素,会形成缓存与DB数据不一致的问题。

而形成缓存数据不一致问题的主要缘由,基本都是由数据更新+并发操做致使。 简单举例:

算了,感受缓存一致性问题都能单开一章分析了。那么下面的小结咱仍是留到后面再开新章节吧,感谢看到这里的各位。

4.1 更新缓存的常见方案

4.2 缓存一致性保障方案

5.缓存高可用

6.超热点缓存

相关文章
相关标签/搜索