Redis使用场景:
根据简历业务回答
缓存:穿透 击穿 雪崩 双写一致 持久化 数据过期 淘汰策略
分布式锁:setnx redisson
缓存穿透
查询一个不存在的数据,mysql查询不到数据也不会直接写入缓存,导致每次请求都要查数据库
解决方案一:缓存空数据,查询返回的数据为空,仍然把这个空结果(null)缓存起来
特点:简单但是消耗内存,还可能造成不一致问题(后续如果查询的位置添加了数据,但是缓存中还是原来的null)
解决方案二:布隆过滤器(检索数据是否在一个集合中)
布隆过滤器原理:使用bitmap将redis中key(也可以放其他数据比如重复请求的攻击者ip,垃圾邮件发件人等)经过几次hash函数计算映射过去(对应位置改为1,默认为0),此时查询请求发送过来会先经过布隆过滤器,请求的id编号在经过hash函数计算后若是能在bitmap中对应上,则放行,否则拦截。
缓存预热:将经常查询使用的热点数据提前存入redis和布隆过滤器
特点:占用内存小,无多余key,但实现复杂,存在误判情况
缓存击穿
有过期时间的key在过期时,恰好有大量的对这个key的并发请求(因为是并发请求,所以虽然会查询数据库并存入redis但会消耗时间,这段时间足以压垮DB),会压垮DB
解决方案一:互斥锁
锁是一个广义的概念,可以包括各种类型的并发控制机制
互斥锁是锁的一种特定类型,专门用于独占访问资源,保证同一时刻只有一个线程可以访问资源,适用于简单的互斥需求
特点:强一致性(只会有一个线程拿到锁并重建缓存)但性能差
解决方案二:逻辑过期
通过引入一个额外的字段来记录缓存中的数据是否已经过期,从而避免脏数据被继续使用。逻辑过期并不会物理删除缓存中的数据,而是通过逻辑判断数据是否仍然有效(下图绿色虚线表示时间)
线程1查询发现逻辑时间过期,于是获取一个互斥锁并开启一个新的线程用来更新数据(从数据库查询),原来的线程继续进行并返回过期数据。
特点:高可用 性能优 但不保证数据绝对一致
缓存雪崩
同一时段大量缓存的key同时失效或Redis服务宕机,导致大量请求给到数据库
解决方案:
1.给不同的key的TTL(失效时间)添加随机值
2.利用Redis集群提高服务的可用性(哨兵模式、集群模式)
哨兵模式(Sentinel Mode)是 Redis 提供的一种高可用架构,用于监控 Redis 主从集群中的各个实例,确保系统在 Redis 主节点故障时能够自动进行主从切换,保证服务的高可用性。哨兵模式除了监控 Redis 实例,还负责通知客户端更新主节点的地址
集群模式(Cluster Mode)是 Redis 的一种分布式架构,用于在大规模分布式场景中进行数据分片和高可用管理。Redis 集群模式允许 Redis 在多个节点之间分配数据,从而提高系统的可扩展性、容错性和性能。
3.给缓存业务添加降级限流策略(ngxin或spring cloud gateway)(降级可作为系统保底策略,适用于穿透、击穿、雪崩)
Nginx 可以配置备份服务或默认响应,当缓存不可用或后端服务响应超时时,返回默认的数据或静态页面。
Spring Cloud Gateway 提供了熔断器(Circuit Breaker)功能,可以配置降级逻辑。当调用的后端服务失败时,熔断器触发降级操作,返回默认的降级响应。
4.给业务添加多级缓存(Guava或Caffeine)
Guava 是一个强大的 Java 缓存库,提供了简单的内存缓存管理,支持自动过期、最大容量限制、基于时间的回收等功能。
Caffeine 是 Guava 缓存的替代品,性能更好,且使用类似的 API。Caffeine 支持异步加载、最大容量限制和基于访问频率的回收策略。