反向代理和负载均衡是什么?
一句话回答
反向代理站在服务端前面,代表服务端接收请求、再转发给后端,客户端不知道背后有哪些真实的服务器;正向代理正好相反,代表客户端去访问外部。负载均衡是反向代理最常见的用途:按轮询、加权、最少连接、哈希等算法把请求分发到多台服务器,并通过健康检查自动摘除故障节点。按工作的层级,负载均衡分为四层(按 IP 和端口转发,如 LVS)和七层(理解 HTTP 内容,如 Nginx)。
详细解析
正向代理和反向代理
| 正向代理 | 反向代理 | |
|---|---|---|
| 代表谁 | 客户端 | 服务端 |
| 谁知道它的存在 | 客户端,需要主动配置代理 | 服务端;客户端以为自己在直接访问服务器 |
| 隐藏了谁 | 客户端:服务端看到的是代理的地址 | 后端:客户端不知道背后有哪些真实的服务器 |
| 例子 | 公司内网的上网代理、开发时用的抓包工具 | Nginx、云厂商的负载均衡、API 网关、CDN |
反向代理的作用
- 负载均衡:把请求分发到多台后端服务器
- TLS 终止:在代理上统一处理 HTTPS 和证书,代理到后端走内网 HTTP,后端不用各自配置证书
- 缓存与压缩:缓存静态资源或部分接口的响应,统一开启 gzip 压缩
- 隐藏后端、安全防护:后端不直接暴露在公网;可以在代理上做限流、IP 黑白名单、WAF
- 统一入口:同一个域名下按路径转发,比如
/返回前端页面,/api/转发给后端服务。前端调用接口就是同源请求,不存在跨域问题(见跨域)
负载均衡算法
| 算法 | 规则 | 适用场景 |
|---|---|---|
| 轮询 | 按顺序依次分配 | 服务器配置相近,请求耗时差不多 |
| 加权轮询 | 按权重分配,权重高的分到更多请求 | 服务器配置不同 |
| 最少连接 | 分给当前活跃连接最少的服务器 | 请求耗时差异大,比如有长连接、慢请求 |
| IP 哈希 | 对客户端 IP 做哈希,同一个客户端固定到同一台服务器 | 需要会话保持 |
| 一致性哈希 | 服务器和请求的 key 映射到同一个哈希环上,增减服务器时只有少部分请求受影响 | 缓存集群,让同一个 key 尽量落到同一台机器 |
| 随机 | 随机选择,也可以加权 | 简单场景,请求量大时效果接近轮询 |
四层和七层负载均衡
| 四层负载均衡 | 七层负载均衡 | |
|---|---|---|
| 工作层级 | 传输层 | 应用层 |
| 转发依据 | IP 和端口,转发 TCP / UDP 流量,不看内容 | URL、域名、请求头、Cookie 等 HTTP 内容 |
| 性能 | 高 | 相对低,要解析协议,HTTPS 还要解密 |
| 能力 | 只做转发 | 按路径路由、改写请求头、缓存、TLS 终止、灰度发布 |
| 代表 | LVS、云厂商的网络型负载均衡 | Nginx、HAProxy、云厂商的应用型负载均衡 |
Nginx 用 stream 模块也能做四层转发。大型系统常把两者组合起来:外层用四层负载均衡承接流量,内层用 Nginx 集群做七层路由。分层的概念见网络分层模型。
健康检查
- 主动检查:定期探测后端(建立 TCP 连接,或者请求
/health这类接口),连续失败若干次就摘除,恢复后再加回来 - 被动检查:根据真实请求的失败情况判断,比如 Nginx
server指令的max_fails和fail_timeout参数。Nginx 开源版要做主动检查,需要借助第三方模块或商业版 NGINX Plus
会话保持
后端有多台服务器时,如果会话存在某一台的内存里,下一个请求落到别的机器上就找不到了。用 IP 哈希或粘性会话把同一个用户固定到同一台服务器,可以解决问题,但会导致负载不均,那台服务器故障时会话照样丢失。更好的做法是让服务无状态:会话存到 Redis 等共享存储里,或者改用 JWT(见 Cookie、Session、Token、JWT 的区别)。
获取真实的客户端 IP
经过代理后,后端看到的连接来源是代理的 IP,代理要通过请求头传递客户端的地址:
X-Forwarded-For:形如X-Forwarded-For: 203.0.113.7, 10.0.0.2,最左边是客户端的地址;每经过一层代理,代理就把它看到的上一跳地址追加到末尾X-Real-IP:Nginx 常用的做法,只放一个地址,通常取自$remote_addr
这些请求头客户端可以伪造,只能信任由自己的代理追加的值,见下面的追问。
代码示例
Nginx 配置:
upstream api_servers {
least_conn; # 最少连接;不写则默认是加权轮询
# ip_hash; # 换成 IP 哈希:同一个客户端固定到同一台
server 10.0.0.11:3000 weight=3; # 权重越高,分到的请求越多
# 被动健康检查:30 秒内失败 3 次,接下来 30 秒不再分配请求
server 10.0.0.12:3000 weight=1 max_fails=3 fail_timeout=30s;
keepalive 32; # 每个 worker 进程最多保留的空闲长连接数(1.29.7 起默认开启)
}
server {
listen 443 ssl;
server_name example.com;
ssl_certificate /etc/nginx/certs/example.com.pem;
ssl_certificate_key /etc/nginx/certs/example.com.key;
# 前端单页应用
location / {
root /var/www/app;
try_files $uri $uri/ /index.html;
}
# 接口转发到后端集群,和页面同域,不存在跨域
location /api/ {
proxy_pass http://api_servers; # 不带路径:/api/users 原样转发
proxy_http_version 1.1; # 这一行和下一行配合 keepalive 复用连接(1.29.7 起已是默认值)
proxy_set_header Connection '';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
面试官可能追问
一致性哈希的原理是什么?
- 把哈希值的空间(比如 0 到 2 的 32 次方减 1)首尾相连,组成一个环
- 每台服务器按自己的哈希值放到环上;请求的 key 也算出哈希值,从这个位置顺时针找到的第一台服务器,就是目标服务器
- 增加或删除一台服务器时,只有相邻区间的 key 需要迁移;而普通的取模(
hash(key) % N)在 N 变化时,几乎所有 key 的位置都会变 - 服务器少时,在环上容易分布不均,可以给每台物理服务器设置多个虚拟节点,让负载更均匀
负载均衡器自己挂了怎么办?
- 主备 + 虚拟 IP:两台负载均衡器用 Keepalived(基于 VRRP 协议)共享一个虚拟 IP,平时由主节点持有;主节点故障时,备节点自动接管这个 IP,客户端无感知
- 多活:DNS 解析到多个入口 IP,某个入口故障时从解析中摘除
- 云厂商的负载均衡服务本身就是集群化、跨可用区部署的
X-Forwarded-For 可以信任吗?
不能直接信任。客户端可以自己在请求里带一个伪造的 X-Forwarded-For,代理只会在后面追加,所以最左边的值完全可能是假的。可信的只有自己的代理追加的部分:从右往左看,跳过自己信任的代理地址,遇到的第一个其他地址就是真实的客户端 IP。只有一层代理时,直接用代理按 $remote_addr 设置的 X-Real-IP 即可。后端要正确配置可信代理,比如 Nginx 的 set_real_ip_from 和 real_ip_header,Express 的 trust proxy。
易错点
- 正向代理和反向代理的技术实现差不多,区别在于代表谁、对谁透明
proxy_pass的地址带不带路径,行为不同:写成http://api_servers/时,/api/users会被转发成/users- IP 哈希不保证均衡:大量用户在同一个 NAT 出口后面时,请求会集中到一台服务器上;Nginx 的
ip_hash只用 IPv4 地址的前三段计算,同一个 /24 网段的用户都会落到同一台
AI 模拟面试官
用自己的话回答,AI 对照参考答案打分、指出遗漏,再追问,最多 3 轮
这道题你掌握了吗?
选一个最接近的状态,没掌握的题会出现在"我的进度 · 待复习"里。
学习记录暂存在本机浏览器。登录后自动同步到账号,换设备也能看到。