什么是多级缓存
传统的缓存策略一般是请求到达Tomcat后,先查询Redis,如果未命中则查询数据库,如图:

存在下面的问题:
- 请求要经过Tomcat处理,Tomcat的性能成为整个系统的瓶颈
- Redis缓存失效时,会对数据库产生冲击
多级缓存就是充分利用请求处理的每个环节,分别添加缓存,减轻Tomcat压力,提升服务性能:
- 浏览器访问静态资源时,优先读取浏览器本地缓存
- 访问非静态资源(ajax查询数据)时,访问服务端
- 请求到达Nginx后,优先读取Nginx本地缓存
- 如果Nginx本地缓存未命中,则去直接查询Redis(不经过Tomcat)
- 如果Redis查询未命中,则查询Tomcat
- 请求进入Tomcat后,优先查询JVM进程缓存
- 如果JVM进程缓存未命中,则查询数据库

在多级缓存架构中,Nginx内部需要编写本地缓存查询、Redis查询、Tomcat查询的业务逻辑,因此这样的nginx服务不再是一个反向代理服务器,而是一个编写业务的Web服务器了。
因此这样的业务Nginx服务也需要搭建集群来提高并发,再有专门的nginx服务来做反向代理。另外,我们的Tomcat服务将来也会部署为集群模式。
可见,多级缓存的关键有两个:
- 一个是在nginx中编写业务,实现nginx本地缓存、Redis、Tomcat的查询
- 另一个就是在Tomcat中实现JVM进程缓存
其中Nginx编程则会用到OpenResty框架结合Lua这样的语言。
目录
多级缓存总结

1. 页面请求静态资源
- 静态资源服务器:item.html页面部署在Nginx服务器上,同时承担静态资源服务器和反向代理服务器双重角色
- 请求流程:用户浏览器请求页面时,Nginx直接返回静态HTML;页面渲染时通过ajax请求数据,请求地址格式为item/{id}
- 反向代理特性:Nginx不处理业务逻辑,仅将数据请求代理给后端OpenResty集群
2. openResty本地缓存
- 缓存机制:使用shared dict实现本地缓存,请求到达后优先查询内存中的缓存数据
- 集群限制:本地缓存仅在当前Nginx进程有效,集群环境下不同节点内存不共享
- 解决方案:
- 负载均衡配置基于商品ID哈希路由(非轮询)
- 相同ID始终路由到同一OpenResty节点,确保缓存命中率
- 修改负载均衡算法为基于URL地址的哈希策略
3. openResty查询Redis缓存
- 二级查询:本地缓存未命中时查询Redis集群
- API操作:通过OpenResty提供的Redis操作接口访问缓存
- 命中处理:若Redis命中则直接返回数据,否则继续向下游Tomcat查询
4. 查询Tomcat
- 集群配置:Tomcat同样采用集群部署(示例中2个节点)
- 缓存层级:
- 进程缓存:Tomcat本地JVM缓存,集群间不共享
- 查询顺序:先查进程缓存 → 未命中再查数据库
- 路由策略:
- 基于商品ID哈希路由确保请求一致性
- 相同ID始终访问同一Tomcat节点
- 多级缓存效果:
- 第一级:OpenResty本地缓存
- 第二级:Redis缓存
- 第三级:Tomcat进程缓存
- 最终才访问数据库
5. 数据同步问题
- 同步挑战:数据库修改后需同步Redis/本地缓存/进程缓存
- OpenResty方案:
- 超时失效机制:设置缓存过期时间自动删除
- 适用场景:低频更新数据(如商品基础信息)
- Redis+Tomcat方案:
- Canal监听MySQL binlog变更
- 实时通知Java客户端更新Redis和本地缓存
- 适用场景:高频更新且强一致性要求的数据
- 混合策略:根据数据特性组合使用超时失效和实时同步机制