1。介绍每一次后端面试,似乎都少不了关于redis的话题,比如项目用过哪些分布式缓存服务,为什么用redis,有没有遇到过缓存失效,缓存穿透,缓存雪崩等等问题。在之前关于redis的介绍文章中,我们说过项目中之所以引入分布式缓存服务,主要是为了解决集群环境下内存数据不共享的问题,比如session会话,还有一些字典缓存等,存储在当前服务器的内存中,但在另一台服务器中很难获取查询。通过引入缓存服务,将缓存的数据统一到一台服务器上,解决系统内存数据不共享的问题。同时,缓存性能也不会受到太大影响。当然,在软件开源市场上,也有很多分布式缓存服务,比如比较有名的redis、memcached。和memcached相比,redis的各项指标比memcached强很多,而且Redis号称可以读取速度110000次/s,写入速度81000次/s,无数的实践证明redis确实是一个非常高的-性能内存数据库。从面试官的角度来看,软件系统的技术选型以及上述相关的技术问题,在实际生产环境中确实会出现。以这个话题为切入点,可以更清楚地了解面试官是否也遇到过类似的问题,以及如何处理。从面试官的角度来说,除了熟练掌握redis的使用之外,我们可能还需要对引入redis后系统可能出现的一些问题以及如何处理有更深入的了解。今天我们聊聊吧。2.常见问题2.1。问题一:为什么数据存入redis,查询失败?Redis的所有数据都保存在内存中,然后不定时的异步保存到磁盘;也可以将每次数据变化写入,当redis服务器重启时,数据会自动从日志文件恢复到内存中。哪些场景会出现缓存失效?总结起来有两种场景:当redis服务器重启时,可能会出现缓存失效的情况。这时候可以将redis的持久化模式改为AOF模式,也就是全持久化模式,但是性能上会消耗大量的存储对于redis的数据,设置一个自动过期时间。在这种情况下,可以重新调整过期时间。2.2.问题2:缓存中的数据和数据库不一致。通常,我们使用缓存。其中一个重要的目的就是减轻数据库的访问压力。比如查询商品信息时,优先从缓存中查询,如果没有,再从数据库中查询。对于一个既有写数据库又有缓存操作的接口,一般分为两种情况。先写入数据库,再操作缓存。这种情况下,如果数据库操作成功,缓存操作失败,就会导致缓存和数据库不一致。先操作缓存,再写入数据库。这种情况下,如果缓存操作成功,数据库操作失败也会导致数据库和缓存不一致。大部分情况下,缓存理论上需要从数据库中恢复,所以基本上第一个顺序不会有问题。有问题,但不能保证数据库和缓存完全一致。也就是说,使用缓存,可能会出现缓存和数据库不一致的情况,只是说这种可能性有多大。对于那些必须保证数据库和缓存一致性的情况,通常不推荐使用缓存,直接从数据库查询。2.3.问题三:什么是缓存穿透?缓存渗透是指恶意用户频繁模拟请求缓存中不存在的数据。这时候如果有大量的接口请求,会在短时间内直接落到数据库上,缓存就会被阻塞。故障,导致数据库性能急剧下降,最终影响服务的整体性能。这在实际项目中很容易遇到,抢购活动、闪购活动、抢券等接口API被大量恶意用户刷卡,导致数据库短时间内宕机。对于缓存击穿的问题,有如下几种解决方案。使用分布式锁的队列。当从缓存中获取数据失败时,锁定当前接口,从数据库加载写入数据后释放锁。如果其他线程获取锁失败,等待一段时间再尝试。使用布隆过滤器。将所有可能的数据哈希成一个足够大的位图,一个一定不存在的数据会被这个位图拦截,从而避免底层存储系统缓存空结果的查询压力。如果一个查询返回的数据是空的,我们还是把空的结果缓存起来,但是它的过期时间会很短,不会超过五分钟,这样第二次从缓存中取出来就有价值了,不会继续访问数据库,简单粗暴。2.4.问题四:什么是缓存雪崩?简单来说就是短时间内大量缓存失效。如果在此期间出现大量请求,也可能导致数据库宕机。如果在Redis集群的数据分布算法中使用传统的哈希取模算法,在添加或移除Redis节点时会出现大量的临时缓存失效。缓存雪崩问题有几种解决方案。像解决缓存穿透一样通过加锁和排队来创建备份缓存。比如缓存A和缓存B,A设置了超时时间,B没有设置超时时间的值,先从A读取缓存,A不读取B,当缓存A发生变化时,同时更新缓存B计算数据缓存节点的时间。哈希算法,使得当节点数量发生变化时,不会有大量的缓存数据需要迁移。2.5.问题五:redis缓存会不会有并发问题?首先,Redis在单线程中执行命令。当有多个RedisClient并发操作数据时,坚持先发起先执行的原则,其他的阻塞。redis缓存并发问题其实主要是指读取数据库数据的并发操作问题。当缓存过期时,会从数据库中查询数据,然后存储到Redis缓存中。但是,在高并发的情况下,其他客户端可能会在数据库中查到的数据还没有存储到Redis中之前,去查询数据库中的数据。再次保存到Redis。这样会导致多个请求同时从数据库中获取数据,然后存储到Redis中,读取时可能会出现脏数据。对于这种场景,有如下几种解决方案。同步锁处理。写入数据库时??,再次操作缓存阶段,并进行加锁处理,保证串行服务,可能会牺牲一点异步队列串行执行的时间。把写入数据库和操作缓存的操作放到队列中序列化,让它们一个一个执行,比如通过消息中间件异步执行。使用类似于SQL的乐观锁机制:在并发写入Redis缓存时,比较待写入数据的版本号和时间戳与Redis中的数据,如果写入数据的时间戳或版本号高于Redis,然后写入;否则就别写了3.总结这篇文章主要针对redis使用中出现的一些场景问题,做一个简单的总结。如有遗漏,请留言指出!4.参考1.博客园-Castame的保护伞-springboot中RedisTemplate的使用
