专注于 JetBrains IDEA 全家桶,永久激活,教程
持续更新 PyCharm,IDEA,WebStorm,PhpStorm,DataGrip,RubyMine,CLion,AppCode 永久激活教程

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

35_1.png

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

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

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

1.缓存穿透

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

应对缓存击穿有两种常用方案:(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]

35_2.png

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

使用布隆过滤器作为缓存的前置过滤,可以有效过滤掉无效数据请求。

35_3.png

两种方案对比

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

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

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.超热点缓存

文章永久链接:https://tech.souyunku.com/37968

未经允许不得转载:搜云库技术团队 » 分布式系统中缓存常见问题与解决方案(1)

JetBrains 全家桶,激活、破解、教程

提供 JetBrains 全家桶激活码、注册码、破解补丁下载及详细激活教程,支持 IntelliJ IDEA、PyCharm、WebStorm 等工具的永久激活。无论是破解教程,还是最新激活码,均可免费获得,帮助开发者解决常见激活问题,确保轻松破解并快速使用 JetBrains 软件。获取免费的破解补丁和激活码,快速解决激活难题,全面覆盖 2024/2025 版本!

联系我们联系我们