多级缓存架构
大约 14 分钟
多级缓存架构
- Web 应用的客户端缓存
- 应用层的静态资源缓存
- 服务层的多级缓存
引言
缓存是架构设计中提升性能最直接的方法。
举例:假设应用程序将原始数据存放在 MySQL 数据库中。
- MySQL 会将数据存储在硬盘上,以防止掉电丢失。
- 硬盘的 IO 性能比内存差一个数量级。
- 典型的读多写少场景,如淘宝、京东等电商应用,需要进行数据的读写分离, 读多写少。
- 90% 的读取操作通过 Redis 进行数据提取,利用内存的高吞吐特性完成数据操作。
多级缓存架构
分为四层:客户端、应用层、服务层、数据层。
客户端缓存
- 假设商城客户端是浏览器,主要缓存 HTML 中的图片、CSS、JS、字体等静态资源。
- 例如:百度 logo 图片通过 HTTP 的
expires
响应头控制静态图片的有效期。- 过期时间为 2031 年 2 月 8 日 09:26:31。
- 浏览器会将图片以文件形式保存到本地,再次访问时直接从本地读取,减少带宽损耗。
作为客户端缓存呢,只需要进行文件缓存就可以了。
应用层缓存
对于 expire 要在应用层,也就是 CDN 与 nginx 中来进行设置。
在 CDN 与 Nginx 中进行设置。
CDN(内容分发网络):
- 主要技术手段是内容分发。
- 例如:上海用户访问北京服务器资源,通过 CDN 将北京的静态文件缓存到上海服务器,降低网络延迟,提高系统可用性。
- 智能 DNS 根据用户的 IP 自动就近访问 CDN 节点。
- CDN 的核心是智能 DNS 服务。
- 阿里云、腾讯云、华为云等提供 CDN 服务,可以租用,按年付费或流量付费。
- 设置缓存属性:
expires
响应头或cache-control
响应头。expires
指定具体时间点缓存到期。cache-control
设置缓存时长。- 根据不同的业务场景使用不同的响应头。
Nginx:
- 开源的高性能 Web 服务器。
- 作为 Web 应用架构中的常客,可以做负载均衡。
- 适用于企业级应用,通过 Nginx 的静态资源缓存和压缩功能,满足大多数企业级应用场景。
- 在配置文件
nginx.conf
中增加配置片段,对静态资源进行缓存。
服务层缓存
细化为进程内缓存和进程外缓存。
进程内缓存:
进程内缓存即我们常说的分布式缓存,如 redis 等,进程内缓存的应用非常多,如mybatis的一级缓存等(为什么很多sql查第一次慢,后面就快了),如下图:
- 在应用中开辟一段内存空间,数据在运行时载入内存,提高访问速度。
- Java 框架中的应用:Hibernate、MyBatis 的一级缓存、二级缓存,Spring MVC 的页面缓存。
- 开源实现:EHCache、Caffeine 等。
分布式缓存:
- 通过独立部署的缓存服务,常用 Redis。
- 设计多级应用缓存:进程内缓存和分布式缓存相结合。
- 访问顺序:进程内缓存 -> Redis -> 数据库。
- 数据库查询成功后,对 Redis 和进程内缓存进行双写更新。
很多人在设计缓存的时候,认为只要加一个redis就行了,其实不是,我们在设计缓存的时候,一般要遵守如下:
- 先近后远
- 由快到慢
两个规则来进行逐级访问。
即我们在设计相关的数据时要结合进程内缓存以及分布式缓存,如下图:
缓存数据一致性挑战
两级缓存设计后,我们必然遇到其他的问题,例如一致性的问题,如下图:
数据库写操作不会走缓存。
解决方法:引入 MQ 消息队列(如 RocketMQ、RabbitMQ、Kafka)。
- 商品服务实例一对商品价格调整后,向 MQ Broker 发送变更消息。
- Broker 将消息推送到其他实例和 Redis 集群。
- 服务实例收到消息后,删除并重新创建缓存,保证数据一致。
由于以上问题又会产生中间件可靠性的问题
什么时候引入多级缓存?
- 缓存的数据是稳定的:
- 例如:邮政编码、地域区块、归档的历史数据。
- 瞬间可能产生极高并发的场景:
- 例如:12306 春运售票、双十一秒杀、股市开盘交易。
- 解决方法:应用启动时对热点数据进行预热处理。
- 允许引入缓存后数据不一致:
- 例如:博客平台修改自我介绍等非关键性信息。
- 解决方法:通过 T+1 的方式,采用 ETL 日终处理补全数据。
总结
多级缓存提升性能,但也增加一致性问题和架构复杂度。
需根据具体业务场景决定是否引入多级缓存。