负载均衡器设置
概览
部署和配置负载均衡器以在多个后端服务器之间分配流量,确保高可用性、容错性和基础设施资源的最优利用。
何时使用
- 多服务器流量分配
- 高可用性和故障转移
- 会话持久性和粘性会话
- 健康检查和自动恢复
- SSL/TLS 终止
- 跨区域负载均衡
- 在负载均衡器处进行 API 速率限制
- DDoS 缓解
实施示例
1. HAProxy 配置
# /etc/haproxy/haproxy.cfg
global
log stdout local0
log stdout local1 notice
maxconn 4096
daemon
# 安全
tune.ssl.default-dh-param 2048
ssl-default-bind-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256
ssl-default-bind-options ssl-min-ver TLSv1.2
defaults
log global
mode http
option httplog
option denylogin
option forwardfor
option http-server-close
# 超时
timeout connect 5000
timeout client 50000
timeout server 50000
# 统计
stats enable
stats uri /stats
stats refresh 30s
stats admin if TRUE
# 前端 - 面向公众
frontend web_frontend
bind *:80
bind *:443 ssl crt /etc/ssl/certs/myapp.pem
mode http
option httplog
# 将 HTTP 重定向到 HTTPS
http-request redirect scheme https if !{ ssl_fc }
# 日志记录
log /dev/log local0 debug
# 速率限制
stick-table type ip size 100k expire 30s store http_req_rate(10s)
http-request track-sc0 src
http-request deny if { sc_http_req_rate(0) gt 100 }
# ACLs
acl is_websocket hdr(Upgrade) -i websocket
acl is_api path_beg /api/
acl is_health path /health
acl is_static path_beg /static/
# 路由到适当的后端
use_backend health_backend if is_health
use_backend api_backend if is_api
use_backend static_backend if is_static
use_backend web_backend if is_websocket
default_backend web_backend
# 前端用于内部 API
frontend internal_api_frontend
bind 127.0.0.1:8080
mode http
default_backend stats_backend
# 健康检查后端
backend health_backend
mode http
balance roundrobin
server local 127.0.0.1:8080 check
# 主要 Web 后端
backend web_backend
mode http
balance roundrobin
# 会话持久性
cookie SERVERID insert indirect nocache
# 压缩
compression algo gzip
compression type text/html text/plain text/css application/json
# 带有健康检查的服务器
server web1 10.0.1.10:8080 check cookie web1 weight 5
server web2 10.0.1.11:8080 check cookie web2 weight 5
server web3 10.0.1.12:8080 check cookie web3 weight 3
# 健康检查配置
option httpchk GET /health HTTP/1.1\r
Host:\ localhost
timeout check 5s
# API 后端与连接限制
backend api_backend
mode http
balance least_conn
maxconn 1000
option httpchk GET /api/health
timeout check 5s
server api1 10.0.2.10:3000 check weight 5
server api2 10.0.2.11:3000 check weight 5
server api3 10.0.2.12:3000 check weight 3
# 静态文件后端
backend static_backend
mode http
balance roundrobin
# 静态文件的缓存控制
http-response set-header Cache-Control "public, max-age=31536000, immutable"
server static1 10.0.3.10:80 check
server static2 10.0.3.11:80 check
# 统计后端
backend stats_backend
stats enable
stats uri /stats
stats refresh 30s
2. AWS 应用负载均衡器(CloudFormation)
# aws-alb-cloudformation.yaml
AWSTemplateFormatVersion: '2010-09-09'
Description: '带有目标组的应用负载均衡器'
Parameters:
VpcId:
Type: AWS::EC2::VPC::Id
Description: VPC ID
SubnetIds:
Type: List<AWS::EC2::Subnet::Id>
Description: ALB 的公共子网 ID
Environment:
Type: String
Default: production
AllowedValues: [dev, staging, production]
Resources:
# ALB 的安全组
LoadBalancerSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: ALB 的安全组
VpcId: !Ref VpcId
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: 0.0.0.0/0
- IpProtocol: tcp
FromPort: 443
ToPort: 443
CidrIp: 0.0.0.0/0
SecurityGroupEgress:
- IpProtocol: -1
CidrIp: 0.0.0.0/0
Tags:
- Key: Name
Value: !Sub '${Environment}-alb-sg'
# 应用负载均衡器
ApplicationLoadBalancer:
Type: AWS::ElasticLoadBalancingV2::LoadBalancer
Properties:
Name: !Sub '${Environment}-alb'
Type: application
Scheme: internet-facing
SecurityGroups:
- !Ref LoadBalancerSecurityGroup
Subnets: !Ref SubnetIds
Tags:
- Key: Environment
Value: !Ref Environment
# HTTP 监听器(重定向到 HTTPS)
HttpListener:
Type: AWS::ElasticLoadBalancingV2::Listener
Properties:
DefaultActions:
- Type: redirect
RedirectConfig:
Protocol: HTTPS
Port: '443'
StatusCode: HTTP_301
LoadBalancerArn: !Ref ApplicationLoadBalancer
Port: 80
Protocol: HTTP
# HTTPS 监听器
HttpsListener:
Type: AWS::ElasticLoadBalancingV2::Listener
Properties:
DefaultActions:
- Type: forward
TargetGroupArn: !Ref WebTargetGroup
LoadBalancerArn: !Ref ApplicationLoadBalancer
Port: 443
Protocol: HTTPS
Certificates:
- CertificateArn: !Sub 'arn:aws:acm:${AWS::Region}:${AWS::AccountId}:certificate/xxxxxxxx'
# Web 服务器的目标组
WebTargetGroup:
Type: AWS::ElasticLoadBalancingV2::TargetGroup
Properties:
Name: !Sub '${Environment}-web-tg'
Port: 8080
Protocol: HTTP
VpcId: !Ref VpcId
TargetType: instance
# 健康检查
HealthCheckEnabled: true
HealthCheckPath: /health
HealthCheckProtocol: HTTP
HealthCheckIntervalSeconds: 30
HealthCheckTimeoutSeconds: 5
HealthyThresholdCount: 2
UnhealthyThresholdCount: 3
# 粘滞性
TargetGroupAttributes:
- Key: deregistration_delay.timeout_seconds
Value: '30'
- Key: stickiness.enabled
Value: 'true'
- Key: stickiness.type
Value: 'lb_cookie'
- Key: stickiness.lb_cookie.duration_seconds
Value: '86400'
# API 的目标组
ApiTargetGroup:
Type: AWS::ElasticLoadBalancingV2::TargetGroup
Properties:
Name: !Sub '${Environment}-api-tg'
Port: 3000
Protocol: HTTP
VpcId: !Ref VpcId
TargetType: instance
HealthCheckPath: /api/health
HealthCheckIntervalSeconds: 15
HealthCheckTimeoutSeconds: 5
HealthyThresholdCount: 2
UnhealthyThresholdCount: 2
# API 路由的监听器规则
ApiListenerRule:
Type: AWS::ElasticLoadBalancingV2::ListenerRule
Properties:
Actions:
- Type: forward
TargetGroupArn: !Ref ApiTargetGroup
Conditions:
- Field: path-pattern
Values: ['/api/*']
ListenerArn: !Ref HttpsListener
Priority: 1
Outputs:
LoadBalancerDNS:
Description: ALB 的 DNS 名称
Value: !GetAtt ApplicationLoadBalancer.DNSName
LoadBalancerArn:
Description: ALB 的 ARN
Value: !Ref ApplicationLoadBalancer
WebTargetGroupArn:
Description: Web 目标组的 ARN
Value: !Ref WebTargetGroup
ApiTargetGroupArn:
Description: API 目标组的 ARN
Value: !Ref ApiTargetGroup
3. 负载均衡器健康检查脚本
#!/bin/bash
# health-check.sh - 监控后端健康
set -euo pipefail
BACKENDS=("10.0.1.10:8080" "10.0.1.11:8080" "10.0.1.12:8080")
HEALTH_ENDPOINT="/health"
TIMEOUT=5
ALERT_EMAIL="ops@myapp.com"
check_backend_health() {
local backend=$1
local host=${backend%:*}
local port=${backend#*:}
if timeout "$TIMEOUT" bash -c "echo >/dev/tcp/$host/$port" 2>/dev/null; then
if curl -sf --max-time "$TIMEOUT" "http://$backend$HEALTH_ENDPOINT" > /dev/null; then
return 0
fi
fi
return 1
}
main() {
local unhealthy_backends=()
for backend in "${BACKENDS[@]}"; do
if ! check_backend_health "$backend"; then
unhealthy_backends+=("$backend")
echo "WARNING: Backend $backend is unhealthy"
else
echo "OK: Backend $backend is healthy"
fi
done
if [ ${#unhealthy_backends[@]} -gt 0 ]; then
local message="Unhealthy backends detected: ${unhealthy_backends[*]}"
echo "$message"
echo "$message" | mail -s "Load Balancer Alert" "$ALERT_EMAIL"
exit 1
fi
}
main "$@"
4. 负载均衡器监控
# prometheus-scrape-config.yaml
scrape_configs:
- job_name: 'haproxy'
static_configs:
- targets: ['localhost:8404']
metrics_path: '/stats;csv'
scrape_interval: 15s
- job_name: 'alb'
cloudwatch_sd_configs:
- region: us-east-1
port: 443
relabel_configs:
- source_labels: [__meta_aws_cloudwatch_namespace]
action: keep
regex: 'AWS/ApplicationELB'
负载均衡算法
- 轮询: 顺序分配
- 最少连接: 最少活跃连接
- IP 哈希: 基于客户端 IP
- 加权: 与服务器容量成比例
- 随机: 随机分配
最佳实践
✅ DO
- 实施健康检查
- 使用连接池
- 需要时启用会话持久性
- 监控负载均衡器指标
- 实施速率限制
- 使用多个可用区
- 启用 SSL/TLS 终止
- 实施优雅的连接排空
❌ DON’T
- 允许单点故障
- 跳过健康检查配置
- 混合 HTTP 和 HTTPS 而不重定向
- 忽略后端服务器限制
- 无监控超额配置
- 缓存敏感响应
- 使用默认安全组
- 忽视备份负载均衡器