总结:如何区分Redis中的缓存穿透与缓存击穿
1. 定义与区别
缓存穿透(Cache Penetration)
+ 定义:查询的数据既不在缓存中,也不在数据库中,但用户仍然频繁请求该数据,导致请求直接穿透到数据库,增加数据库压力。
+ 核心问题:请求的数据根本不存在,但请求量很大,导致数据库被无效查询。
缓存击穿(Cache Breakdown)
+ 定义:热点数据的缓存失效,大量并发请求同时查询该数据,导致请求直接冲击数据库,增加数据库压力。
+ 核心问题:缓存中的数据失效,但数据库中有对应的数据,请求量集中导致数据库压力骤增。
2. 常见场景
缓存穿透
+ 用户请求不存在的ID(如负数ID或非法字符)。
+ 恶意攻击者故意请求不存在的数据。
缓存击穿
+ 热点数据(如热门商品信息、热门新闻)的缓存过期。
+ 大量用户同时请求该热点数据。
3. 解决方案
缓存穿透
+ **布隆过滤器(Bloom Filter)**:在缓存层前加一层布隆过滤器,预存所有合法Key的哈希值。请求到达时,先检查布隆过滤器,若不存在则直接拦截请求,返回空;若存在则再查询缓存或数据库。
- 优点:内存占用少,能有效拦截不存在的请求。
- 缺点:可能存在误判,需要合理设置参数。
+ **缓存空值(Cache Null)**:对查询结果为空的Key,缓存一个Null值,避免重复穿透。
- 优点:实现简单,能有效减少数据库压力。
- 缺点:可能会占用额外的缓存空间。
+ **参数校验**:在查询缓存之前,先对请求的参数进行合法性检查,如过滤非法字符、判断参数范围等,对于明显错误的参数,直接拦截返回。
缓存击穿
+ **互斥锁(Mutex Lock)**:当缓存失效时,通过分布式锁让一个线程重建缓存,其他线程等待锁释放后重试。
- 优点:能有效避免多个线程同时查询数据库。
- 缺点:实现复杂,可能会影响性能。
+ **永不过期(Logical Expiration)**:对热点Key设置物理永不过期,通过后台异步线程定期更新缓存,保证数据新鲜度。
- 优点:避免缓存失效导致的数据库压力。
- 缺点:需要额外的逻辑来管理缓存更新。
+ **熔断降级**:在缓存失效期间,启用降级策略(如返回默认值或静态页面),保护数据库。
- 优点:能有效缓解数据库压力。
- 缺点:用户体验可能受影响。
4. 对比与记忆秘诀
对比
+ 缓存穿透:Redis和MySQL都没有数据,由非正常的数据访问引发的问题。
+ 缓存击穿:正常的数据失效(如热点数据缓存过期)引发的问题。
记忆秘诀
+ 缓存击穿:核心是热点数据失效 -> 解决方案是重建热点数据。可以联想为“击穿犯罪嫌疑人的心里防线”,是“正义之词”。
+ 缓存穿透:核心是Redis和MySQL都没有数据 -> 解决方案是拦截无效请求。可以联想为“穿透犯罪嫌疑的心里防线”是不合适的,是“非正义之词”。例如,“你这点小心思,我还看不‘透’”,“透”这个词通常用来描述不好的事情。