透明多级分流
透明多级分流通过在客户端 → CDN → 反向代理 → 应用 → 数据库各层设置缓存,让请求尽早返回。越靠近用户,缓存命中收益越大。
用户请求
└→ [浏览器缓存] → 命中直接返回
└→ [CDN 边缘节点] → 命中直接返回
└→ [反向代理 Nginx] → 命中直接返回
└→ [应用层] → 命中直接返回
└→ [分布式缓存 Redis] → 命中直接返回
└→ [数据库] → 最终数据源提示
客户端缓存、CDN、反向代理、分布式缓存的多级流量分流体系
客户端缓存
强缓存 vs 协商缓存
| 类型 | 响应头 | 行为 | 状态码 |
|---|---|---|---|
| 强缓存 | Cache-Control: max-age=86400 | 有效期内不发请求 | 200(from cache) |
| 协商缓存 | ETag / Last-Modified | 每次请求验证 | 304(未修改) |
强缓存优先级高于协商缓存。
缓存策略
| 内容类型 | 策略 |
|---|---|
| 静态资源(有 hash 名) | max-age=31536000 强缓存 |
| HTML 页面 | no-cache 每次协商 |
| API 接口 | no-store 不缓存 |
CDN
CDN 通过全球分布的边缘节点缓存静态资源,用户请求时 DNS 调度系统根据地理位置返回最近节点,命中缓存就近返回,未命中则回源站拉取并缓存。
适合内容:不频繁变动的静态资源。不适合内容:个性化内容、实时变动数据。
反向代理缓存
Nginx 在反向代理时缓存后端响应,减少对应用服务器的请求。
proxy_cache_path /tmp/nginx_cache levels=1:2 keys_zone=my_cache:10m;
server {
location /api/ {
proxy_cache my_cache;
proxy_cache_valid 200 60m; # 200 响应缓存 60 分钟
proxy_pass http://backend;
}
}分布式缓存(Redis)
三大问题
缓存穿透:查询数据库中不存在的数据,每次都绕过缓存直击数据库。解决:缓存空值(短 TTL)或布隆过滤器拦截。
缓存击穿:热点 key 过期瞬间,大量并发涌入数据库。解决:互斥锁(仅允许一个线程重建缓存)或热点数据永不过期。
缓存雪崩:大量 key 同时过期,大量请求打到数据库。解决:随机化 TTL + 多级缓存 + Redis 高可用。
互斥锁方案
public User getUserWithLock(Long id) {
User user = redis.get("user:" + id);
if (user != null) return user;
if (redis.setNX("lock:user:" + id, "1", 10, TimeUnit.SECONDS)) {
try {
user = userRepository.findById(id).orElse(null);
redis.set("user:" + id, user, 30, TimeUnit.MINUTES);
} finally {
redis.delete("lock:user:" + id);
}
}
return user;
}负载均衡分层
| 层级 | 代表技术 | 工作原理 |
|---|---|---|
| L4(四层) | LVS、F5 | 基于 IP + 端口转发 |
| L7(七层) | Nginx、Gateway | 解析 HTTP 内容智能路由 |
大流量入口用 L4 + L7 组合,微服务内部用 L7。
缓存层选型
| 缓存层 | 工具 | 缓存对象 |
|---|---|---|
| 浏览器 | Cache-Control / ETag | 静态资源 |
| CDN | 阿里云/腾讯云 CDN | 静态资源 + 非个性化内容 |
| 反向代理 | Nginx proxy_cache | 低频变化 API 响应 |
| 本地缓存 | Caffeine / Guava Cache | 高频读、不跨节点共享 |
| 分布式缓存 | Redis | 热点业务数据、Session |
适用场景
| 场景 | 推荐缓存层 | 原因 |
|---|---|---|
| 静态资源(JS/CSS/图片) | CDN + 浏览器强缓存 | 就近访问,减少带宽 |
| 高频读 API | Nginx 反向代理缓存 | 减轻应用服务器压力 |
| 热点业务数据 | Redis 分布式缓存 | 跨节点共享,支持持久化 |
| 用户 Session | Redis | 分布式会话管理 |
FAQ
Q: 缓存穿透、击穿、雪崩有什么区别? A: 穿透是查询不存在的数据,缓存永远不命中,请求直达数据库——解决:缓存空值或布隆过滤器。击穿是热点 key 过期瞬间,大量并发涌入数据库——解决:互斥锁或永不过期。雪崩是大量 key 同时过期,数据库压力骤增——解决:随机化 TTL + 多级缓存 + Redis 高可用。
Q: CDN 适合什么内容? A: 适合不频繁变动的静态资源(图片、视频、JS/CSS 文件、字体)。不适合:个性化内容(用户数据)、实时变动数据(股票行情)、需要鉴权的 API。动态内容可以用 CDN 的边缘计算能力处理,但成本较高。
Q: 本地缓存和分布式缓存如何选择? A: 本地缓存(Caffeine/Guava Cache)适合高频读、数据量小、不跨节点共享的场景(如配置信息、字典表),速度最快但各节点数据可能不一致。分布式缓存(Redis)适合需要跨节点共享、数据量大、需要持久化的场景。生产环境通常两者配合:本地缓存作为 L1,Redis 作为 L2。