如何在香港服务器的 Ubuntu 上部署、设置与优化负载均衡,扛住双11/黑五的流量洪峰

凌晨 02:10,我站在香港荃湾机房 5 层的冷通道尽头,看着两台新换上的 LB 服务器状态灯一明一灭。运营刚在群里发来“红包雨”预热战报,UV 峰值预测临时上调了 30%。这意味着我们今天要从“稳稳扛住”升级到“有余量地扛住”。
我深吸一口气,打开传呼机上的一键回滚脚本,再次核对 VIP 漂移、健康检查、队列水位告警。过去几年,每次大促前夜都是这样:把看似枯燥的参数、无数次演练和一堆“坑”,揉成能救命的手感。
1. 场景与目标
场景:香港自建机房,面对国内外用户混合流量(CN & Global),高并发秒杀与大促页静态资源占比高,支付链路对延迟敏感。
目标:
- 峰值 HTTP(S) 连接速率 ≥ 25 万 cps(connections per second)
- 峰值 应用层 QPS ≥ 80 万 QPS(有 CDN,LB 仍需兜底与回源)
- 零单点:LB 层支持故障 60 秒内自动恢复;应用层滚动升级无感
- 观测与回滚:10 分钟内定位瓶颈,1 键回退配置与 VIP 漂移
2. 架构总览(简单到能复盘,复杂到能落地)
[ 用户/客户端 ]
|
(CDN/高防)
|
┌───────────┐ VRRP 漂移 VIP: 203.XX.XX.10
│ LB 层 │<=====> Keepalived + LVS(IPVS) [L4]
│ (LB-A/B) │ HAProxy [L7/TLS终止/限流/灰度]
└───────────┘
|
┌───────────────────────────┐
│ 应用池(ASG/裸机/K8s Node) │ ↔ Redis/MQ/DB (独立 HA)
└───────────────────────────┘
|
[ 存储/缓存层, 观测与日志 ]
策略:
- L4 用 LVS/IPVS(DR 模式优先,必要时 NAT),追求极致吞吐与低开销。
- L7 用 HAProxy 做 TLS 终止、路由、限流、熔断、灰度发布。
- VIP 高可用 由 Keepalived(VRRP)承载,一主一备(可多备)。
- 后端自动收敛:用 HAProxy Runtime API + 注册中心(可选 Consul)动态上下线。
- 监控:Prometheus + Grafana(haproxy_exporter、node_exporter、keepalived_exporter、blackbox_exporter)。
3. 机器与网络选型(实打实的参数)
3.1 LB 规格(2 台起步,支持水平扩展)
| 角色 | 机型/CPU | 内存 | 系统盘 | 网卡 | OS | 备注 |
|---|---|---|---|---|---|---|
| LB-A/B | Intel Xeon Gold 6338N(或 AMD EPYC 7313P) | 128GB | NVMe 960GB | 2×10GbE Intel X710(Bond LACP) | Ubuntu 22.04 LTS | BIOS 开启 NUMA、SR-IOV 可选 |
网络:
- 对外:BGP 混线/国际专线(HK 出口),MTU 1500。
- 对内:与应用池同 IDC 二层/三层,后端可用 9000 MTU(Jumbo Frame),但需端到端一致。
- VIP:对外弹性 IP(203.),对内 10. 段回源。
- CDN 前置:尽量让静态流量走 CDN,但 LB 仍需承受回源与动态请求峰值。
4. 容量预估(先算明白,再上机器)
4.1 粗略估算方法
- 峰值 QPS ≈ 日均 QPS × 峰值倍率(双11/黑五常见 10~30 倍)
- 连接速率(cps)与 QPS 关系:若复用良好(HTTP/2/keep-alive),cps 会远小于 QPS;若秒杀与短连接较多,cps 急升。
- 单 LB L7(HAProxy)在 2×10GbE、调优后 20~30 万 QPS 较稳妥;L4(IPVS)可上 百万级 QPS。
4.2 示例计算(保守)
| 指标 | 规划值 |
|---|---|
| 峰值 QPS(动态) | 80 万 |
| 峰值 cps | 25 万 |
| LB 数量 | 2(主备)+ 1 颗冷备(同配置) |
| 后端实例 | 100 台(8C/16G 起,按业务拓扑分组) |
| 余量 | ≥ 30% |
5. Ubuntu 基线与内核调优
5.1 系统准备
sudo apt update && sudo apt -y upgrade
sudo apt -y install htop iftop net-tools ipvsadm keepalived haproxy nftables ethtool \
conntrack iperf3 wrk jq chrony prometheus-node-exporter
sudo systemctl enable --now chrony node-exporter
5.2 Bond + Netplan(LACP)
/etc/netplan/01-bonding.yaml
network:
version: 2
ethernets:
eno1: {}
eno2: {}
bonds:
bond0:
interfaces: [eno1, eno2]
parameters:
mode: 802.3ad
mii-monitor-interval: 100
transmit-hash-policy: layer3+4
dhcp4: no
addresses: [203.XX.XX.12/24]
gateway4: 203.XX.XX.1
nameservers:
addresses: [8.8.8.8, 1.1.1.1]
应用:
sudo netplan apply
5.3 sysctl(连接跟踪、队列、BBR)
/etc/sysctl.d/99-lb.conf
net.core.somaxconn = 8192
net.core.netdev_max_backlog = 250000
net.core.rmem_max = 134217728
net.core.wmem_max = 134217728
net.ipv4.tcp_max_syn_backlog = 262144
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_timestamps = 0
net.ipv4.tcp_sack = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.ip_local_port_range = 10240 65535
net.ipv4.tcp_fin_timeout = 10
net.ipv4.tcp_fastopen = 3
net.ipv4.tcp_congestion_control = bbr
net.ipv4.tcp_mtu_probing = 1
net.nf_conntrack_max = 2621440
net.netfilter.nf_conntrack_buckets = 524288
net.netfilter.nf_conntrack_tcp_timeout_established = 1200
net.netfilter.nf_conntrack_tcp_timeout_time_wait = 30
net.netfilter.nf_conntrack_tcp_timeout_close_wait = 30
应用:
sudo sysctl --system
5.4 NIC Offload(遇到奇怪丢包/延迟突刺时再用)
sudo ethtool -K bond0 gro on gso on tso on
# 如遇 TLS/小包延迟异常,可尝试调为 off 再测
6. L4:LVS/IPVS(DR 模式)+ Keepalived 高可用
6.1 选择 DR 的原因
NAT:简单但 LB 成性能瓶颈(回包也走 LB)。
DR:LB 只负责入流量改 MAC,将包直接送给后端,回包不经过 LB → 吞吐高、延迟低。
6.2 Keepalived(LB-A 为 MASTER,LB-B 为 BACKUP)
/etc/keepalived/keepalived.conf(LB-A)
vrrp_script chk_haproxy {
script "pidof haproxy"
interval 2
weight 2
}
vrrp_instance VI_1 {
state MASTER
interface bond0
virtual_router_id 51
priority 150
advert_int 1
authentication {
auth_type PASS
auth_pass S3cretXX
}
virtual_ipaddress {
203.XX.XX.10/24 dev bond0 label bond0:1
}
track_script {
chk_haproxy
}
garp_master_delay 1
}
LB-B 改为 state BACKUP、priority 100。
启用:
sudo systemctl enable --now keepalived
6.3 IPVS 规则(L4 直转发到 L7)
我们让 IPVS 把 443/80 的流量打到本机 HAProxy(或旁路 L7 集群)。
# 确保内核模块
sudo modprobe ip_vs ip_vs_rr ip_vs_sh
# 添加虚拟服务
sudo ipvsadm -A -t 203.XX.XX.10:443 -s rr
sudo ipvsadm -a -t 203.XX.XX.10:443 -r 127.0.0.1:8443 -g
sudo ipvsadm -A -t 203.XX.XX.10:80 -s rr
sudo ipvsadm -a -t 203.XX.XX.10:80 -r 127.0.0.1:8080 -g
ipvsadm -Ln
这里用 DR(-g) 语义统一;由于 real 指向本机 127.0.0.1,回包仍走协议栈,性能损失极小且简化 L7 集群。若 L7 单独集群,real 即为 L7 池机器 IP。
7. L7:HAProxy(TLS 终止、限流、灰度、健康检查)
7.1 关键运行参数
- nbthread = 物理核心数(或略小),cpu-map 进行亲和
- tune.bufsize(默认 16384,按业务调),maxconn(结合内存)
- http-reuse safe,启用 HTTP/2;必要时启 H3(需新版与内核/QUIC 支持)
- 后端 balance leastconn 或 random,健康检查 httpchk 带 SNI
7.2 配置示例(/etc/haproxy/haproxy.cfg)
global
log /dev/log local0
maxconn 500000
nbthread 32
cpu-map auto:1/1-32 0-31
tune.bufsize 32768
tune.ssl.default-dh-param 2048
stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
ssl-default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384
ssl-default-bind-options no-sslv3 no-tlsv10 no-tlsv11
ssl-server-verify none
defaults
log global
mode http
option httplog
option dontlognull
option http-keep-alive
timeout connect 3s
timeout client 30s
timeout server 30s
timeout http-request 5s
retries 2
maxconn 400000
frontend fe_https
bind 0.0.0.0:8443 ssl crt /etc/haproxy/certs/site.pem alpn h2,http/1.1
http-response set-header Strict-Transport-Security max-age=31536000;\ includeSubDomains;\ preload
http-response set-header X-Frame-Options DENY
http-response set-header X-Content-Type-Options nosniff
http-request set-header X-Forwarded-Proto https
http-request set-header X-Client-IP %[src]
acl is_health path_beg /healthz
http-request allow if is_health
# 基于路径/域名的路由示例
acl is_api path_beg /api
use_backend be_api if is_api
default_backend be_web
frontend fe_http
bind 0.0.0.0:8080
redirect scheme https code 301 if !{ ssl_fc }
backend be_web
balance leastconn
http-reuse safe
option httpchk GET /healthz HTTP/1.1\r\nHost:\ www.example.com
server web01 10.0.10.21:80 check fall 3 rise 2
server web02 10.0.10.22:80 check
# 灰度发布
acl canary hdr_beg(User-Agent) -i Canary
use-server web02 if canary
backend be_api
balance random
option httpchk GET /ping HTTP/1.1\r\nHost:\ api.example.com
http-request set-header X-Req-Id %[unique-id]
stick-table type ip size 1m expire 10m store http_req_rate(10s)
http-request deny if { sc_http_req_rate(0) gt 100 } # 每 IP 100 rps
server api01 10.0.20.31:8080 check
server api02 10.0.20.32:8080 check
证书:生产常用自动化(例:ACME/私有 CA)。测试可先:
sudo apt -y install certbot
sudo certbot certonly --standalone -d www.example.com
# 将 fullchain.pem 与 privkey.pem 合并为 site.pem
cat fullchain.pem privkey.pem | sudo tee /etc/haproxy/certs/site.pem
sudo systemctl reload haproxy
7.3 运行时动态上下线(避免重启)
echo "disable server be_web/web01" | sudo socat stdio /run/haproxy/admin.sock
echo "set server be_web/web01 addr 10.0.10.23 port 80 check" | sudo socat stdio /run/haproxy/admin.sock
echo "enable server be_web/web01" | sudo socat stdio /run/haproxy/admin.sock
8. 安全与防护(nftables、SYN 防护、限速)
8.1 基础防护(nftables)
/etc/nftables.conf
flush ruleset
table inet filter {
chain input {
type filter hook input priority 0;
ct state established,related accept
iif lo accept
tcp dport { 22 } ct state new limit rate 30/minute accept
tcp dport { 80,443,8080,8443 } accept
ip protocol icmp accept
reject with icmpx type admin-prohibited
}
}
sudo systemctl enable --now nftables
8.2 SYN 抗压(syncookies + synproxy)
对于可疑来源在前置(高防/CDN)后一般足够;若直连开启:
# 仅在必要时对直连入口做 synproxy,或在边界设备实现
9. 后端(Real Server)在 DR 模式下的 ARP 抑制(关键坑点)
DR 模式需要 RS 不响应 VIP 的 ARP,否则会把 VIP 抢走或路由紊乱。
在每台后端加:
echo 1 | sudo tee /proc/sys/net/ipv4/conf/all/arp_ignore
echo 2 | sudo tee /proc/sys/net/ipv4/conf/all/arp_announce
或写入 /etc/sysctl.d/90-arp.conf 永久生效:
net.ipv4.conf.all.arp_ignore=1
net.ipv4.conf.all.arp_announce=2
10. 观测:别猜,用数据说话
Exporter:haproxy_exporter、node_exporter、keepalived_exporter、blackbox_exporter
关键指标:
- LB:连接速率、前端/后端队列、请求耗时分位(P50/P90/P99)、重试/5xx
- 系统:CPU SoftIRQ、Run Queue、NIC 丢包、SYN backlog、conntrack 使用率
- 业务:下单成功率、支付成功率、库存命中率
- SLO(示例):静态页 P99 < 120ms、下单接口 P99 < 300ms、支付回调 P99 < 500ms;5xx < 0.1%。
11. 压测与演练(把事故留在凌晨)
11.1 工具与场景
- wrk:HTTP/1.1 压测
- h2load:HTTP/2 并发链接
- iperf3:网络带宽/抖动
场景:
1)静态页 70%,动态 30%
2)短连接突刺(模拟秒杀开场 15 秒)
3)长连接保活(支付、IM 通道)
11.2 命令模板
# 静态页
wrk -t64 -c40000 -d60s --latency https://www.example.com/
# 动态接口
wrk -t64 -c20000 -d60s -s post.lua https://api.example.com/order
# post.lua 根据业务定制
# HTTP/2 连接 1 万并发
h2load -n 1000000 -c 10000 -m 100 https://www.example.com/
# 带宽
iperf3 -c <server-ip> -P 8 -t 60
11.3 样例结果(节选)
| 场景 | QPS | P99(ms) | cps | LB CPU(%) | 备注 |
|---|---|---|---|---|---|
| 静态 H2 | 420,000 | 85 | 9,000 | 62 | CDN 命中不回源时更轻 |
| 动态 H1 | 310,000 | 140 | 18,000 | 68 | 限流触发阈值 5% |
| 短突刺 15s | 峰 520,000 | 190 | 峰 240,000 | 78 | SYN backlog 8k→16k |
这些数字仅为示例,实际以贵司业务为准。要点是保留足够余量(>30%)。
12. 线上变更与回滚策略
- 变更窗口:凌晨 01:00–03:00(非支付高峰)
- 灰度顺序:后端 → L7 → L4 → VIP 切换(永远从里向外)
回滚:
- HAProxy:git revert && systemctl reload haproxy
- LB 漂移:systemctl stop keepalived@MASTER 触发 VIP 切换
- 一键脚本:恢复上一版 /etc/haproxy/haproxy.cfg 与 /etc/keepalived/keepalived.conf
13. 常见“坑”与一线解法
MTU 不一致:前端 1500、后端 9000,路径中某交换机不支持 → 间歇性超时
解:要么全链路 1500,要么确认端到端 Jumbo OK;在 LB 上开 tcp_mtu_probing=1 仅止血。
DR 模式 ARP 抢答:某台 RS 忘了 arp_ignore/announce → VIP 飘忽
解:Ansible/Salstack 合规基线;健康检查一旦异常立刻报警。
H2→H1 转换引发 HOL(下游不支持 H2)
解:HAProxy http-reuse safe、分离静态/动态后端;必要时让下游也启 H2。
TLS CPU 飙升(证书链/椭圆曲线配置不当)
解:检查 cipher 套件与 ALPN;启用 0-RTT 需权衡幂等安全;多核 pin 线程。
conntrack 爆表:短连接洪峰 + NAT 节点
解:上 DR、增大 nf_conntrack_max、优化 keep-alive、静态资源充分 CDN。
PMTU 黑洞(海外用户)
解:黑盒探测 + 降 MTU 到 1400 或启用 tcp_mtu_probing;边界设备做 MSS Clamping。
健康检查误伤(SNI/Host 头不对)
解:httpchk 明确 Host;后端启独立 /healthz 路由不依赖业务逻辑。
日志 IO 瓶颈
解:Haproxy httplog 走 rsyslog 异步;本地落盘只保关键字段,完整日志进 Kafka/对象存储。
14. 自动化与弹性(可选但很香)
注册中心:Consul/Etcd,后端实例注册;consul-template 更新 HAProxy server-template。
伸缩钩子:扩容后自动 enable server,缩容前先 drain,确保连接优雅退出。
发布:Blue/Green 或 Canary(示例用 UA 头控流量);结合特征开关平台。
15. 运维清单(上线前最后一遍)
- VRRP 触发演练(拔网线/停 keepalived)
- 单点故障注入(停一台 HAProxy/下游)
- 链路 MTU 验证(tracepath/ping -M do)
- 压测重放(峰值 ×1.2)
- 告警阈值:队列、5xx、连接速率、CPU SoftIRQ、conntrack、SYN backlog
- 回滚脚本、上版/下版配置包可用
- 证书与密钥管理(权限、过期)
- 业务灰度策略已下发,风控规则联动
16. 真实落地的小结表
| 分类 | 关键项 | 我们的落地 |
|---|---|---|
| L4 | Keepalived + IPVS(DR) | VIP 漂移 < 3s,DR 模式回包不走 LB |
| L7 | HAProxy | TLS 终止、H2、限流、灰度、健康检查 |
| 内核 | TCP/conntrack/队列 | sysctl 固化基线,BBR,上限充足 |
| 网络 | Bond LACP + X710 | 2×10GbE,hash 使用 layer3+4 |
| 监控 | Prom + Grafana | 全链路观测,可回放压测轨迹 |
| 安全 | nftables | 基础 ACL + 速率限制 |
| 变更 | 灰度 & 回滚 | 从里到外,1 键回退 |
| 演练 | 故障注入 | VRRP/后端/带宽多场景必跑 |
17. 尾声:凌晨 03:14 的绿灯
03:14,Grafana 的 P99 折线在 150ms 附近平稳地荡着,队列水位始终没过 20%。我把对讲机音量调低,听到同事在另一头笑着说“红包雨继续”。
这些年的经验告诉我,负载均衡不是某个“神器”,而是一套稳、简、可回滚的工程习惯:少耍花活,多做演练;少靠猜,多看数据;少做极限,留足余量。
当大促的流量洪峰退去,机房还是那样的冷,灯还是一明一灭。但我们知道——这次,又稳住了。