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

如何在香港服务器的 Ubuntu 中部署跨境电商,用 HAProxy 解决多地区买家访问延迟

发布人:Minchunlin 发布时间:2025-09-08 08:29 阅读量:1079


周五晚 8 点开团,周六凌晨爆单,活动开始 90 分钟,客服在群里喊:「新加坡、东京、法兰克福的买家下单慢、支付页开得非常慢。」我看监控:TTFB(首字节)从平时的 120ms 飙到了 800ms~1.2s,活跃连接峰值翻倍,应用层 CPU还不高——问题不在应用,而在网络往返与入口层转发。

我们当时的拓扑很简单:香港单点入口(Nginx)+ 两台应用 + 一个数据库主库。境外用户全部打到香港,靠 CDN 只加速了静态资源,动态请求还是跨洋回源。那夜我果断拍板:把入口改成 HAProxy 高可用集群、做地理就近路由、把跨地域的应用副本拉起来,让动态流量也就近落地,仅把写操作回香港主库。三天迭代,两夜通宵,周日复盘时大家一致点头:这才是跨境电商应该有的网络骨架。

下面,把全过程复盘出来。

目标与范围

目标:在香港服务器(Ubuntu 22.04 LTS)上,部署 HAProxy L7 负载均衡 + 高可用,配合 地理就近路由,把多地区买家的动态请求延迟打下来。

典型买家区域(真实流量占比高):

  • 中国大陆华南/华东(深圳、广州、上海)
  • 东南亚(新加坡、雅加达、曼谷)
  • 日本/韩国(东京/大阪、首尔)
  • 大洋洲(悉尼)
  • 中东(迪拜)
  • 欧洲(法兰克福、伦敦)
  • 北美西海岸(洛杉矶、旧金山)

不改变:应用框架与业务逻辑最小侵入;数据库仍以香港为单主写入,海外多地只读副本承载读多写少的页面(商品/搜索/详情)。

硬件与网络选型(落地可执行)

入口层(香港 HAProxy 集群)

角色 CPU 内存 存储 网卡 备注
HKG-LB-01/02 Intel Xeon E-2388G(8C/16T)或 AMD 7371 同级 32–64GB NVMe 480–960GB(RAID1) 2×10GbE(Bond) HAProxy 2.8+,Keepalived VRRP,syslog 远程落盘

理由:SSL 终止 + HTTP/2 压缩 + L7 ACL/Map 匹配对 CPU 单核性能友好;双 10G 做 LACP,避免队首阻塞。

应用层(多地域)

地区 规格建议 用途
香港(主) 4–6 台,8C/16G 起 动态主集群,写请求归集
新加坡 2–4 台,8C/16G 起 东南亚就近
东京 2–3 台,8C/16G 起 日/韩就近
洛杉矶 2–3 台,8C/16G 起 美西就近
法兰克福 2–3 台,8C/16G 起 欧陆就近

海外副本通过 WireGuard 组网回香港专线网段,仅同步必要端口(应用、只读 DB、缓存)。

数据与缓存

  • MySQL 8:香港 单主,各地域 异步只读副本(延迟 50–300ms 可接受)。
  • Redis:本地读写,海外使用只读从库或本地缓存层(淘汰策略 allkeys-lru)。

基线数据(优化前)

采样方法:curl -w + mtr + wrk 取 95 分位。单位:ms

区域 RTT→香港 TTFB(动态页)
深圳/广州 20–35 150–220
新加坡 30–45 200–280
东京 35–55 220–320
悉尼 110–140 450–600
迪拜 160–190 600–800
法兰克福 180–220 700–900
洛杉矶 140–170 650–850

瓶颈非常直观:跨洋 RTT 直接把 TTFB 顶上去了,CDN 只救静态,动态没法躲。

参考拓扑(文字版)

[Client(全球)]
        |
     GeoDNS / CDN(可选:仅做就近/健康路由+静态加速)
        |
  ┌───────────────香港───────────────┐
  │         VIP (VRRP)              │
  │   [HAProxy-LB-01]  [LB-02]      │
  │         |            |           │
  │        Bond/LACP 与上联          │
  │         |            |           │
  │   ┌────────应用(HK 主)────────┐ │
  │   |   APP1..APPn  + Redis +     | │
  │   |   MySQL 主库                | │
  │   └─────────────────────────────┘ │
  └───────────────────────────────────┘
         /     |       |       \
     WireGuard 专网到(SG/JP/US/EU 各地只读集群)

系统准备(Ubuntu 22.04 LTS)

# 基础
sudo apt update && sudo apt -y upgrade
sudo timedatectl set-timezone Asia/Hong_Kong
sudo apt -y install haproxy rsyslog net-tools socat jq curl gnupg2 \
  keepalived gcc make unzip mtr-tiny htop iftop netcat-openbsd

# 文件句柄与内核参数
echo '* soft nofile 1048576
* hard nofile 1048576
haproxy soft nofile 1048576
haproxy hard nofile 1048576' | sudo tee /etc/security/limits.d/haproxy.conf

cat <<'EOF' | sudo tee /etc/sysctl.d/99-lb-tuning.conf
net.core.somaxconn = 65535
net.core.netdev_max_backlog = 250000
net.ipv4.ip_local_port_range = 1024 65000
net.ipv4.tcp_fin_timeout = 30
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_max_syn_backlog = 262144
net.ipv4.tcp_mtu_probing = 1
net.ipv4.tcp_syncookies = 1
fs.file-max = 2097152
EOF

sudo sysctl --system

说明:tcp_tw_reuse 在新内核仍然安全;somaxconn 与 netdev_max_backlog 避免高并发丢包;端口范围放宽给短连接。

HAProxy:版本、线程与日志

Ubuntu 22.04 自带的 HAProxy 常为 2.4/2.6,建议 2.8+(LTS,HTTP/2 稳定,性能优化更好)。如果仓库版本较老,可用官方 repo 或 PPA;这里用系统仓库演示。

日志(强烈建议开远程)

/etc/rsyslog.d/49-haproxy.conf

module(load="imudp")
input(type="imudp" port="514")
$template HaproxyFormat,"%timestamp% %syslogtag%%msg%\n"
if ($programname == 'haproxy') then {
  action(type="omfile" file="/var/log/haproxy.log" template="HaproxyFormat")
  stop
}

HAProxy 主配置(可直接落地)

/etc/haproxy/haproxy.cfg(关键片段,包含:全局、前端、Geo 路由、后端、健康检查、缓存与压缩)

global
    log 127.0.0.1:514 local0
    chroot /var/lib/haproxy
    stats socket /run/haproxy/admin.sock mode 660 level admin
    stats timeout 30s
    user haproxy
    group haproxy
    daemon
    nbthread 8
    cpu-map auto:1/1-8 0-7
    maxconn 200000
    tune.ssl.default-dh-param 2048
    ssl-default-bind-options no-sslv3 no-tls-tickets
    ssl-default-bind-ciphers ECDHE+AESGCM:CHACHA20+POLY1305

defaults
    log     global
    mode    http
    option  httplog
    option  http-keep-alive
    option  forwardfor header X-Forwarded-For
    timeout client  60s
    timeout server  60s
    timeout connect 5s
    timeout http-request 10s
    timeout http-keep-alive 20s
    retries 3

# —— 管理面板(内网)——
listen stats
    bind 0.0.0.0:8404
    stats enable
    stats uri /haproxy?stats
    stats auth admin:StrongPass!

# —— 前端:443 终止 TLS,支持 H2 —— 
frontend fe_https
    bind :443 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 add-header X-Frame-Options DENY
    http-response add-header X-Content-Type-Options nosniff
    http-response add-header Referrer-Policy strict-origin-when-cross-origin

    # 如果前置 CDN/GeoDNS 注入了国家头,优先使用(比如 Cloudflare: CF-IPCountry)
    http-request set-var(txn.cc) req.fhdr(CF-IPCountry),lower if { req.fhdr(CF-IPCountry) -m found }

    # 若无,则用 Map 文件基于源 IP 网段做粗粒度归属(示例)
    # 约定:map 返回的值是区域标签(ap-sg, ap-jp, us-west, eu-de 等)
    http-request set-var(txn.region) map_ip(/etc/haproxy/maps/ip2region.map) if !{ var(txn.cc) -m found }

    # 有国家则再映射到区域
    http-request set-var(txn.region) map(/etc/haproxy/maps/cc2region.map) if { var(txn.cc) -m found }

    # A/B 或灰度:高价值国家直上香港主集群
    acl vip_country var(txn.cc) -i cn hk mo tw
    use_backend bk_hk if vip_country

    # 常规就近路由:根据 region 选择后端
    use_backend bk_sg if { var(txn.region) -i ap-sg }
    use_backend bk_jp if { var(txn.region) -i ap-jp }
    use_backend bk_usw if { var(txn.region) -i us-west }
    use_backend bk_eu if { var(txn.region) -i eu-de }
    default_backend bk_hk

# —— 后端:香港主集群 —— 
backend bk_hk
    balance roundrobin
    option httpchk GET /healthz
    http-check expect rstring OK
    server app1 10.10.0.11:8080 check inter 2s fall 3 rise 2
    server app2 10.10.0.12:8080 check inter 2s fall 3 rise 2
    server app3 10.10.0.13:8080 check backup

# —— 后端:新加坡(就近动态 + 读多写少页面)——
backend bk_sg
    balance leastconn
    option httpchk GET /healthz
    http-check expect status 200
    server sg1 10.20.0.11:8080 check
    server sg2 10.20.0.12:8080 check

# —— 后端:东京 —— 
backend bk_jp
    balance leastconn
    option httpchk GET /healthz
    server jp1 10.30.0.11:8080 check
    server jp2 10.30.0.12:8080 check

# —— 后端:美西(洛杉矶)——
backend bk_usw
    balance leastconn
    option httpchk GET /healthz
    server us1 10.40.0.11:8080 check
    server us2 10.40.0.12:8080 check

# —— 后端:欧洲(法兰克福)——
backend bk_eu
    balance leastconn
    option httpchk GET /healthz
    server eu1 10.50.0.11:8080 check
    server eu2 10.50.0.12:8080 check

# —— 简易缓存(对价格不敏感的 GET,可以视业务启用)——
cache imgcache
    total-max-size 512
    max-object-size 1048576

backend static_cache
    http-request cache-use imgcache
    http-response cache-store imgcache

Map 文件示例

/etc/haproxy/maps/cc2region.map

sg ap-sg
id ap-sg
th ap-sg
jp ap-jp
kr ap-jp
us ap-us
ca ap-us
de eu-de
fr eu-de
gb eu-de
ae me-ae

/etc/haproxy/maps/ip2region.map(片段示例,生产请用脚本生成 CIDR)

103.1.0.0/16 ap-sg
106.0.0.0/8   ap-jp
34.80.0.0/12  ap-sg
13.52.0.0/16  us-west
3.120.0.0/13  eu-de

实践要点

  • 优先利用 CDN/GeoDNS 注入的国家头,准确度高;
  • Map 文件只做兜底,维护成本高时可转 Lua + MaxMind;
  • 核心国家(CN/HK/MO/TW)走香港主集群,支付/风控更稳。

高可用(Keepalived + VRRP)

/etc/keepalived/keepalived.conf(两台 LB 配置略有不同,以下为 MASTER)

vrrp_instance VI_1 {
    state MASTER
    interface bond0
    virtual_router_id 51
    priority 150
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass VeryStrong!
    }
    virtual_ipaddress {
        203.0.113.10/24 dev bond0
    }
    track_script {
        chk_haproxy
    }
}

vrrp_script chk_haproxy {
    script "pidof haproxy"
    interval 2
    weight 10
    fall 3
    rise 2
}

切换验证:systemctl stop haproxy 看 VIP 是否漂移;ip a 与 dig @VIP 验证。

专网互联(WireGuard)

海外集群与香港走加密专网,只允许必要端口(应用/DB 只读/缓存)。

/etc/wireguard/wg0.conf(香港端)

[Interface]
Address = 10.254.0.1/24
PrivateKey = <HK-PRIVATE>
ListenPort = 51820

[Peer]
PublicKey = <SG-PUBLIC>
AllowedIPs = 10.254.1.0/24,10.20.0.0/16
Endpoint = sg-edge.example.com:51820
PersistentKeepalive = 25

路由策略:香港到各 Region 的应用网段通过对应 WG 隧道;应用后端上报健康与指标走专网。

数据层策略(最低侵入)

  • MySQL:香港主(read_only=OFF),各地只读(read_only=ON),业务层读写分离(读优先本地,只要能容忍秒级延迟;写回香港)。支付与库存这类强一致写操作始终回香港。
  • Redis:会话与购物车走香港(或用地域会话粘性 + 回源),只读查询缓存可以在本地副本命中。
  • 一致性声明:用户侧看得到的价格、库存,请在页面/接口层明确强一致字段来源(香港主)。

压测与上线

烟囱式压测(逐段验证)

  • LB 自测:h2load/wrk 打 LB 回环后端(dummy),确认 TLS/QPS 与 CPU 占比。
  • 专线链路:iperf3 跨 WG 测吞吐与 RTT 波动。
  • 应用实测:海外节点对本地后端压测;再通过香港 LB 转发到各地后端,确认 95/99 分位。
  • 灰度:GeoDNS/流量开关按地区 10%→30%→50% 放量。

优化后数据(重点看 TTFB)

区域 优化前 TTFB 优化后 TTFB 改善
深圳/广州 150–220 110–160 25–30%
新加坡 200–280 120–180 35–40%
东京 220–320 130–190 35–40%
悉尼 450–600 210–300 50–55%
迪拜 600–800 320–420 45–50%
法兰克福 700–900 330–450 50%+
洛杉矶 650–850 300–420 45–55%

解释:静态仍由 CDN 命中;动态由就近应用副本响应,写少回香港;HAProxy 在香港做入口与全局路由,同时承担本地主集群负载均衡。

运营期的关键配置与监控

1) HAProxy 运行参数

  • nbthread = CPU 物理核数;cpu-map auto 绑定,尽量减少迁核。
  • maxconn 结合内核与 ulimit,不要随意拉满;稳态留出 20% 余量。
  • 日志打开 tc, tr, tw, ttt 字段,便于定位是后端慢还是排队慢。

2) HTTP/2 与压缩

  • alpn h2,http/1.1;
  • 仅对 text/ 类型启用 gzip,慎对 JSON(权衡延迟与 CPU)。
  • 可在后端开 Server Push(如需要,或直接上 HTTP/2 多路复用即可)。

3) 健康检查

  • option httpchk + /healthz(自检依赖)
  • 严格:http-check expect status 200/rstring OK
  • 延迟抖动时,rise/fall 增大,避免抖动引发大面积摘除。

4) 观测与告警

  • stats 面板 + Prometheus exporter(如 haproxy_exporter)

关键告警:

  • hrsp_5xx、qcur/qmax 排队过长
  • svr_abrt 后端重置
  • 各后端 rtime 抬升(跨域链路问题)

常见坑与现场解法

证书链不完整导致海外终端握手慢

修复:PEM 里 服务端证书 + 中间证书链完整拼接;开启 OCSP Stapling(若前置 CDN,也可由 CDN 处理)。

HTTP/2 触发服务端队首阻塞

现象:某些浏览器下单时突然抖动。

处理:调大 timeout http-keep-alive,后端接口做并发限制;必要时对关键接口回退到 h1(ACL)。

Map 文件维护成本高

方案:改用 CDN 注入国家头 或 Lua + MaxMind DB。

Lua 片段(仅示例):

# global 段
lua-load /etc/haproxy/lua/geoip.lua

# fe_https 中
http-request set-var(txn.cc) lua.geoip_country() if !{ var(txn.cc) -m found }

后端读写分离不彻底

现象:海外只读库被误写,主从延迟飙升。

处理:业务 SDK 层封装强制写路由;DB 层加 read_only 与写入审计。

Keepalived 抢占震荡

处理:关闭 nopreempt 或调优优先级与 advert_int;加入 track_script 只在 HAProxy 健康时抢占。

SYN 洪泛或突发高并发

处理:tcp_syncookies=1,LB 前加 ACL/速率限制;必要时用 SYNPROXY(iptables)护前门。

跨洋链路偶发丢包

处理:应用层重试与超时策略放宽;WireGuard PersistentKeepalive=25;与上游谈 CN2/GIA/直连「贵但值」。

回滚与变更 SOP(真的用得到)

预检:
haproxy -c -f /etc/haproxy/haproxy.cfg

无损热加载:
systemctl reload haproxy(确认 hard-stop-after 合理,旧进程优雅退出)

  • 灰度:GeoDNS 权重从 10%→30%→50%,每档观察 10–15 分钟。
  • 回滚:一键把 GeoDNS 指回香港主集群;HAProxy use_backend 默认回 HK;DB 与缓存不需回滚。
  • 变更记录:保存 stats 面板截图、关键时段日志,复盘沉淀。

进阶建议(可择机上)

  • HTTP/3(QUIC):移动端提升明显,但要评估 HAProxy 版本与生态成熟度;通常先由 CDN 承担更稳。
  • Anycast + 多地域 LB:大盘期望极致就近,可把 HAProxy 布在 SG/JP/US/EU,GeoDNS/Anycast 入口;香港只做数据写主。
  • 请求级熔断与重路由:HAProxy 的 http-retry + on-error 回落到香港,保证交易闭环。

给你一份可复制的上线清单(摘)

  •  系统升级、时区、本地化
  •  limits 与 sysctl 调优
  •  HAProxy 2.8+ 安装、日志接入
  •  证书链与 HSTS/安全头
  •  fe_https/后端/健康检查/缓存
  •  Map 文件或 CDN 国家头
  •  Keepalived VRRP 测试漂移
  •  WireGuard 互联与路由策略
  •  只读库/缓存策略与读写分离
  •  压测(分段→全链路)与灰度
  •  监控&告警、回滚预案

那周日,我拎着咖啡沿着机房走廊慢慢地走了一圈。风扇的白噪音里,监视器上的曲线终于乖乖地贴着地面。新加坡买家的 TTFB 稳在 150ms 左右,洛杉矶 350ms,法兰克福 380ms,客服群安静得像没人。
这套架构说不上花哨,但它尊重物理距离,尊重跨境电商的业务特性。把「入口的聪明」安在香港、把「响应的就近」铺到各大区,再把「写入的一致」守在主库。
如果你正被多地区延迟折腾,不妨按上面的步骤先把入口与路由做扎实了:HAProxy + Geo + 只读副本,一步一步来。上线那刻,看到 95 分位一路走低的快感,你会懂的。

目录结构
全文