
那天是周六凌晨 1:40,我香港九龙湾机房盯着 Smokeping 上华北某省的曲线:延迟像锯齿,丢包时不时 2% 抬头。隔着大洋,手游玩家的登录峰值刚好压在跨境链路的抖动点上。“得上多线 BGP,且要能在波动时自动把流量拨到好走的那条。” 于是,我在 42U 柜门上挂好“维护中”,把一台预装好的路由主机推上托盘,开始了这次“把香港机房变成四线加速枢纽”的通宵活儿。下面是我当晚到上线后一周的完整实操记录——我怎么选硬件、怎么接线、怎么跟 CN2/CMIN2/CU/PCCW 建 BGP、怎么做按目的地(中国大陆)定向择路、怎么监控、怎么抗抖动和踩坑复盘。
这篇写给新手也写给老手,我会把每个步骤拆开、每处坑点标出,配置与脚本都能直接拿去用。
目标与思路(一句话版)
目标:香港机房对外同时接 CN2(CT GIA/AS4809)、CMIN2(CMI/AS58453)、CU(AS4837/或 9929)、PCCW(AS3491) 四家国际/跨境线路,通过 eBGP 多宿 + 按目的地(中国大陆 IP 集)策略路由 + 健康探测切换,实现跨境波动时自动避障,中国大陆玩家优先走运营商自家精品回国,海外玩家走 PCCW。
实现:边界路由器跑 FRR(或 VyOS),同各上游 eBGP;内网到边界使用 L2/L3 上联;用 ipset + nftables 标记中国大陆目的网段,配合 policy routing(多路由表) 把不同目的地流量导向不同 ISP;再用 熔断探测(track 脚本 + route replace)在单线抖动时快速摘除故障路径。
1. 机柜与硬件清单(我用过、稳定的那套)
| 角色 | 型号/规格 | 关键参数 | 选择理由 |
|---|---|---|---|
| 边界路由主机(x1) | 1U/短深机箱 + Xeon-D 2146NT 或 AMD 7302P | 双电 550W,2×10G SFP+(Intel X710-DA2),1×1G 管理口,32G ECC,NVMe 500G | 纯软件路由(FRR/VyOS)在 10G 级别足够,Xeon-D/EPYC 都省电稳。X710 驱动成熟,PPS 抗打好。 |
| 上游光模块 | SFP+ SR/LR 视对端 | 对应机房尾纤类型 | 跟对端/机房确认 LC/SC、OM3/OM4,别在凌晨被尾纤制裁。 |
| ToR 交换 | 机房/ISP 提供或自带轻交换 | 支持 VLAN Trunk | 把四个上游各走一根上联,避免混接。 |
| 游戏服务器群 | CentOS 7 / Rocky 8 + 万兆网卡 | 每台 10G 上联到内网交换 | 我们的业务面在 CentOS 7,下面贴的 sysctl 也是围绕它写的。 |
上行带宽参考(我们实测):
- 单线 eBGP,10G 口可跑满;四线同时开,CPU < 35%,中断亲和绑核后 PPS 更稳。
- 典型手游场景:登录短突发 + 长连接维持,对 RTT 抖动敏感,对吞吐压力分散。
2. 物理与逻辑拓扑
[ Game Servers (CentOS7) ] -- L2/L3 --> [Edge Router (FRR/VyOS, 10G)]
|-- eBGP -- [CN2 (AS4809)]
|-- eBGP -- [CMIN2 (AS58453)]
|-- eBGP -- [CU (AS4837/9929)]
|-- eBGP -- [PCCW (AS3491)]
我们向上游申请 /24 公网段(或多段),由我们对外 BGP 广告(有些托管商也支持你用他们的 AS 代播,注意 LOA/CIDR 验证)。
入站(玩家 → 我们):靠 各上游对我们前缀的传播 决定走哪条,上游通常提供 Community 控制(例如“仅向中国路由传播”/“降低非目标地区 LP”),上线前要索取对方的 BGP 社区文档。
出站(我们 → 玩家):用 策略路由+多路由表 显式指定:中国大陆目的地 → CN2/CMIN2/CU;非大陆 → PCCW。同时以 本地优先级(local-pref) 微调 BGP 选择,做二次兜底。
3. 上游参数台账(上线当天我就贴在机柜门背面)
以下 IP/AS 为示例,请替换为你的对接信息。
| 线路 | 对端 ASN | 本地互联(our side) | 对端(peer side) | VLAN/物理口 | BGP MD5 | 备注 |
|---|---|---|---|---|---|---|
| CN2 | 4809 | 203.0.113.2/30 | 203.0.113.1 | eth1.100 | md5-ct |
GIA 口,费用高但稳 |
| CMIN2 | 58453 | 203.0.113.6/30 | 203.0.113.5 | eth1.101 | md5-cm |
移动回国好 |
| CU | 4837(或 9929) | 203.0.113.10/30 | 203.0.113.9 | eth1.102 | md5-cu |
华北/东北常常好 |
| PCCW | 3491 | 203.0.113.14/30 | 203.0.113.13 | eth1.103 | md5-pccw |
海外首选 |
4. 边界路由系统搭建(两种做法,我更偏向 FRR on Linux)
4.1 选型
方案 A:FRR on CentOS 7 / Rocky(我本次采用)
优点:灵活、和内核策略路由亲和;缺点:需要自己打理内核/驱动。
方案 B:VyOS
配置语义化、带内建 PBR/VRF/健康探测;适合快速落地。
下面以 FRR 8.x on CentOS 7 为主线,穿插给出 VyOS 等效命令。
4.2 安装与基线
# EPEL + FRR
yum install -y epel-release
yum install -y frr frr-pythontools
# 开启需要的守护
sed -i 's/bgpd=no/bgpd=yes/' /etc/frr/daemons
sed -i 's/zebra=no/zebra=yes/' /etc/frr/daemons
systemctl enable frr && systemctl start frr
内核建议:CentOS 7 自带内核较老,如需 BBR/更好的 RFS/RPS,可装 ELRepo 的 kernel-ml。我们线上稳定在 5.x,BPF/nftables 表现更好。谨慎变更,灰度重启。
5. BGP 基础配置(bgpd.conf 精简骨架)
vtysh -c 'configure terminal' <<'CFG'
router bgp 65001
bgp router-id 203.0.113.2
timers bgp 10 30
no bgp ebgp-requires-policy
no bgp default ipv4-unicast
neighbor CT peer-group
neighbor CT remote-as 4809
neighbor CT password md5-ct
neighbor 203.0.113.1 peer-group CT
neighbor CM peer-group
neighbor CM remote-as 58453
neighbor CM password md5-cm
neighbor 203.0.113.5 peer-group CM
neighbor CU peer-group
neighbor CU remote-as 4837
neighbor CU password md5-cu
neighbor 203.0.113.9 peer-group CU
neighbor PCCW peer-group
neighbor PCCW remote-as 3491
neighbor PCCW password md5-pccw
neighbor 203.0.113.13 peer-group PCCW
address-family ipv4 unicast
network 198.51.100.0/24 ! 我们对外广告的业务前缀
maximum-paths 4
neighbor CT activate
neighbor CM activate
neighbor CU activate
neighbor PCCW activate
! 入站调 LP,优先 CN 线路(只对中国大陆目的地产生作用的“二次兜底”)
neighbor CT route-map IN-CT in
neighbor CM route-map IN-CM in
neighbor CU route-map IN-CU in
neighbor PCCW route-map IN-PCCW in
! 出站打社区/AS Path(配合上游策略)
neighbor CT route-map OUT-CT out
neighbor CM route-map OUT-CM out
neighbor CU route-map OUT-CU out
neighbor PCCW route-map OUT-PCCW out
exit-address-family
! 例:入站本地优先
route-map IN-CT permit 10
set local-preference 300
route-map IN-CM permit 10
set local-preference 290
route-map IN-CU permit 10
set local-preference 280
route-map IN-PCCW permit 10
set local-preference 200
! 例:出站社区与轻度 prepend(具体值向上游索取文档)
route-map OUT-CT permit 10
set community 65001:100 additive
route-map OUT-CM permit 10
set community 65001:110 additive
route-map OUT-CU permit 10
set community 65001:120 additive
route-map OUT-PCCW permit 10
set as-path prepend 65001 65001
CFG
要点
- maximum-paths 4 保留等价多路径(用于非策略流量的均衡兜底);
- 入站 local-pref 只是帮助“默认流量”的选择;关键仍靠 PBR 把中国大陆目的地导向 CT/CM/CU;
- 社区值请用上游的官方文档,很多 ISP 提供“仅向中国传播/降低国际 LP”的社区,这对入站非常关键。
6. “中国大陆目的地识别 + 策略路由”——核心避抖方案
6.1 准备中国大陆 IP 集(ipset)
我用 ipset 存中国大陆 CIDR 集合(自动脚本每日更新,数据源可以是 APNIC/各镜像,生产不要用可疑来源)。
# 创建集合
ipset create cn hash:net family inet maxelem 131072
# 导入(示例文件,如 /opt/data/cn_cidr.txt,每行一个CIDR)
while read cidr; do ipset add cn $cidr; done < /opt/data/cn_cidr.txt
我踩的坑:ipset 太大时要注意 maxelem,否则导入一半报错。生产我会做 双集合 切换(cn_new → cn,导入完成后 swap),避免更新瞬间漏判。
6.2 用 nftables 给中国目的流量打标记(fwmark)
cat >/etc/nftables.conf <<'NFT'
flush ruleset
table inet mangle {
set cn {
type ipv4_addr
flags interval
elements = {
# 仅示例,实际由脚本生成
1.0.1.0/24, 1.0.2.0/23, 27.0.0.0/8
}
}
chain prerouting {
type filter hook prerouting priority mangle;
ip daddr @cn meta mark set 100 # 大陆目的地 → mark=100(优先 CT/CN2)
}
}
NFT
systemctl enable nftables && systemctl restart nftables
扩展:如果你想 移动号段走移动(CMIN2)、联通号段走联通,可以把 @cn 拆成更细的集合(@ct, @cm, @cu),在 prerouting 里按不同集合设置 不同 fwmark(101/102/103)。
6.3 多路由表与策略(ip rule / ip route)
在 /etc/iproute2/rt_tables 加入:
100 cn2
101 cmin2
102 cu
103 pccw
为每条 ISP 设置一张表的默认出口(网关替换为你的对端 /30 地址):
# CN2
ip route add default via 203.0.113.1 dev eth1.100 table 100
# CMIN2
ip route add default via 203.0.113.5 dev eth1.101 table 101
# CU
ip route add default via 203.0.113.9 dev eth1.102 table 102
# PCCW
ip route add default via 203.0.113.13 dev eth1.103 table 103
策略:中国大陆目的地(mark=100)优先 CN2,其次 CMIN2/CU;默认流量走 PCCW。
# 中国大陆 → table 100(CN2)
ip rule add fwmark 100 table 100 priority 100
# 默认(海外/未匹配) → PCCW
ip rule add table 103 priority 500
可选改进:把 fwmark 100 的 fallback 写成 nftables 动态切换(见 7.2),当检测到 CN2 抖动就把 mark 重写到 101(CMIN2)或 102(CU)。
7. 健康探测与自动避障(“抖则绕,稳则复位”)
7.1 轻量探测脚本(探测对端与中国境内目标)
我用一个简单的 check_isp.sh 做两类检测:
- 邻居连通(对端互联 IP);
- 业务目的地质量(选几省的权威 DNS / 自建探针 IP)。
#!/bin/bash
# /usr/local/bin/check_isp.sh
ISP=$1 # cn2|cmi|cu|pccw
GW=$2 # 203.0.113.1 等
PROBE=$3 # 例如 114.114.114.114/各省探针IP
TABLE=$4 # 100/101/102/103
ok=1
# 1) 网关连通
ping -c 3 -W 1 $GW >/dev/null || ok=0
# 2) 目的地质量(丢包<5%,均延小于阈值)
loss=$(ping -c 10 -W 1 $PROBE | awk -F',' '/packet loss/{print $3+0}')
rtt=$(ping -c 4 -W 1 $PROBE | awk -F'/' 'END{print $5+0}')
if (( $(echo "$loss > 5" | bc -l) )) || (( $(echo "$rtt > 120" | bc -l) )); then
ok=0
fi
STATE_FILE="/run/isp_${ISP}.state"
if [ $ok -eq 1 ]; then
echo up > $STATE_FILE
else
echo down > $STATE_FILE
# 摘除该表默认路由(插一条更高 metric 的兜底或直接删除)
ip route replace default dev lo table $TABLE || true
fi
配合 systemd 定时每 10s 跑一次,并在 down 时通过 nft 动态改 mark(见 7.2)。
7.2 动态改写 mark 的思路
- 维护一个 优先队列:CN2 > CMIN2 > CU;
- 当某一条 down,就把 nft 中的 meta mark set 100 改为对应备选的 101 或 102。
示例(切到 CMIN2):
nft replace rule inet mangle prerouting ip daddr @cn meta mark set 101
经验:避免“抖则反复切”的振荡,可加 抖动抑制(down 连续 3 次才认定,up 连续 6 次才恢复),或给每条线路加一个 最小驻留时间。
8. 服务器侧(CentOS 7)网络内核与连接优化
/etc/sysctl.d/99-game.conf:
# 队列与并发
net.core.somaxconn=65535
net.ipv4.tcp_max_syn_backlog=262144
net.core.netdev_max_backlog=250000
net.core.rmem_max=67108864
net.core.wmem_max=67108864
net.ipv4.udp_rmem_min=16384
net.ipv4.udp_wmem_min=16384
# BBR(如用 5.x 内核)
net.core.default_qdisc=fq
net.ipv4.tcp_congestion_control=bbr
# TIME_WAIT 与端口
net.ipv4.ip_local_port_range=10000 65000
net.ipv4.tcp_tw_reuse=1
net.ipv4.tcp_fin_timeout=10
# 保活
net.ipv4.tcp_keepalive_time=600
net.ipv4.tcp_keepalive_intvl=30
net.ipv4.tcp_keepalive_probes=3
# RFS/RPS(按 CPU/队列调,示例值)
net.core.rps_sock_flow_entries=32768
多队列/中断绑核(以 X710 为例):
ethtool -L eth0 combined 8
for i in $(seq 0 7); do
echo $((1<<i)) > /proc/irq/$(grep eth0-TxRx-$i -m1 /proc/interrupts | awk '{print $1}'|tr -d :) /smp_affinity
done
坑:CentOS7 + 古老内核下开 BBR 容易遇到队列调度兼容问题,务必先灰度一台机器,确认 RTT 抖动没被放大再全量。
9. 业务面(登录网关/LB)与四线联动
- 入口 LB:HAProxy/Envoy,TCP 模式承载长连接;
- 后端:同机房 L3 直连或 VLAN;
- 四线关联:LB 所在节点通过 默认路由 → 边界路由,由策略路由决定实际出口。
- 会话保持:手游大多靠逻辑层 Token,网络侧只要避免 NAT 变更即可。带公网段时推荐 不做 NAT,让真实源 IP 进业务,方便风控。
HAProxy 片段(示例):
defaults
mode tcp
timeout connect 3s
timeout client 2m
timeout server 2m
frontend fe_login
bind 0.0.0.0:7000
default_backend be_login
backend be_login
server s1 10.10.10.11:7000 check
server s2 10.10.10.12:7000 check
10. 监控与验收
我用的三板斧:
- Smokeping:对各省运营商 DNS/自有探针做往返延迟/抖动图;
- Prometheus + node_exporter + blackbox_exporter:抓 ping、tcp_connect;
- MTR:出现异常时比对经不同出口的路径差异。
上线前/后对比(节选)
| 目的地 | 单线(PCCW)RTT/丢包 | 多线策略后(CN2/CM/ CU/PCCW) | 备注 |
|---|---|---|---|
| 华北-联通 | 85ms / 1.2% | 48ms / 0.2%(走 CU) | 峰值抖动明显下降 |
| 华东-电信 | 95ms / 1.5% | 43ms / 0.3%(走 CN2) | 贴合玩家分布 |
| 华南-移动 | 78ms / 0.9% | 50ms / 0.2%(走 CMIN2) | 登录洪峰稳定通过 |
| 新加坡 | 35ms / 0.1% | 35ms / 0.1%(走 PCCW) | 海外不受影响 |
11. 典型故障与坑位清单(我真遇到过的)
BGP 起不来:Bad authentication
→ 典型是 MD5 不一致,或者上游换了口没同步。核对 LOA、对端接口、ACL 是否放行 TCP/179。
有 BGP,没转发
→ Linux 路由表没装入缺省路由;或者 策略路由没有 hit(fwmark 没打上)。tcpdump -i any -n 'port 179' 看 BGP;nft list ruleset 看 mark;ip rule 看优先级。
频繁“抖切”
→ 探测阈值太严/周期太短;给健康检查加 hysteresis,并在切换时 降速收敛(sleep 1~3s)避免抢占。
CN2 很稳但偶尔单省炸毛
→ 地区性维护常见。我们在 ipset 层做了省份细分(按自治系统归属/探针归属),只对异常省份重定向至次优线路,不要“一刀切”。
大表 ipset 更新导致瞬时 miss
→ 用 ipset swap 双集合切换,更新在新集合完成后再原子替换。
入站不走你想要的线
→ 这是 入站流量工程,靠你对外的 Community 与上游的传播策略。跟 ISP 要清楚 “仅向中国传播/优先中国回国口” 的社区,必要时对非目标地区做 as-path prepend 降权。
RPKI 导致前缀被丢弃
→ 把你的前缀在 RIR(APNIC 等)完成 ROA(Route Origin Authorization),并确认上游的 RPKI 验证状态,避免 invalid。
12. VyOS 等效(如果你更喜欢“一句话”式配置)
set interfaces ethernet eth1 address '203.0.113.2/30' # CN2 子网
set protocols bgp 65001 neighbor 203.0.113.1 remote-as '4809'
set protocols bgp 65001 neighbor 203.0.113.1 password 'md5-ct'
set protocols bgp 65001 network '198.51.100.0/24'
set protocols bgp 65001 maximum-paths ebgp '4'
# 省略 CMI/CU/PCCW 类似配置...
# 策略路由
set firewall group network-group CN-NETS network '1.0.1.0/24'
# ... 批量导入
set policy route CN2-ROUTE rule 10 set table '100'
set policy route CN2-ROUTE rule 10 destination group network-group 'CN-NETS'
set interfaces ethernet eth0 policy route 'CN2-ROUTE'
# 健康检查:vyos 原生 track-sla(新版),或脚本同上
13. 安全与 DDoS 备忘
- 四线同时开口,面更大。与上游确认 黑洞社区(/32 RTBH)和是否支持 FlowSpec。
- 游戏端口暴露最少化,管理面走专线/VPN。
- 有预算时在香港对接 清洗/高防,与边界 BGP 做 GRE/隧道回注。
14. 变更与回滚策略(我当晚的操作手册)
- 新设备上架但不接入生产,只起 BGP 邻居看路由学习是否正常;
- 打开策略路由但仅对测试段(内网几个源 IP),跑完整链路压测;
- 分时段放量(夜间 10% → 30% → 50% → 100%);
- 准备一键回滚脚本:恢复 nft 原规则 + ip rule flush + 只留 PCCW 缺省;
- 整晚监控(Smokeping/黑盒探测/日志),记录每次切换与理由。
15. 我线上用的“最小可复用”脚本包(提纲)
/opt/netops/
├── update_cn_ipset.sh # 拉取/校验/生成 cn_cidr.txt + ipset swap
├── check_isp.sh # 健康探测 + 摘除默认路由
├── switch_mark.sh # 根据可用性在 100/101/102 间切换
├── nft_gen.py # 由模板生成 nft 规则(大表分片)
└── bootstrap.sh # 首次部署一键跑
update_cn_ipset.sh(核心片段):
NEW=/tmp/cn_new.txt
# 1) 下载并校验(略)
# 2) 生成 ipset 命令文件
echo "create cn_new hash:net family inet maxelem 131072" > /tmp/cn_new.ipset
awk '{print "add cn_new "$1}' $NEW >> /tmp/cn_new.ipset
ipset restore < /tmp/cn_new.ipset
ipset swap cn cn_new
ipset destroy cn_new
16. 成本与带宽利用
计费:香港常见 95 峰值计费 或 固定带宽;四线分流后单线峰值更平滑,95 峰值更友好。
路由策略会改变计费分布,与财务沟通好“哪条线承接中国流量”,避免月底惊喜。
17. 一周后的图
上线 7 天后,我把那张“锯齿延迟”截图和现在的 Smokeping 放在了一起:华北、华东、华南三条曲线像拉直的丝带,晚上 8 点到 11 点也只见轻微起伏。玩家提单里“卡登录、掉线”的关键词骤降。
那个周六的凌晨 4:55,我把最后一条 nft replace rule 回到 CN2,工具箱收好,机柜门轻轻一合——服务器们在冷气里继续嗡嗡,四条 BGP 像四根稳固的桥。
运营小伙伴发来消息:“今天登陆峰值很顺”。我回了个“👌”。这活,值了。
附:检查清单(上线前逐条打勾)
- 四条上游 LOA/ASN/MD5 校验
- RPKI/ROA 完成,前缀不 invalid
- FRR maximum-paths、邻居 route-map 生效
- ipset 双集合切换,nft 标记命中率 > 95%
- ip rule 优先级正确,默认海外走 PCCW
- 健康探测阈值与抖动抑制设置妥当
- 回滚脚本已在 /root/rollback.sh 并演练
- Smokeping/Blackbox 面板齐备,告警阈值设置
- 与财务确认计费模型变化
本文不是随便“抄的一份通用 BGP 模板”,而是我在香港机房里亲手把 CN2/CMIN2/CU/PCCW 四线串起来、让手游的跨境体验稳住的全过程。BGP 只是路由协议,稳定来自工程细节:目的地识别、策略路由、健康探测与抖动抑制、入站社区协商、监控与回滚。
如果你也在把游戏服放在香港,希望这些 可复制的配置与脚本 能帮你少熬几个夜。