上一篇 下一篇 分享链接 返回 返回顶部

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

发布人:Minchunlin 发布时间:2025-09-09 09:00 阅读量:690


凌晨 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%。我把对讲机音量调低,听到同事在另一头笑着说“红包雨继续”。
这些年的经验告诉我,负载均衡不是某个“神器”,而是一套稳、简、可回滚的工程习惯:少耍花活,多做演练;少靠猜,多看数据;少做极限,留足余量。
当大促的流量洪峰退去,机房还是那样的冷,灯还是一明一灭。但我们知道——这次,又稳住了。

目录结构
全文