强曰为道

与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

反向代理与负载均衡

反向代理与负载均衡

Apache 的 mod_proxy 模块提供了强大的反向代理和负载均衡功能,可以将请求转发到后端服务器。

1. mod_proxy 架构

1.1 模块组成

模块功能
mod_proxy代理核心框架
mod_proxy_httpHTTP/HTTPS 代理
mod_proxy_fcgiFastCGI 代理
mod_proxy_wstunnelWebSocket 代理
mod_proxy_balancer负载均衡
mod_proxy_connectCONNECT 方法代理
mod_proxy_ajpAJP 协议代理
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重定向路由

状态标记:

标记含义
+HHot 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. 注意事项

  1. 安全性:代理配置不当可能导致内网暴露
  2. 性能:代理会增加延迟,合理配置超时
  3. 日志:确保记录代理日志以便故障排查
  4. 缓存:利用代理缓存减少后端压力
  5. 健康检查:定期检查后端服务健康状态
  6. WebSocket:需要较长的超时时间和特殊配置

8. 扩展阅读

9. 总结

Apache 的反向代理和负载均衡功能强大而灵活:

  • 反向代理:保护后端服务器,统一入口
  • 负载均衡:多种算法,支持会话亲和
  • 健康检查:自动检测故障节点
  • WebSocket:支持现代实时应用

合理配置代理和负载均衡可以提高应用的可用性和扩展性。