对线面试官 -Redis(缓存的三大问题)
面试官:Redis 了解过吗?知不知道它有哪些主要用途?
派大星:Redis 是一个开源的内存数据结构存储系统,用于高性能应用程序。它的主要用途包括缓存、会话存储、消息队列、排行榜/计数器和分布式锁等。
缓存:将频繁访问的数据存储在 Redis 中,以加快读取速度。
会话存储:将用户会话数据存储在 Redis 中,实现可扩展和高性能的会话管理。
消息队列:利用 Redis 的发布/订阅功能,实现异步消息传递。
排行榜/计数器:使用 Redis 的有序集合和计数器功能,实现排行榜和计数器应用。
分布式锁:利用 Redis 的原子操作和过期时间特性,实现分布式锁机制。
面试官:不错。那么,作为缓存,Redis 有哪些挑战和问题呢?聊一聊
派大星:主要的三大经典问题包括缓存击穿、缓存穿透和缓存雪崩,当然还有数据一致性、内存消耗和缓存更新的延迟等问题。
面试官:非常好。那么,针对缓存击穿、缓存穿透和缓存雪崩,你有什么具体的解决方案或思路吗?
派大星:首先聊一聊缓存击穿,所谓的缓存击穿主要原因是 key 的过期造成并发访问数据库,也就是所有的请求打到数据库,如何阻止?做好数据库的最后一道防线,我们就可以按照这个思路去进行解决。
首先我们分析一下:因为 reids 是单进程,单实例,这样我们可以利用 redis 作为锁:setnx,只有获取到锁的去访问 DB,这样就可以有效的防止请求打到服务器
大致步骤如下:
getkey
setnx() -锁
ok 的去数据库
flase 的 sleep 一会
面试官:那么这么做就可以了吗?
派大星:当然!!!不太可以。上述方案的也有弊端:就是会产生死锁,以及锁超时的问题
面试官:那应该如何解决死锁和锁超时的问题呢?
派大星:首先我们可以想到如果第一个抢到锁的挂了,可以通过设置过期时间解决死锁问题;同时虽然设置了过期时间但是有可能会产生抢到锁的并没有挂只是没有处理完,这是锁的过期时间已经达到了。可以通过在客户端使用两个线程进行监听来解决:一个线程去数据去去数据,另外一个线程监听是否从数据库中取出结果,从而更新锁的超时时间,从而解决锁超时问题。
注意:到这里其实代码复杂度就已经很高了。可以使用 zk 临时顺序节点做分布式锁。
面试官:那接下来聊一下缓存穿透的问题吧?
派大星:好的,所谓的缓存穿透指的是缓存和数据库都不存在的数据。我们可以通过 bloom 过滤器。
具体的解决方案可以参考如下方案:
client 实现算法和存储数据结构,client 压力较大
client 实现算法,redis 承载 bloom 的 bitmap-无状态
redis 集成 bloom(压力在 redis,但更符合 service mactc 的设计理念,同时 redis 的承受能力要比 client 强)
面试官:不错不错,那雪崩的问题呢?
派大星:所谓的缓存雪崩也就是大量 key 失效导致请求直接到达 DB。如果想要解决雪崩问题我们需要做如下分析:什么场景下会产生雪崩:也就是系统的零点过期。针对上述场景可以有两种解决方案
方案一:如果到达某一时刻必须过期(key),必须造成雪崩,解决方案就是强依赖击穿方案,或者业务判断,零点延时。
方案二:如果与时点性无关解决方案就是随机过期时间
面试官:非常好,你的回答非常详细。下次我们再聊聊数据一致性、内存消耗和缓存更新的延迟等问题。非常感谢你的时间和分享。
派大星:非常感谢您的提问,期待下一次的面试。
如有问题,欢迎加微信交流:w714771310,或关注微信公众号【码上遇见你】。
版权声明: 本文为 InfoQ 作者【派大星】的原创文章。
原文链接:【http://xie.infoq.cn/article/441d63b58c1e227a884149420】。
本文遵守【CC BY-NC-ND】协议,转载请保留原文出处及本版权声明。
评论