1.定期生成:
核心逻辑:
按照固定的时间间隔(比如每个小时,每天)批量生成或者更新缓存,而非依赖实时数据变更触发。
实现方式:
定期任务触发:
写一套离线流程(使用shell,python写脚本代码),然后定期缓存更新。
全量/增量更新:
全量:每次生成所有的缓存数据,覆盖原来的数据。
增量:仅更新上次更新后发生变化的缓存数据。
优点和缺点:
优点:实现简单,过程可控,方便排查问题。
缺点:实时性差,因为是定期更新,会有无效更新的情况,比如缓存数据没有变化还是会更新。
2.实时生成:
核心逻辑:
数据一旦发生变化(数据库更新),缓存数据就会更新或者失效,确保了缓存和数据源的一致性。
一段时间后,redis的key都会是一些热点数据。这样不停地写会导致redis的内存占用越来越多。(逐渐达到内存上限,不一定是机器内存上限,可能是redis配置的内存上限)
然后就有了内存淘汰策略。(经典面试题)
内存淘汰策略:
FIFO(First In First Out)先进先出:
把缓存中存在时间最久的(也就是先来的数据)淘汰掉。
LRU(Least Recently Userd)淘汰最久未使用的:
记录每个key最近访问的时间,把最近访问时间最久 的key淘汰掉。
LFU(Least Frequently Userd)淘汰访问次数最少的:
记录每个key最近一段时间的访问次数,把访问次数最少的淘汰掉。
Random随机淘汰:
从所有的key中随机抽取进行淘汰。
缓存预热:
服务启动或者缓存重新启动时,缓存中可能没有数据,此时所有用户请求会直接穿透到数据库。
数据库可能因为瞬间高并发导致被压垮(特别是一些量大的系统)。
用户体验极差(请求响应时间从毫秒级到秒级别)
缓存预热是通过"提前在缓存中加载一些热点数据",让服务启动后缓存命中率迅速提高,数据库承担的请求压力就会变小。
缓存穿透:
缓存穿透是指:查询某个key时,这个key既没有在redis中,也没有在MySQL中,导致每次请求都会直接穿透缓存,直接访问数据库,如果查询大量这样的key(如黑客的恶意攻击),就会导致数据库压力骤增,甚至导致数据库宕机。
缓存穿透的核心原因:
1.业务逻辑导致无效请求:比如代码中缺少参数校验环节,到时非法的key也能进行查询。
2.黑客的恶意攻击。
3.比如运维和开发误操作:不小心把部分数据从数据库中删除了。
缓存穿透的解决方案:
方案一:缓存空值:
当我们查询一个key时,这个key如果在redis和mysql中都不存在,那么就把它存入redis中并设置一个ttl(过期时间),value设为null。后续相同的请求就会返回null,无需访问数据库。
**优点:**实现简单,无需外部依赖,可以快速拦截非法请求。
缺点:
1.占用缓存空间。(大量空的key会浪费内存)
2.在ttl时间内,如果当前key重新存在了,但仍然返回null,那么就需要等到ttl到了,才能继续设置。(比如商品下架但是又上架了);解决方法:可以ttl为5-30s(平衡内存使用和数据实时性),还可以给空值key加上一个特定的前缀。
方法二:布隆过滤器:
在缓存前加一个布隆过滤器,提前过滤"一定不存在的数据",布隆过滤器是一种空间效率极高的概率性数据结构,能判断一个key是否可能存在于数据源中(存在误判,但不存在漏判)
实现步骤:
需要提前初始化布隆过滤器:将数据中有效的数据key提前导入到布隆过滤器中。
拦截请求:先要通过布隆过滤器,如果布隆过滤器判断这个key不存在,直接返回空结果,不会访问缓存和数据库;但是布隆过滤器判断这个key可能存在,就需要再次访问缓存和数据库。
**优点:**内存占用率极低,查询速度也很快
**缺点:**存在误判,当新增数据时,需要更新布隆过滤器,实现难度较大。
缓存雪崩:
缓存雪崩:在某一时刻,Redis中大量缓存的key同时过期或者Redis集群整体不可用,导致缓存的命中率陡然下降,数据库的压力陡然上升,甚至直接宕机。
核心原因:
1.大量的key同时过期。因为设置了相同的过期时间。一旦到期会同时失效,请求全部打向数据库。
2.Redis的集群故障:因网络中断、服务器宕机、内存耗尽等原因,Redis 集群整体不可用,所有请求被迫直接访问数据库。
解决方案:
1.避免key集中过期,为缓存key设置随机过期时间(base_ttl+random(0-300ms)),避免集中过期。
2.部署哨兵+主从模式,确保单点故障后自动切换。
3.服务降级和熔断:当数据库压力超过阈值时,暂时拒绝部分请求(返回空或者返回错误提示)
4.多级缓存兜底:增加本地缓存,作为Redis的二级缓存,减少数据库访问。
缓存击穿:
缓存击穿:某一个热点的key突然过期了,恰好有大量并发请求访问这个key,导致所有请求穿透到数据库,导致数据库压力骤增,甚至宕机。
解决办法:
1.基于统计的方式,设置热点key永不过期。
2.当缓存未命中时,先尝试获取分布式锁,然后只有获取到锁的请求才能查询数据库,其他请求等待重试,限制同时请求数据库的并发数。
3.提前预热+扩咱过期时间。