分布式缓存复习

缓存可以加快速度,极大提高系统性能,但也会产生许多问题,使用前需要了解清楚。

首先一个问题:为什么不能用本地缓存而要用分布式缓存呢?

(1)多个机器的本地缓存可能不一致。比如第一次负载均衡A机器,A机器查数据库,存在缓存中了,第二次负载均衡到B机器,又没有缓存,还得再查一遍数据库;更严重的情况是,一般写操作在更新数据库之后都会更新缓存,或者先使缓存失效再更新数据库,无论怎么做,如果使用本地缓存,都只能保证当前机器的混存一致性,而其他机器则会继续缓存错误的数据。

(2)像京东、淘宝等可能缓存量很大,让本应专注于业务处理的服务器承担了不必要的压力。而放在redis中,就完全可以通过集群等方式分散压力。

缓存常见的问题:

(1)缓存穿透:指查询一个数据库中不存在的数据,这样每次查到都是null,都没存入缓存,都走数据库,等于说缓存没用上。而且恶意攻击者可以专门构造这样的请求,就查你不存在的数据。

解决办法:

(A)一开始就做一些基础校验,不合法的数据,比如price<0,id<0,这样的请求不放进来

(B)把查出来的null也存入redis,这个的问题是可能导致redis中存入大量的null值。可以设置一个过期时间,比如30s,这样即使你攻击,30s内页最多查数据库一次。并且30s这些null都会删除,不会过多占用redis的内存。

(C)布隆过滤器 其实就是设置多个hash函数,然后每一个hash的结果是一个很大的bitmap。事先把每个可能出现的key值通过哈希函数哈希后将对应的bitmap点位设为1,这样每个存在的key值其实对应一组bitmap的点位。然后一个查询进来的时候,先用布隆过滤器过滤一遍,如果有一个bitmap为0,则不存在。如果都为1,则极大概率是存在的,这时候再到redis中查。优点是性能好,缺点是有极小概率误判

(A)B)(C)其实可以结合起来

(2)缓存击穿

比如混存了一个iphone15的数据,这是个热点数据,早上9点这个缓存ttl到期了,然后大量请求涌进来,由于没有缓存,一下子都来查数据库了,很容易就会造成数据库服务器的崩溃。

解决办法:

(A)加分布式锁。每次只放一个进去查库,查到后放入redis缓存才解锁。可以用双重检测锁(DCL)提高效率。

(B)设置热点数据永不过期。

(3)缓存雪崩

如果每个服务都在同一时间设置缓存,并且ttl设置得相同,就会有某个时间点所有的缓存都失效了,都去db查,这显然不行。

解决办法:设置ttl时增加一个随机量。

如何保证缓存和数据库的一致性?

(1)双写模式。即先改数据库,再改缓存。这里存在一个问题,就是比如A机器修改数据库数据为1,他刚要改缓存,可能因为机器卡顿、网络卡顿等各种原因,改的比较慢,他还没改,B机器把数据库数据改为2,并且把缓存改为2了,这时候A机器又把缓存改为1了。数据库中是2,缓存中是1,这就出现了数据不一致的问题。能不能先写缓存再写数据库呢?首先,显然这也数据不一致的问题,其次,先写数据库,后写缓存,缓存跟着数据库走,稍微有点延迟,这叫最终一致。如果缓存走在数据库前面,这叫什么?这叫错误数据。

(2)失效模式,即先修改数据库,再把缓存直接删掉。这样也有问题。可能发生这样的情况:

注:本文内容、图片参考谷粒商城项目。

总之,上述两种方法不能保证一致性。

解决办法,无论哪一种模式,更新缓存的时候都加一个过期时间,这样每隔一段时间一定会去查一次数据库,保证最终一致性。

那有的业务就是要求强一致呢,可以加分布式读写锁。读读可以并发,读写互斥,写写当然也互斥,这样保证在一个服务更新数据库数据、更新缓存的整个过程没人能进来,就保证二楼强一致。

但是频繁的加锁、解锁本身也会给系统增加很多负担,特别对于一些经常修改的数据,如果一致性还高,那可能也不应该用缓存了,就应该让他直接走数据库。

还有一个办法,使用canal。canal会伪装成一个数据库的从服务器,订阅主库的binlog,主库有什么更新,从库一定会收到,再来更新redis。binlog一定是按照数据库的更新顺序排好的,所以不会有一致性的问题。当然,从数据库更新到redis缓存更新当然会有一个很小的延迟,但这个可不是像上面两幅图的情况那样,不干预甚至永远都不一致。如果用canal,更新数据库的时候也不用再管缓存了,后台自动完成。缺点是又增加了一个组件,增加了系统的复杂度,而且多一个组件就又多一个可能的故障点。

所以还是那句话,对修改不不频繁,并且实时性要求不高的,可以用缓存,保证最终一致性即可;对于一些经常修改的数据,如果一致性还高,那可能也不应该用缓存了,就应该让他直接走数据库。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值