反向代理与负载均衡
反向代理与负载均衡
Apache 的 mod_proxy 模块提供了强大的反向代理和负载均衡功能,可以将请求转发到后端服务器。
1. mod_proxy 架构
1.1 模块组成
| 模块 | 功能 |
|---|---|
mod_proxy | 代理核心框架 |
mod_proxy_http | HTTP/HTTPS 代理 |
mod_proxy_fcgi | FastCGI 代理 |
mod_proxy_wstunnel | WebSocket 代理 |
mod_proxy_balancer | 负载均衡 |
mod_proxy_connect | CONNECT 方法代理 |
mod_proxy_ajp | AJP 协议代理 |
mod_proxy_hcheck | 健康检查 |
1.2 启用模块
# Debian/Ubuntu
sudo a2enmod proxy
sudo a2enmod proxy_http
sudo a2enmod proxy_balancer
sudo a2enmod proxy_wstunnel
sudo a2enmod lbmethod_byrequests
sudo a2enmod lbmethod_bytraffic
sudo a2enmod lbmethod_bybusyness
sudo a2enmod slotmem_shm
sudo a2enmod proxy_hcheck
sudo systemctl reload apache2
2. 基本反向代理
2.1 简单配置
<VirtualHost *:80>
ServerName www.example.com
# 启用代理
ProxyPreserveHost On
ProxyPass / http://localhost:8080/
ProxyPassReverse / http://localhost:8080/
</VirtualHost>
2.2 路径代理
<VirtualHost *:80>
ServerName www.example.com
DocumentRoot /var/www/html
# 主站
# /var/www/html 中的静态文件
# API 代理到后端
ProxyPass /api http://localhost:3000/api
ProxyPassReverse /api http://localhost:3000/api
# 管理后台代理
ProxyPass /admin http://localhost:8080/admin
ProxyPassReverse /admin http://localhost:8080/admin
# 静态资源不代理
ProxyPass /static !
</VirtualHost>
2.3 Location 块代理
<VirtualHost *:80>
ServerName www.example.com
<Location "/app">
ProxyPass http://localhost:8080/
ProxyPassReverse http://localhost:8080/
ProxyPreserveHost On
</Location>
<Location "/api">
ProxyPass http://localhost:3000/
ProxyPassReverse http://localhost:3000/
</Location>
</VirtualHost>
3. 高级代理配置
3.1 请求头设置
<VirtualHost *:80>
ServerName www.example.com
ProxyPass / http://localhost:8080/
ProxyPassReverse / http://localhost:8080/
# 传递真实 IP
RequestHeader set X-Real-IP "%{REMOTE_ADDR}s"
RequestHeader set X-Forwarded-For "%{REMOTE_ADDR}s"
RequestHeader set X-Forwarded-Proto "http"
RequestHeader set X-Forwarded-Host "%{HTTP_HOST}s"
</VirtualHost>
# HTTPS 反向代理
<VirtualHost *:443>
ServerName www.example.com
SSLEngine on
SSLCertificateFile /etc/ssl/certs/example.com.crt
SSLCertificateKeyFile /etc/ssl/private/example.com.key
# 代理到 HTTP 后端
SSLProxyEngine on
SSLProxyVerify none
SSLProxyCheckPeerCN off
SSLProxyCheckPeerName off
ProxyPass / http://localhost:8080/
ProxyPassReverse / http://localhost:8080/
# HTTPS 相关头
RequestHeader set X-Forwarded-Proto "https"
RequestHeader set X-Forwarded-Port "443"
</VirtualHost>
3.2 代理超时设置
<VirtualHost *:80>
ServerName www.example.com
# 连接超时
ProxyTimeout 300
# 详细超时设置
ProxyPass / http://localhost:8080/ timeout=300 connectiontimeout=300
# 保持连接
ProxyPass / http://localhost:8080/ keepalive=On
# 重试设置
ProxyPass / http://localhost:8080/ retry=5
</VirtualHost>
3.3 代理错误处理
<VirtualHost *:80>
ServerName www.example.com
# 自定义错误页面
ErrorDocument 502 /custom-502.html
ErrorDocument 503 /custom-503.html
ProxyPass / http://localhost:8080/
ProxyPassReverse / http://localhost:8080/
# 代理状态检查
ProxyPass /status http://localhost:8080/status
</VirtualHost>
4. 负载均衡
4.1 基本负载均衡
# 定义后端集群
<Proxy balancer://mycluster>
BalancerMember http://192.168.1.101:8080
BalancerMember http://192.168.1.102:8080
BalancerMember http://192.168.1.103:8080
</Proxy>
<VirtualHost *:80>
ServerName www.example.com
ProxyPass / balancer://mycluster/
ProxyPassReverse / balancer://mycluster/
</VirtualHost>
4.2 负载均衡算法
# 按请求数(默认)
<Proxy balancer://cluster-requests>
BalancerMember http://server1:8080
BalancerMember http://server2:8080
ProxySet lbmethod=byrequests
</Proxy>
# 按流量
<Proxy balancer://cluster-traffic>
BalancerMember http://server1:8080
BalancerMember http://server2:8080
ProxySet lbmethod=bytraffic
</Proxy>
# 按繁忙度
<Proxy balancer://cluster-busyness>
BalancerMember http://server1:8080
BalancerMember http://server2:8080
ProxySet lbmethod=bybusyness
</Proxy>
# 轮询(round-robin)
<Proxy balancer://cluster-roundrobin>
BalancerMember http://server1:8080
BalancerMember http://server2:8080
ProxySet lbmethod=byrequests
</Proxy>
算法对比:
| 算法 | 说明 | 适用场景 |
|---|---|---|
byrequests | 按请求数轮询 | 通用场景 |
bytraffic | 按流量分配 | 下载/流媒体服务 |
bybusyness | 按繁忙度分配 | 请求处理时间差异大 |
heartbeat | 基于心跳检测 | 高可用场景 |
4.3 节点权重和参数
<Proxy balancer://mycluster>
# 主服务器(权重高)
BalancerMember http://server1:8080 loadfactor=3
# 次要服务器
BalancerMember http://server2:8080 loadfactor=2
# 备用服务器
BalancerMember http://server3:8080 loadfactor=1 status=+H
# 热备服务器
BalancerMember http://server4:8080 status=+H
# 全局设置
ProxySet lbmethod=byrequests
ProxySet timeout=300
ProxySet max=100
</Proxy>
BalancerMember 参数:
| 参数 | 说明 |
|---|---|
loadfactor | 负载因子(1-100) |
timeout | 连接超时 |
retry | 重试时间(秒) |
ttl | 连接生存时间 |
ping | 健康检查间隔 |
max | 最大连接数 |
smax | 软最大连接数 |
keepalive | 保持连接 |
status | 状态标记 |
route | 会话亲和路由 |
redirect | 重定向路由 |
状态标记:
| 标记 | 含义 |
|---|---|
+H | Hot Standby(热备) |
-H | 非热备 |
+D | 已禁用(可恢复) |
-D | 未禁用 |
+S | 已停止 |
-S | 未停止 |
+I | 忽略错误 |
-I | 不忽略错误 |
+R | 仅接受恢复请求 |
-R | 接受所有请求 |
4.4 会话亲和(Session Affinity)
# 基于 Cookie 的会话亲和
<Proxy balancer://mycluster>
BalancerMember http://server1:8080 route=node1
BalancerMember http://server2:8080 route=node2
ProxySet stickysession=ROUTEID
</Proxy>
<VirtualHost *:80>
ServerName www.example.com
Header add Set-Cookie "ROUTEID=.%{BALANCER_WORKER_ROUTE}e; path=/" env=BALANCER_ROUTE_CHANGED
ProxyPass / balancer://mycluster/
ProxyPassReverse / balancer://mycluster/
</VirtualHost>
# 基于 JSESSIONID 的 Java 应用会话亲和
<Proxy balancer://javacluster>
BalancerMember http://server1:8080 route=node1
BalancerMember http://server2:8080 route=node2
ProxySet stickysession=JSESSIONID
</Proxy>
# 基于 IP 的会话亲和
<Proxy balancer://mycluster>
BalancerMember http://server1:8080
BalancerMember http://server2:8080
ProxySet stickysession=BALANCER_SESSIONID
</Proxy>
4.5 健康检查
# 启用被动健康检查
<Proxy balancer://mycluster>
BalancerMember http://server1:8080 retry=30 timeout=10
BalancerMember http://server2:8080 retry=30 timeout=10
# 设置错误阈值
ProxySet maxattempts=3
</Proxy>
# 启用主动健康检查(mod_proxy_hcheck)
<Proxy balancer://mycluster>
BalancerMember http://server1:8080 hcheck=hc
BalancerMember http://server2:8080 hcheck=hc
ProxySet lbmethod=byrequests
</Proxy>
# 健康检查配置
<Proxy "http://server1:8080">
ProxySet hcheck=true
ProxySet hcmethod=TCP
ProxySet hcinterval=10
ProxySet hcpasses=2
ProxySet hcfails=3
</Proxy>
# 自定义健康检查 URL
<Proxy "http://server1:8080">
ProxySet hcheck=true
ProxySet hcmethod=GET
ProxySet hcuri=/health
ProxySet hcinterval=10
</Proxy>
4.6 负载均衡管理
# 启用管理界面
<Location "/balancer-manager">
SetHandler balancer-manager
Require ip 127.0.0.1
Require ip 192.168.1.0/24
</Location>
访问 http://example.com/balancer-manager 查看和管理负载均衡状态。
5. WebSocket 代理
5.1 基本配置
<VirtualHost *:80>
ServerName ws.example.com
# 启用 WebSocket 代理
ProxyPass /ws ws://localhost:8080/ws
ProxyPassReverse /ws ws://localhost:8080/ws
# 混合 HTTP 和 WebSocket
ProxyPass / http://localhost:8080/
ProxyPassReverse / http://localhost:8080/
ProxyPass /ws ws://localhost:8080/ws
ProxyPassReverse /ws ws://localhost:8080/ws
</VirtualHost>
5.2 SSL WebSocket
<VirtualHost *:443>
ServerName ws.example.com
SSLEngine on
SSLCertificateFile /etc/ssl/certs/ws.example.com.crt
SSLCertificateKeyFile /etc/ssl/private/ws.example.com.key
# WSS (WebSocket Secure)
SSLProxyEngine on
ProxyPass /wss wss://localhost:8080/ws
ProxyPassReverse /wss wss://localhost:8080/ws
# HTTPS
ProxyPass / http://localhost:8080/
ProxyPassReverse / http://localhost:8080/
</VirtualHost>
5.3 实时应用配置
<VirtualHost *:80>
ServerName app.example.com
# 前端
DocumentRoot /var/www/app
# API 代理
ProxyPass /api http://localhost:3000/api
ProxyPassReverse /api http://localhost:3000/api
# WebSocket 代理(如 Socket.IO)
ProxyPass /socket.io ws://localhost:3000/socket.io
ProxyPassReverse /socket.io ws://localhost:3000/socket.io
# 设置超时(WebSocket 需要较长超时)
ProxyTimeout 3600
</VirtualHost>
6. 业务场景
6.1 微服务网关
<VirtualHost *:80>
ServerName gateway.example.com
# 用户服务
ProxyPass /api/users http://localhost:3001/api/users
ProxyPassReverse /api/users http://localhost:3001/api/users
# 订单服务
ProxyPass /api/orders http://localhost:3002/api/orders
ProxyPassReverse /api/orders http://localhost:3002/api/orders
# 产品服务
ProxyPass /api/products http://localhost:3003/api/products
ProxyPassReverse /api/products http://localhost:3003/api/products
# 静态文件
ProxyPass /static !
</VirtualHost>
6.2 应用服务器代理
# Tomcat/Jetty 代理
<VirtualHost *:80>
ServerName app.example.com
ProxyPass / ajp://localhost:8009/
ProxyPassReverse / ajp://localhost:8009/
</VirtualHost>
# Node.js 应用代理
<VirtualHost *:80>
ServerName node.example.com
ProxyPass / http://localhost:3000/
ProxyPassReverse / http://localhost:3000/
RequestHeader set X-Forwarded-Proto "http"
</VirtualHost>
# Python/WSGI 应用代理
<VirtualHost *:80>
ServerName python.example.com
ProxyPass / http://localhost:5000/
ProxyPassReverse / http://localhost:5000/
</VirtualHost>
6.3 CDN 回源代理
<VirtualHost *:80>
ServerName origin.example.com
# 限制 CDN IP 访问
<Directory "/var/www/html">
Require ip 103.21.244.0/22
Require ip 173.245.48.0/20
Require ip 103.22.200.0/22
# ... CDN IP 范围
</Directory>
# 缓存头设置
<IfModule mod_headers.c>
Header set Cache-Control "public, max-age=31536000"
</IfModule>
</VirtualHost>
6.4 A/B 测试
<Proxy "balancer://abtest">
BalancerMember http://server-a:8080 route=a loadfactor=50
BalancerMember http://server-b:8080 route=b loadfactor=50
ProxySet lbmethod=byrequests
</Proxy>
<VirtualHost *:80>
ServerName www.example.com
Header add Set-Cookie "ABTEST=.%{BALANCER_WORKER_ROUTE}e; path=/"
ProxyPass / balancer://abtest/
ProxyPassReverse / balancer://abtest/
</VirtualHost>
7. 注意事项
- 安全性:代理配置不当可能导致内网暴露
- 性能:代理会增加延迟,合理配置超时
- 日志:确保记录代理日志以便故障排查
- 缓存:利用代理缓存减少后端压力
- 健康检查:定期检查后端服务健康状态
- WebSocket:需要较长的超时时间和特殊配置
8. 扩展阅读
9. 总结
Apache 的反向代理和负载均衡功能强大而灵活:
- 反向代理:保护后端服务器,统一入口
- 负载均衡:多种算法,支持会话亲和
- 健康检查:自动检测故障节点
- WebSocket:支持现代实时应用
合理配置代理和负载均衡可以提高应用的可用性和扩展性。