Redis高频八股文与解决策略

什么是Redis?

Redis是一个高性能的非关系型的键值对数据库,使用C编写实现的。与传统的数据库不同的是Redis是存在内存中的,所以读写速度非常快,每秒可以处理超过10万次的读写操作,这也是Redis常常被用作缓存的原因。

什么是缓存穿透?

缓存穿透是指用户的请求没有经过缓存而直接请求到数据库上了,比如用户请求的key在Redis中不存在,或者用户恶意伪造大量不存在的key进行请求,都可以绕过缓存,导致数据库压力太大挂掉。

如何解决缓存穿透?

  • 参数校验、屏蔽非法参数
    检验用户请求的合法性,屏蔽掉不合理的参数请求(无法彻底避免)

  • 缓存空值
    数据库查询为空,可以给缓存一个空值或默认值,防止第二次再去数据库(导致Redis缓存大量无效数据,甚至内存爆掉)

  • 布隆过滤器
    使用布隆过滤器快速判断数据是否存在,将所有可能存在的数据哈希存到一个足够大的容器中,不存在的数据被这个bitmap拦截掉(布隆过滤器存在一定误差,且不支持删除数据,可通过定期重构解决数据变更问题)

什么是缓存雪崩?

缓存雪崩是指在某一个时刻出现大规模的缓存失效的情况,大量的请求直接打在数据库上面,可能会导致数据库宕机,如果这时重启数据库并不能解决根本问题,会再次造成缓存雪崩。

为什么会造成缓存雪崩?

一般来说,造成缓存雪崩主要有两种可能

  • Redis宕机了
  • 很多key采取了相同的过期时间

如何解决缓存雪崩?

  • 为避免Redis宕机造成缓存雪崩,可以搭建Redis集群
  • 尽量不要设置相同的过期时间,例如可以在原有的过期时间加上随机数
  • 服务降级,当流量到达一定的阈值时,就直接返回“系统繁忙”之类的提示,防止过多的请求打在数据库上,这样虽然用户体验较差,但至少可以使用,避免直接把数据库搞挂

什么是缓存击穿?

缓存雪崩是大规模的key失效,而缓存击穿是一个热点的Key,有大并发集中对其进行访问,突然间这个Key失效了,导致大并发全部打在数据库上,导致数据库压力剧增,这种现象就叫做缓存击穿。

比较经典的例子是商品秒杀时,大量的用户在抢某个商品时,商品的key突然过期失效了,所有请求都到数据库上了。

如何解决缓存击穿?

  • 虑热点key不设置过期时间,避免key过期失效
  • 在数据的value上增加一个逻辑到期时间,数据查询发现过期后进行加锁,拿到锁的请求去查询数据库进行Redis更新,未抢到锁的线程可以返回过期前的默认数据,用弱一致性来避免缓存击穿

如何保证缓存与数据库双写时的数据一致性?

这是面试的高频题,需要好好掌握,这个问题是没有最优解的,只能数据一致性和性能之间找到一个最适合业务的平衡点

首先先来了解下一致性,在分布式系统中,一致性是指多副本问题中的数据一致性。一致性可以分为强一致性、弱一致性和最终一致性

  • 强一致性:当更新操作完成之后,任何多个后续进程或者线程的访问都会返回最新的更新过的值。强一致性对用户比较友好,但对系统性能影响比较大。
  • 弱一致性:系统并不保证后续进程或者线程的访问都会返回最新的更新过的值。
  • 最终一致性:也是弱一致性的一种特殊形式,系统保证在没有后续更新的前提下,系统最终返回上一次更新操作的值。
    大多数系统都是采用的最终一致性,最终一致性是指系统中所有的副本经过一段时间的异步同步之后,最终能够达到一个一致性的状态,也就是说在数据的一致性上存在一个短暂的延迟。

如果想保证缓存和数据库的数据一致性,最简单的想法就是同时更新数据库和缓存,但是这实现起来并不现实,常见的方案主要有以下几种:

  • 先更新数据库,后更新缓存
  • 先更新缓存,后更新数据库
  • 先更新数据库,后删除缓存
  • 先删除缓存,后更新数据库

乍一看,感觉第一种方案就可以实现缓存和数据库一致性,其实不然,更新缓存是个坑,一般不会有更新缓存的操作。因为很多时候缓存中存的值不是直接从数据库直接取出来放到缓存中的,而是经过一系列计算得到的缓存值,如果数据库写操作频繁,缓存也会频繁更改,所以更新缓存代价是比较大的,并且更改后的缓存也不一定会被访问就又要重新更改了,这样做无意义的性能消耗太大了。

下面介绍删除缓存的方案

先更新数据库,后删除缓存

这种方案也存在一个问题,如果更新数据库成功了,删除缓存时没有成功,那么后面每次读取缓存时都是错误的数据。
解决这个问题的办法是删除重试机制,常见的方案有利用消息队列和数据库的日志
但这个方案也有一些缺点,比如系统复杂度高,对业务代码入侵严重,这时可以采用订阅数据库日志的方法删除缓存。

先删除缓存,后更新数据库

这种方案也存在一些问题,比如在并发环境下,有两个请求A和B,A是更新操作,B是查询操作,假设A请求先执行,会先删除缓存中的数据,然后去更新数据库,B请求查询缓存发现为空,会去查询数据库,并把这个值放到缓存中,在B查询数据库时A还没有完全更新成功,所以B查询并放到缓存中的是旧的值,并且以后每次查询缓存中的值都是错误的旧值。

这种情况的解决方法通常是采用延迟双删,就是为保证A操作已经完成,最后再删除一次缓存

逻辑很简单,删除缓存后,休眠一会儿再删除一次缓存,虽然逻辑看起来简单,但实现起来并不容易,问题就出在延迟时间设置多少合适,延迟时间一般大于B操作读取数据库+写入缓存的时间,这个只能是估算,一般可以考虑读业务逻辑数据的耗时 + 几百毫秒。

在实际应用中,还是先更新数据库后删除缓存这种方案用的多些,因为延迟双删这个操作的颗粒度过于庞大,不太适合实际开发。

需要注意的是,无论哪种方案,如果数据库采取读写分离+主从复制延迟的话,即使采用先更新数据库后删除缓存也会出现类似先删除缓存后更新数据库中出现的问题,举个例子

  1. A操作更新主库后,删除了缓存
  2. B操作查询缓存没有查到数据,查询从库拿到旧值
  3. 主库将新值同步到从库
  4. B操作将拿到的旧值写入缓存

这就造成了缓存中的是旧值,数据库中的是新值,解决方法还是上面说的延迟双删,延迟时间要大于主从复制的时间。

  • 14
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Redis面试八股文主要包括以下几个方面: 1. Redis的特点和优势:Redis是一个高性能的非关系型键值对数据库,其数据存储在内存中,读写速度非常快。它支持多种数据类型,包括String、Hash、List、Set、ZSet等,还支持持久化和事务操作。此外,Redis还支持主从复制和单线程的命令处理,具有较好的性能和可扩展性。 2. Redis的数据结构和常用命令:Redis提供了多种数据结构,如字符串、哈希表、列表、集合和有序集合,并提供了相应的命令进行操作。例如,使用SET命令可以设置字符串值,使用HSET命令可以设置哈希表字段值,使用LPUSH命令可以将元素插入列表的头部等。 3. Redis的持久化机制:Redis支持RDB和AOF两种持久化机制。RDB是将当前数据集的快照保存到磁盘上,而AOF则是通过追加方式记录每个写操作到日志文件中。这两种机制可以保证数据的安全性和可恢复性。 4. Redis的主从复制:Redis通过主从复制实现数据的备份和读写分离。主节点将数据同步到从节点,从节点可以处理读操作,从而提高系统的并发处理能力和可靠性。 5. Redis的高可用性和集群模式:为了提高Redis的可用性,可以通过搭建Redis集群来实现数据的分布和负载均衡。Redis集群使用分片的方式将数据分散到多个节点上,并通过Gossip协议实现节点间的通信和数据同步。 6. Redis的性能优化和调优:为了提升Redis的性能,可以通过配置合适的缓存大小、使用合理的数据结构、优化命令使用方式等手段进行性能优化和调优。 7. Redis的高可靠性和数据一致性:为了保证Redis的高可靠性和数据一致性,可以通过配置合理的主从复制和持久化方式,并使用合适的监控和告警系统进行监控和故障处理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值