当前位置: 首页 > news >正文

Day30:Redis 缓存策略 + 菜单实战缓存 + 三大缓存问题(穿透 / 击穿 / 雪崩)

一、今日学习目标

  1. 掌握字典缓存、分布式缓存概念
  2. 吃透缓存穿透、缓存击穿、缓存雪崩原理 + 解决方案
  3. 实战:把菜单树、角色权限加入 Redis 缓存
  4. 适配 DDD 架构,缓存和业务解耦
  5. 整理高频面试题标准答案

二、基础概念

1. 本地内存缓存 vs 分布式缓存

本地缓存(MemoryCache)

  • 进程内缓存,每个服务独立一份
  • 集群 / 多实例不共享
  • 优点:速度最快、无网络开销
  • 缺点:数据不一致、无法跨服务共享

分布式缓存(Redis)

  • 独立中间件,所有服务共用一份缓存
  • 集群、微服务、多实例数据共享
  • 可设置过期、持久化、支持多种数据结构
  • 后台管理系统必用 Redis

2. 字典缓存

不常变动、全局共用的数据放缓存:

  • 菜单树形列表
  • 角色列表
  • 数据字典
  • 系统配置特点:改动少、查询多、适合全局缓存

三、三大缓存问题 原理 + 企业级解决方案(面试必背)

1. 缓存穿透

现象

请求数据库不存在的数据,缓存也没有,每次都直接打数据库。例如:查不存在的用户 ID、恶意伪造大量不存在 Key。

解决方案

  1. 缓存空值,设置短期过期
  2. 布隆过滤器拦截不存在 Key
  3. 接口参数校验、非法参数直接拦截

2. 缓存击穿

现象

热点 Key刚好过期,瞬间大量请求同时打到数据库。例如:首页菜单、热门角色配置。

解决方案

  1. 互斥锁(分布式锁)同一时间只放行一个请求查库
  2. 热点 Key永不过期
  3. 后台定时主动刷新缓存

3. 缓存雪崩

现象

大量缓存 Key 同一时间过期,瞬间全部请求压垮数据库;或 Redis 宕机。

解决方案

  1. 给过期时间加随机偏移,避免同时失效
  2. Redis 集群高可用(主从 + 哨兵)
  3. 多级缓存:本地缓存 + Redis
  4. 服务熔断、降级限流

四、高频面试题 + 标准答案

1. 为什么菜单、角色适合做缓存?

菜单 / 角色改动少、查询频率极高,每次登录、侧边栏渲染都要查库,缓存后大幅减少 DB 压力,提升接口响应速度。

2. 分布式缓存和本地缓存区别?

本地缓存进程独享、不支持多实例共享;Redis 分布式缓存全局共享,适合集群、微服务项目,支持过期、持久化、原子操作。

3. 怎么保证缓存和数据库一致性?

  • 更新 / 删除时:先改库,再删缓存
  • 不做更新缓存,直接删除,下次查询自动重建
  • 强一致性场景可用:队列异步延迟删缓存

4. 为什么不建议缓存永久不过期?

数据变更后缓存不会自动更新,容易脏数据,必须手动删缓存刷新。


五、实战练习:菜单信息接入 Redis 缓存(DDD 架构直接可用)

业务思路

  1. 查询菜单树 → 先查 Redis
  2. 有缓存直接返回
  3. 无缓存查数据库,写入 Redis 再返回
  4. 新增 / 编辑 / 删除菜单、分配角色菜单时 → 清空对应缓存,保证一致性

1. 缓存 Key 规范

menu:tree:all // 全量菜单树 menu:user:{userId} // 当前用户菜单树

2. MenuService 改造缓存版核心逻辑

① 获取全量菜单树(加缓存)

// 缓存Key private const string AllMenuTreeKey = "menu:tree:all"; public async Task<R<List<MenuVo>>> GetTreeListAsync() { // 1.先查Redis var cacheData = await _redis.GetAsync<List<MenuVo>>(AllMenuTreeKey); if (cacheData != null && cacheData.Any()) { return R<List<MenuVo>>.Success(cacheData); } // 2.缓存没有,查库 var allMenus = await _uow.MenuRepository.GetAllAsync(); var voList = _mapper.Map<List<MenuVo>>(allMenus); var tree = BuildMenuTree(voList, 0); // 3.写入Redis 缓存30分钟 await _redis.SetAsync(AllMenuTreeKey, tree, 30); return R<List<MenuVo>>.Success(tree); }

② 获取当前用户菜单树(加缓存)

public async Task<R<List<MenuVo>>> GetUserMenuTreeAsync(long userId) { string key = $"menu:user:{userId}"; // 1.读缓存 var cacheData = await _redis.GetAsync<List<MenuVo>>(key); if (cacheData != null && cacheData.Any()) { return R<List<MenuVo>>.Success(cacheData); } // 2.查库逻辑不变... // ...省略原有查角色、查菜单、建树代码 // 3.写入缓存 await _redis.SetAsync(key, tree, 30); return R<List<MenuVo>>.Success(tree); }

③ 菜单新增 / 修改 / 删除、角色分配菜单清空缓存

任意菜单变更、角色分配菜单后,删除所有菜单相关缓存

// 清除菜单缓存 await _redis.DeleteAsync(AllMenuTreeKey); // 可按需清空所有用户菜单缓存,简单项目直接清全量即可

规范:改库 → 删缓存 → 下次访问自动重建缓存


六、今日任务清单

✅ 理解本地缓存 / 分布式缓存区别
✅ 背熟 缓存穿透、击穿、雪崩 原理 + 方案
✅ 自定义菜单缓存 Key 规范
✅ 改造菜单树接口接入 Redis
✅ 菜单变动主动清空缓存,保证数据一致
✅ 整理本周 Redis 面试题,可直接背面试

http://www.jsqmd.com/news/811755/

相关文章:

  • 从 3D Gaussian Splatting 到具身智能:AI 正在学会“进入世界”
  • 别再空谈帕累托最优了!用Python+Excel手把手教你做资源分配决策分析
  • 开源智能抓取框架:为低成本机械爪赋予视觉与决策能力
  • Word公式转MathType:从批量转换报错到权限配置的实战复盘
  • 手机号逆向查询QQ号:3分钟掌握终极查询技巧
  • EdgeCIM框架:存内计算技术如何优化边缘设备上的小型语言模型
  • 多模态大模型学习笔记(三十九)——生成式与Transformer式OCR:从“像素抄录“到“文档智能“的完整演进
  • 智能工厂的核心交互:薄膜开关技术在新型基础设施中的关键作用
  • 五款API管理系统的功能体系与数据表现
  • 使用TaotokenTokenPlan套餐在长期项目中获得更大优惠的方法
  • Taotoken多模型聚合平台为arm7边缘AI应用提供稳定API服务
  • “柔”不是降低饱和度!Pastel印相的光学衍射模拟原理,及如何用--chaos 23–47精准控制粉彩颗粒噪点分布
  • Unlock-Music:浏览器音乐解锁工具完全指南
  • Python环境PyTorch无法调用GPU_检查CUDA驱动与版本匹配性
  • 覆盖成都各区的川师大家教网(大学生创业平台),怎么帮孩子挑个合适的学霸老师? - 教育快讯速递
  • 从图像融合到系统设计:EDA工程师的跨界思维迁移与工具选型实践
  • A1 学习速查表
  • 2026年GEO优化服务商口碑哪家好?案例验证与服务响应深度解析 - 科技焦点
  • 兔抗FANCI抗体亲和纯化,IP-WB全流程兼容设计,一站式解决FANCI蛋白分析功能
  • 从接入到上线观察 Taotoken 对开发者体验的整体提升
  • Arm Cortex-R52处理器流水线优化与指令调度实战
  • 2026年三款最值得在线预约小程序,解决您的预约难题
  • 在Windows上安装安卓应用的轻量化实践
  • 用ChatGPT 10分钟生成TikTok爆款脚本:5步工作流+3类高转化话术模板(附Prompt库下载)
  • 【OAI实战】基于Docker-Compose的5G核心网基础部署与排错指南
  • 实习期如何脱颖而出?3个月转正答辩的满分操作
  • 2026年GEO优化公司专业性评测:五大服务商技术能力深度对比 - 科技焦点
  • SpringAI全流程实战手册
  • DSP28335串口调试别再抓瞎了!手把手教你重定向printf到串口(附完整代码)
  • MBTI十六型人格职业性格测试源码完整版 亲测源码