Redis缓存常见问题

本文探讨了缓存雪崩、缓存穿透和缓存击穿这三个常见的缓存问题,并提出了具体的解决策略,包括设置不同过期时间、采用集群部署、使用布隆过滤器等方法。

一 缓存雪崩 

        reids缓存key同一时间大量失效,导致大量请求全部访问数据库,造成数据库压力过大宕机。
解决方案:

        设置缓存的不同过期时间,是的缓存不会在同一时间失效,导致所有的请求都直接访问数据库。

        redis采用集群部署,将一些热点的key进行集群化部署,使得热点的key平均的分布在不同的redis系统中。

        通过定时任务对缓存进行刷新缓存,同时将新的缓存设置失效时间。


二 缓存穿透 

        指缓存和数据库中都没有的数据,一般常见的黑客攻击,一般是黑客攻击,如通过请求id=-1的数据,这样数据直接透过缓存,直接请求数据库,导致数据库挂掉。 

        redis缓存中的数据不存在,则会去请求数据库。

解决方案:

        将用户的新请求缓存,使得用户的错误请求访问缓存而不是直接请求数据库。

        对参数的合法性做前置校验。

        对错误请求用户的ip拉黑。

        布隆过滤器。


三 缓存击穿 

        用户请求时间超过了redis缓存的时间,导致用户请求直接发送到数据库,此时数据库压力过大宕机。
解决方案:

        缓存永远不过期(存在一些问题,谨慎使用)。

        分布式锁(互斥锁):当大量用户访问redis的数据的时候,当数据已经存在于缓存中的时候,则直接返回给用户,当数据不存在时,则会将直接请求数据库,此时通过对请求数据库的操作加锁,此时同一时间只有一个线程能够抢到这个锁,也就是只有一个线程能够操作这个数据库。当线程查到数据时,将这个数据写入缓存中,其他线程再次请求时就会直接访问redis中的缓存数据。

        分布式锁:zookeeper, redis分布式锁。

思考:项目可以分为上线前准备(redis,mysql,项目分布式集群),项目上线中的准备(采用限流降级的措施防止大量数据打到数据库上,导致系统宕机,集成报警系统),以及上线后一些问题的处理(通过redis RDB/AOF持久化机制来对缓存数据进行恢复,最大限度的减少系统的不可用时间)。

### Redis 缓存常见问题及解决方案 #### 1. 缓存击穿 缓存击穿指的是某个热点 key 过期后,此时有大量的请求访问该 key,在重新加载缓存之前,所有的请求都会直接到达数据库,导致数据库压力骤增。 **解决方案** - **加锁机制**:通过分布式锁控制只有一个线程能够重建缓存,其他线程等待直到缓存构建完成后再读取缓存[^1]。 - **永过期策略**:对于特别热的 key 设置较长的时间或者设置过期时间,减少因 key 到期带来的冲击[^2]。 --- #### 2. 缓存雪崩 缓存雪崩指的是某一时刻大量缓存在同一时间失效,导致大量的请求直接落到数据库上,造成数据库负载过高甚至崩溃。 **解决方案** - **随机化过期时间**:为同的 key 添加随机化的过期时间,避免多个 key 同时到期引发雪崩效应。 - **限流降级**:在高峰期对流量进行限制,防止过多请求涌入数据库;同时可以通过熔断机制来保护下游服务[^3]。 --- #### 3. 缓存穿透 缓存穿透是指查询一个既缓存中又存在于数据库中的 key,这种情况下每次请求都会直达数据库,增加其负担。 **解决方案** - **空值缓存**:将查询结果为空的情况也存储至缓存中,并设定较短的有效期,这样后续相同的请求可以直接返回而无需再次查询数据库[^4]。 - **布隆过滤器**:利用布隆过滤器提前判断是否存在对应的数据记录,有效拦截那些可能存在于实际数据集内的非法请求,减轻后台系统的压力。 --- #### 示例代码实现——基于 Redis 的简单缓存管理逻辑 以下是针对上述三种场景的一个基础示例: ```python import redis from threading import Lock # 初始化 Redis 客户端 r = redis.Redis(host='localhost', port=6379, db=0) lock = Lock() def get_data_from_cache(key): data = r.get(key) if not data: with lock: # 使用锁确保单线程更新缓存 if not r.exists(key): # 双重检查锁定模式 data = fetch_data_from_db(key) # 查询数据库 if data is None: r.setex(key, 60, "") # 如果数据为空,则缓存空值一段时间 else: r.set(key, data) # 将新获取的数据加入缓存 return data or "" def fetch_data_from_db(key): """模拟从数据库中提取数据""" # 实际应用中替换为真实的数据库操作 return {"key": "value"} if key == "valid_key" else None ``` ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值