proxy - gateway - load - balancer - cdn

11. 代理、网关、负载均衡与 CDN

0. 本章先解决什么问题

真实网络服务通常不是“一台客户端直接访问一台服务器”这么简单。

用户访问一个域名,背后可能经过:

浏览器
-> DNS
-> CDN 边缘节点
-> 负载均衡器
-> API 网关
-> 反向代理
-> 多个应用实例
-> 下游依赖

这条链路里,代理、网关、负载均衡、CDN 都可能改变请求路径、Header、缓存行为、超时、来源 IP、错误码。

本章要解决:

  1. 这些中间层分别解决什么问题。
  2. 它们怎样组织多个服务成为一个统一入口。
  3. 502、503、504、来源 IP 丢失、缓存旧内容等问题为什么经常出现在这些层。
  4. 排障时怎样判断问题发生在哪一段。

代理、负载均衡与 CDN 链路

这张图怎么读

这张图把入口链路画成一条可排查路径:CDN、负载均衡、网关、反向代理、应用实例、下游依赖。每一层都可能终止 TLS、改 Header、缓存、限流、重试、设置超时或直接返回错误码。

1. 为什么不能只有一台服务直接暴露

如果所有用户都直接访问一台机器,会遇到:

问题解释
单点故障机器挂了,服务整体不可用
扩展困难流量增长时无法分摊
安全边界弱应用实例直接暴露在外部网络
证书和协议处理重复每个实例都要处理 TLS、压缩、限流等
路由混乱不同路径、不同版本、不同服务难以统一入口
地理距离远用户离源站远,延迟高

中间层的价值是把外部访问和内部服务组织分开。

外部用户看到一个稳定入口;
内部可以有多个实例、多个区域、多种服务。

2. 代理:代替一方发送或接收请求

代理的核心是:它站在通信路径中,代替某一方和另一方交互。

2.1 正向代理

正向代理更靠近客户端,代表客户端访问外部资源。

Client -> Forward Proxy -> Internet Server

客户端知道自己在使用代理,目标服务看到的可能是代理地址。

常见用途:

用途说明
访问控制控制客户端能访问哪些外部资源
审计记录访问行为
缓存缓存外部资源
网络出口统一让内部网络通过统一出口访问外部

2.2 反向代理

反向代理更靠近服务端,代表内部服务接收外部请求。

Client -> Reverse Proxy -> Internal Service

客户端访问的是代理入口,不一定知道背后有多少实例。

常见用途:

用途说明
TLS 终止代理处理 HTTPS,内部可走其他协议
路由转发根据域名、路径、Header 转到不同服务
压缩对响应做压缩
限流控制请求速率
安全过滤拦截异常请求
统一日志记录入口访问

3. 网关:统一入口和协议/策略边界

网关通常比普通反向代理承担更多应用级策略:

Client -> Gateway -> Service A
-> Service B
-> Service C

常见能力:

能力作用
路由按路径、域名、版本把请求转到不同服务
鉴权在入口验证身份或权限
限流防止某些客户端打爆系统
协议转换外部 HTTP,内部可能是另一种协议
统一错误将内部错误包装成统一响应
观测记录日志、指标、追踪信息

网关是系统边界。它的配置错误会让请求根本到不了目标服务,或者让正确请求被错误拒绝。

4. 负载均衡:把流量分给多个实例

负载均衡器的目标是:

一个入口,多台实例,共同承载流量。

负载均衡:一个入口把流量分给多台实例

4.1 四层和七层负载均衡

类型工作层次依据特点
四层 LB传输层IP、端口、连接不理解 HTTP 语义,转发成本低
七层 LB应用层Host、Path、Header、Cookie能做内容路由和应用策略

四层更像连接分发,七层更像理解请求后再路由。

4.2 调度策略

常见策略:

策略含义
轮询依次分配到各实例
加权轮询性能强的实例分更多
最少连接分给当前连接少的实例
哈希按客户端或请求特征稳定分配
一致性哈希节点变化时减少重新映射

不同策略适合不同负载形态。请求耗时差异很大时,简单轮询可能不均衡。

4.3 健康检查

负载均衡不能只知道实例存在,还要知道实例是否健康。

健康检查可能包括:

端口是否开放
HTTP 健康路径是否返回成功
依赖是否可用
实例负载是否过高

如果健康检查过于简单,可能把“端口开着但服务不可用”的实例继续纳入流量;如果检查过于严格,可能把短暂波动误判为故障。

边界条件:健康检查成功不等于真实请求成功

健康检查通常是一个简化请求。它能证明“某个探测路径正常”,但不能证明所有真实请求都正常。

健康检查只证明仍可能失败的真实路径
端口能连接应用线程池已满,业务请求排队
/health 返回成功真实接口依赖的数据库/缓存/外部服务失败
本机进程存活某个租户、区域、版本或路由配置错误
轻量请求很快大请求、上传、长连接、流式响应超时
单实例可用实例之间配置不一致、灰度版本异常

这会制造一种典型故障:

LB 认为实例健康
真实用户请求持续 5xx 或超时

解决思路不是把健康检查无限复杂化,而是分层设计:

  • 存活检查:进程是否还活着
  • 就绪检查:是否能接真实流量
  • 深度检查:关键依赖是否可用
  • 业务指标:真实请求错误率和延迟

健康检查是流量入口的控制信号,不是完整的业务正确性证明。

5. CDN:把内容放到离用户更近的地方

CDN 的核心是边缘缓存和就近访问。

User -> Nearby CDN Edge -> Origin

如果边缘节点有缓存:

User -> CDN Edge -> 返回缓存内容

如果没有缓存:

User -> CDN Edge -> Origin
<- Origin Response
<- 缓存并返回

CDN 常用于:

内容适配原因
图片、脚本、样式静态资源,缓存收益大
下载文件大流量,适合边缘分发
视频切片用户分布广,带宽需求高
可缓存接口读多写少,缓存策略清晰

CDN 也可能做 TLS、压缩、安全过滤、访问控制,但它的核心价值仍然是减少距离和源站压力。

6. 一次请求穿过中间层

一个典型路径:

Client
-> DNS 解析到 CDN 或入口
-> CDN 边缘节点
-> 入口负载均衡
-> 网关
-> 反向代理
-> 应用实例

每一层都可能:

终止 TLS
修改 Header
设置超时
缓存响应
记录日志
丢弃异常请求
返回错误码
重试上游

所以同一个 HTTP 状态码,可能不是应用直接返回的。比如:

状态码可能来源
403CDN 安全策略、网关权限、应用权限
404网关路由不存在、应用路由不存在、CDN 缓存了旧路径
502代理连接上游失败、上游响应格式异常
503负载均衡无健康实例、服务过载
504网关等待上游超时

7. 来源 IP 和转发 Header

经过代理后,应用直接看到的连接来源可能是代理 IP,而不是用户真实 IP。

User IP -> Proxy IP -> App
应用看到 TCP 对端: Proxy IP

为了传递原始来源,代理常加入 Header:

X-Forwarded-For: client, proxy1, proxy2
X-Forwarded-Proto: https
X-Forwarded-Host: example.com

但这些 Header 有信任边界。客户端也可以伪造同名 Header,所以应用不能无条件相信。

正确思路:

代码块JAVA · 2 行收起展开
只信任来自可信代理添加或规范化后的转发头;
在入口处清理外部传入的伪造转发头;

明确记录代理链路和真实来源解析规则。

8. 超时和重试:中间层最容易制造“偶发问题”

每一层都有超时:

客户端超时
CDN 超时
负载均衡超时
网关超时
反向代理超时
应用超时
下游依赖超时

如果它们配置不协调,就会出现复杂现象。

例如:

网关 30s 超时
应用 60s 才放弃下游

结果:
网关 30s 返回 504
应用还在继续占用资源

重试也一样。客户端、代理、网关都可能重试。没有幂等设计时,重试可能导致重复操作。

机制深挖:超时要按链路从内到外收敛

如果中间层很多,超时配置要有顺序感。一个实用原则是:越靠近内部依赖,越早失败;越靠近用户入口,超时略长一些,用来接收内部明确失败,而不是抢先断开。

一个错误配置:

客户端: 20s
网关: 30s
应用: 60s
下游依赖: 55s

结果可能是:

客户端 20s 已经放弃
网关和应用还在占资源
下游依赖继续工作
最后结果无人接收

更合理的方向是:

下游依赖超时 < 应用超时 < 网关超时 < 客户端可等待时间

这不是固定数字规则,而是因果关系:内部越早给出明确失败,外层越能释放连接、返回错误、记录证据。否则一次慢下游会被放大成入口连接堆积、应用线程占满、重试风暴和 504。

9. 联系实际:502、503、504 怎么定位

这三个状态码经常来自中间层:

状态码直觉常见检查
502网关和上游通信异常上游端口、协议、响应格式、连接被重置
503服务不可用是否无健康实例、过载、限流、维护
504等上游超时上游处理慢、网络慢、超时配置不匹配

排查顺序:

  1. 确认错误由哪一层返回:CDN、LB、网关、代理、应用。
  2. 查该层访问日志和上游日志是否有同一个请求。
  3. 判断请求有没有到达应用实例。
  4. 如果没到,查路由、健康检查、连接、TLS、协议。
  5. 如果到了,查应用处理时间和下游依赖。
  6. 检查超时、重试、连接池、空闲连接回收配置。

只看应用日志很可能漏掉入口层问题;只看入口层也可能看不到应用内部耗时。

排障卡:先判断错误码是谁返回的

入口链路长了以后,502/503/504/403/404 不一定来自应用。排障第一件事是定位“响应生成层”。

证据说明
响应 Header可能带 CDN、网关、代理标识
CDN/LB/网关访问日志判断请求是否经过该层,以及上游耗时
应用访问日志判断请求是否真正到达实例
Trace/request id把入口层和应用层日志串起来
上游连接日志判断代理到实例是连接失败、超时还是协议异常
缓存命中标记判断是否根本没回源

一个实用判断:

入口层有日志,应用无日志
-> 问题多半在路由、健康检查、连接、TLS、限流、缓存或代理到上游之间

应用有日志,入口层返回 504
-> 看应用处理是否超过网关超时,或应用是否还在继续占用资源

这能把“服务挂了”拆成“哪一层认为上游不可用”。

10. 学完本章你能解决什么问题

学完本章,你应该能:

  1. 区分正向代理、反向代理、网关、负载均衡、CDN 的核心职责。
  2. 解释四层负载均衡和七层负载均衡的区别。
  3. 理解健康检查、调度策略、超时、重试如何影响可用性。
  4. 判断来源 IP 为什么会变成代理 IP,以及转发 Header 的信任边界。
  5. 分析 CDN 缓存旧内容、命中异常、源站压力变化等问题。
  6. 排查 502、503、504 时判断错误来自入口层、代理层、应用层还是上游依赖。
  7. 画出一个外部请求穿过 CDN、LB、网关、代理、实例的路径,并为每一层列出证据。

延伸阅读