redis知识整理

本文详细解释了Redis中的缓存穿透、击穿和雪崩问题,以及如何通过布隆过滤器、互斥锁和分布式锁解决。还涵盖了Redis的数据持久化、过期策略、内存管理和分布式锁实现,以及如何在大规模数据和高并发场景下优化数据同步和一致性。
摘要由CSDN通过智能技术生成

什么是缓存穿透,怎么解决

缓存穿透是指查询一个一定不存在的数据,导致每次请求都到DB查询,可能导致DB异常,大概率是遭到攻击,可以使用布隆过滤器来解决。

布隆过滤器

布隆过滤器用于检索一个元素是否在一个集合中,可以使用redisson实现,原理是通过多次hash计算将key映射到一个位数组(以位为单位存储信息。每个位只能存储0或1两种状态)中,如果一个元素对应的所有位都是1,那么它可能存在于集合中;但如果任何一个位是0,就可以肯定这个元素不在集合中。
当然这种方法有一定的误报率,非常适合于那些可以容忍偶尔误报的场景,因为与此带来的高效查询相比,这是可以接受的。

什么是缓存击穿,怎么解决

缓存击穿是指对于设置了过期时间的key,缓存在过期时,恰好有大量对这个key的请求过来,请求发现缓存过期就会从DB加载,这些请求可能会导致DB异常。
可以通过锁解决

使用SETNX设置一个互斥锁。
判断是否设置成功:
如果设置成功,说明当前没有其他请求在加载数据,那么这个请求就负责加载数据(load db)。
如果设置失败,说明已经有其他请求在加载数据了,当前请求则可以等待一小段时间后重试获取缓存。
完成数据加载后:
将数据回设到缓存中。
释放锁,让其他请求可以获取到最新的缓存数据。

互斥锁和分布式锁

都是通过某种形式的SETNX命令来实现,但它们的概念和使用场合有所不同:
**互斥锁(Mutex Lock)**通常用于确保某个时间点只有一个进程或线程可以执行某个代码段。
**分布式锁(Distributed Lock)**是用于在分布式系统中防止多个进程同时访问某个共享资源。
**排他锁(Exclusive Locks)**或写锁在读写锁的上下文中使用,是一种特别的锁,用于写操作。提及排他锁时,我们往往是在讨论读写锁的一部分,它和另一种锁——共享锁或读锁——共同作用,以维持数据的完整性。
互斥锁和排他锁在概念上是相似的

什么是缓存雪崩,怎么解决

缓存雪崩指的是缓存使用了相同的过期时间,导致在某一时刻同时失效,请求全部转到DB,可能导致DB异常。
在原有失效时间增加随机值,分散失效时间

Redis作为缓存,mysql如何与redis进行同步呢?(双写一致)

一致性要求高

结合业务,车辆登录状态同步,(看车辆点火时间)时效性比较高,使用读写锁保证一致性
采用redisson的读写锁,读的时候添加共享锁,不影响并发读取;更新时添加排他锁,保证写操作的独占性。
非常适合读多写少的场景,需要注意的是,无论是读还是写操作,都应该使用同一把锁(例如,如果有一个锁对象叫做myLock,那么所有尝试读的线程都应该通过这个myLock获取共享锁(读锁),而所有尝试写的线程则应该通过相同的myLock获取排他锁(写锁))

排他锁底层

setnx

允许延迟一致

延时双删

并不能绝对保证数据的强一致性
**写数据库:**首先,将新的数据写入数据库。
**删除缓存:**然后,立即删除缓存中的旧数据。
**延时:**等待一段时间(延时),这个时间足够长以确保所有从库里携带了旧数据的请求都完成,
**再次删除缓存:**在延时之后,再次删除缓存,以处理在延时期间,新的读请求将旧的数据又写回缓存的情况。
(再次删除后,缓存再次被写入就一定是新数据了,不在乎延时期间的请求是新是旧)

优化

综上所述,延迟双删延时期间的数据很不稳定,延迟时间不好确定,所以可以使用异步读写锁的情况,数据被修改时,通过rabbitmq异步实现数据同步

Redis数据持久化怎么做的

redis提供了两种持久化方式

RDB是一个快照文件,把redis数据写到磁盘,宕机后从快照恢复
AOF是追加文件,redis写命令时,存储到文件,宕机后再执行一遍命令

RDB对比AOF

RDB是二进制文件,体积小,恢复快,但是可能会丢数据
AOF虽然慢,但是丢数据风险小,可以设置刷盘策略,每秒批量写入一次命令

Reids的过期策略

惰性删除:设置过期时间后,需要时检查是否过期,过期删除,反之返回key
定期删除:每隔一段时间,删除过期key

Redis的清理策略是定期清理和惰性删除两者并存

Redis的淘汰策略

当 Redis 的内存使用超过设定的 maxmemory 时,就回采取一些策略来清理数据,释放内存,这些策略就被称为淘汰策略。具体有以下几种:

noeviction: 达到最大内存后,不会主动淘汰数据,所有写入操作(包括del、set等)都将返回错误信息。
allkeys-lru:从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰。
volatile-lru:从已设过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰。
allkeys-random:随机移除某个 key。
volatile-random:从已设过期时间的数据集(server.db[i].expires)中任意选择数据淘汰。
volatile-ttl:根据键值对的剩余生存时间移除(越早过期,越先被移除)。

其中 “volatile” 的策略会尝试只淘汰已经设置了过期时间的键,而 “allkeys” 则会在所有键上进行淘汰。
默认的淘汰策略是 noeviction,并且默认不设定最大内存(maxmemory),这意味着默认配置下 Redis 几乎不会进行内存的淘汰操作,当内存不足时,新的写入会失败。所以,根据应用场景的不同,需要我们去合理设置淘汰策略,以实现不同的业务需求。

数据库有1000万数据 ,Redis只能缓存20w数据, 如何保证Redis中的数据都是热点数据 ?

可以使用 allkeys-lru (挑选最近最少使用的数据淘汰)淘汰策略,那留下来的都是经常访问的热点数据

内存用完了会发生什么

根据淘汰策略,默认情况下直接报错
allkeys-lru会把最常访问的数据留在缓存

分布式锁如何实现

redis提供了setnx命令,只有在关键词不存在的情况下才设置值。

如何控制分布式锁有效时间

redisson

单纯依赖setnx不好控制,采用redisson实现,redisson默认开启看门狗,设置30秒超时,每隔10秒自动检测,增加到30秒,直到锁释放
或者直接指定超时时间,指定超时事件后看门狗默认失效

lua

if redis.call("setnx", KEYS[1], ARGV[1]) == 1 then
    return redis.call("expire", KEYS[1], ARGV[2])
else
    return 0
end

setnx 功能用于尝试获取锁,如果锁不存在(也就是还没有被其他客户端获取),那么设置锁并返回 1。如果锁已经存在,那么不做任何操作并返回 0。如果成功获取到锁,然后立即使用 expire 命令设置锁的有效时间。

redisson实现的分布式锁是可重入的吗?

在 Redisson 中,RLock 对象实现了 java.util.concurrent.locks.Lock 接口,因此它具有可重入的特性。这意味着同一个线程可以多次获取同一个锁,而不会被自己阻塞住。
每次当同一个线程再次获得同一把锁时,重入次数会增加;反过来,当释放锁时,重入次数则会减少。只有当重入次数减少到 0 时,该锁才真正被释放,其他线程才有机会获得该锁。
这种可重入的特性使得我们在使用 Redisson 的分布式锁时,可以像使用 Java 中的 synchronized 关键字或 ReentrantLock 锁一样,避免了死锁的发生,使得编程模型更为简洁和安全。
但是需要注意的是,虽然 RLock 支持可重入,但是在分布式环境中,由于网络等原因,可能会出现一些不可预见的情况。因此在实际使用过程中,可能还需要结合其他手段,如设置合理的锁超时时间,以防止死锁的发生。

参考

新版Java面试专题视频教程,java八股文面试全套真题+深度详解(含大厂高频面试真题)(https://www.bilibili.com/video/BV1yT411H7YK)

  • 24
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值