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

部署在香港服务器上的网络游戏,我们如何结合 CN2 GIA 线路降低国内和东南亚玩家的登录排队延迟?

发布人:Minchunlin 发布时间:2025-09-15 09:36 阅读量:1112


凌晨 1:40,我在香港葵涌机房的监控屏上,广州、成都、曼谷三条曲线同时抬头——登录峰值远超预期,网关服的等待队列一路飙,玩家在论坛里刷屏“排队 6000+,卡在验证”。同一套游戏服、同一套网关逻辑,为什么香港机房离得这么近,延迟还会突然咬人?

我拿着保温杯蹲在机柜旁,另一只手不停地跑 mtr 和 tcpdump。5 分钟后,结论出来:回国路径绕行、抖动大,半数流量没有走 CN2 GIA,而是被挤到普通国际出口上了。

那一夜我们改了路由策略、接入第二条 GIA、切换 GeoDNS、调了 TCP 栈,队列从 5800 掉到 1200,峰值登录耗时从 9.4s 砍到 2.1s。接下来的这篇文章,就是把那次“抢修”整理成可复制的落地教程,不玩玄学,全部按CentOS 7 环境写,既能给新同学照着做,也能给老兵提供优化和排坑清单。

目标画像与关键思路

  • 目标玩家区域:中国大陆(电信/联通/移动)+ 东南亚(泰国、越南、马来西亚、新加坡、印尼)。
  • 核心目标:降低登录阶段的排队等待时间,把首包/握手延迟和队列停留时间打下来。

关键抓手:

  • 入口/出口路径收敛到 CN2 GIA(或等效高质量线路),降低抖动/丢包;
  • 入口分流 + 出口策略路由,实现“谁来、走哪条线”的对称与稳定;
  • 登录网关轻量化 + 并发承载能力提升(连接跟踪、队列、内核 TCP 栈、BBR);
  • DNS/Anycast/多 EIP 组合,把流量“就近”吸到合适的入口;
  • 可观测与应急切换,实时盯丢包/时延,路由一键回滚。

1. 现场环境与参数(真实上手可复刻)

1.1 硬件与网络拓扑

角色 机型 CPU 内存 存储 网卡 线路
网关 (GW-A) 1U 独服 Xeon 4310 *2 64GB NVMe 1TB 2×10GbE (Intel X710) HK 运营商 #1(原生 CN2 GIA)
网关 (GW-B) 1U 独服 Xeon 4310 *2 64GB NVMe 1TB 2×10GbE (Intel X710) HK 运营商 #2(GIA/等效优先大陆 & ASEAN)
业务集群(Login/Logic/DB) 2U × N EPYC 7313P 128GB NVMe RAID10 2×25GbE 机房内东西向
  • OS:CentOS 7.9(统一内核版本便于运维)
  • 内核:生产建议 ELRepo kernel-ml 以启用 BBR2;若暂不升级,也可按下文给出 CentOS7 3.10 的保守优化。

1.2 网络策略(高层)

  • 入站:通过 GeoDNS 将 大陆/ASEAN 客户端解析到不同的 EIP(分别挂载到 GW-A / GW-B),确保入口天然收敛到相应的高质量上游(GIA)。
  • 出站:在 GW 上做 策略路由(ip rule + fwmark + GeoIP/ipset),中国大陆 & 东南亚 请求走 CN2 GIA,其余走普通国际。
  • 对称回程:入站 EIP 与出站下一跳绑定,避免回程绕行与路径抖动。必要时以独立 IP 段分别公告(或独立 EIP),保证对称。
  • LB 层:登录 TCP/UDP 走 HAProxy (L4);Web/TLS 接口走 Nginx (TLS1.3/0-RTT 可选)。

2. 选线与“真假 GIA”识别清单(避坑)

  • 看路由而不是广告词:mtr -T -P 443 your.ip,大陆侧是否进入 59.43/AS4809 等 CN2 节点,是否中间跳过多海缆/欧美绕路。
  • 时段抖动:晚间 20:00–23:00 连续跑 smokeping;真 GIA 抖动低、丢包低,p95/p99 稳定。
  • 分省份/分运营商测试:华南/华东/西南、电信/联通/移动各测一轮,避免只在广州电信好。
  • ASEAN 回程:曼谷/吉隆坡/新加坡分别 mtr,确认不是“去程好、回程差”。
  • 签 SLA 和可视化:要求运营商提供 Looking Glass、BFD/告警,并写进合同可退换(至少试跑 7 天)。

3. 域名与入口:GeoDNS / 多 EIP 策略

3.1 规划

  • login.game.example:中国大陆优先解析到 EIP-CN2(GW-A);ASEAN 解析到 EIP-ASEAN(GW-B);其他地区解析到普通 EIP(可与 GW-B 复用)。
  • 健康检查:各 EIP /healthz,TTL 30–60s,避免过度抖动。

3.2 GeoDNS 实操要点

  • 权威 DNS 选可配置 地理路由 与 最短 RTT 的厂商;
  • 监控字段:每地区解析命中率、切换次数、黑洞率;
  • 故障策略:单地域故障自动回落到另一条 GIA(写成灰度策略,详见 第9点)。

4. 网关(CentOS 7)网络内核与队列优化

4.1 基线内核参数(保守版,3.10 内核)

/etc/sysctl.d/99-game-net.conf

net.core.somaxconn = 65535
net.core.netdev_max_backlog = 250000
net.core.rmem_max = 268435456
net.core.wmem_max = 268435456

net.ipv4.tcp_rmem = 4096 87380 134217728
net.ipv4.tcp_wmem = 4096 65536 134217728
net.ipv4.tcp_max_syn_backlog = 16384
net.ipv4.tcp_synack_retries = 3
net.ipv4.tcp_fin_timeout = 15
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_timestamps = 1
net.ipv4.tcp_sack = 1
net.ipv4.tcp_mtu_probing = 1

net.ipv4.ip_local_port_range = 10000 65000
net.ipv4.tcp_syn_retries = 3

# 开启 fq +(如升级 kernel-ml 后再启用 bbr)
net.core.default_qdisc = fq

若升级 ELRepo kernel-ml(推荐),加上:

net.ipv4.tcp_congestion_control = bbr

4.2 NIC 与中断

# 查看/调优 ring
ethtool -g eth0
ethtool -G eth0 rx 4096 tx 4096

# 关闭可能影响延迟的一些 offload(按需)
ethtool -K eth0 tso off gso off gro on

# CPU 亲和/中断均衡
yum install irqbalance -y
systemctl enable --now irqbalance

5. 出口“走哪条线”:策略路由 + GeoIP 打标

5.1 多上联路由表

假设:

  • eth0 → GW-A 上的 CN2 GIA,网关 10.10.10.1,表 101
  • eth1 → 普通国际,网关 10.20.20.1,表 102
# /etc/iproute2/rt_tables
101 gia
102 intl

# 配置路由表
ip route add default via 10.10.10.1 dev eth0 table gia
ip route add default via 10.20.20.1 dev eth1 table intl

5.2 基于 GeoIP / ASN 的打标(iptables + ipset)

5.2.1 安装与生成中国 & ASEAN 目的地址集合

yum install ipset xtables-addons -y

# 以 CN, TH, VN, MY, SG, ID 为例(可用 cymru / ip2location / maxmind 转换脚本生成)
ipset create geo_cn hash:net
ipset create geo_asean hash:net

# 批量导入(示例)
while read cidr; do ipset add geo_cn $cidr; done < cn_cidr.txt
while read cidr; do ipset add geo_asean $cidr; done < asean_cidr.txt

也可用 ASN 维度(如 AS4134/AS9929/AS4809 等)生成 ipset,更贴近运营商路径。

5.2.2 用防火墙标记流量

# 标记去往 CN/ASEAN 的出站流量
iptables -t mangle -N GEO_MARK
iptables -t mangle -A OUTPUT -p tcp -m conntrack --ctstate NEW -j GEO_MARK
iptables -t mangle -A GEO_MARK -m set --match-set geo_cn dst -j MARK --set-mark 0x1
iptables -t mangle -A GEO_MARK -m set --match-set geo_asean dst -j MARK --set-mark 0x1
# 其余默认不标记 -> 走 intl

5.2.3 策略路由规则

ip rule add fwmark 0x1 table gia
ip rule add fwmark 0x0 table intl

关键点:登录服务的回包必须走同一上联,避免路径不对称导致抖动。对内网到网关的默认路由也要一致(或 SNAT 统一到对应 EIP)。

6. 入口“从哪条线进”:多 EIP + 绑定上联

6.1 EIP 与上联绑定

  • 在 GW-A 只把 EIP-CN2 绑在 eth0(GIA),RP 策略设为 strict 或用 iptables 保证源 EIP 的回程走 eth0。
  • GW-B 同理将 EIP-ASEAN 绑定 eth1(或第二家 GIA/优质 ASEAN 上联)。
# 防源路由欺骗
sysctl -w net.ipv4.conf.all.rp_filter=2
sysctl -w net.ipv4.conf.eth0.rp_filter=2

6.2 DNS 侧路由示意

  • 大陆来访 → 解析 login.game.example → EIP-CN2(GW-A)
  • 泰国/马来等 → 解析到 EIP-ASEAN(GW-B)
  • 其他地区 → EIP-INTL(GW-B 备份)

7. 登录层负载:HAProxy(L4)与 Nginx(TLS/接口)

7.1 HAProxy(TCP 登录握手/网关)

/etc/haproxy/haproxy.cfg

global
    maxconn 200000
    tune.ssl.default-dh-param 2048
    log 127.0.0.1 local0
    nbthread 8

defaults
    mode tcp
    timeout connect 3s
    timeout client  30s
    timeout server  30s
    option dontlognull

# 前端:分别监听不同 EIP(绑定上联)
frontend fe_login_cn2
    bind EIP-CN2:7000
    default_backend be_login_nodes

frontend fe_login_asean
    bind EIP-ASEAN:7000
    default_backend be_login_nodes

backend be_login_nodes
    balance leastconn
    server s1 10.0.1.11:7000 check maxconn 30000
    server s2 10.0.1.12:7000 check maxconn 30000

说明:两个前端口分别承接 CN2/ASEAN 入口,后端共享,以便弹性扩容与业务对齐。

7.2 Nginx(TLS1.3 / 0-RTT 可选,用于启动器 API)

/etc/nginx/conf.d/api.conf

server {
    listen 443 ssl http2 reuseport;
    server_name api.game.example;

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_early_data on;  # 0-RTT,视接口幂等性启用
    ssl_session_cache shared:SSL:50m;

    location /auth {
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
        proxy_pass http://api_backend;
    }
}

0-RTT 只对幂等接口开启,避免重放风险。

8. 登录队列“真凶”与三板斧

登录排队并不只来自并发超限,更多是 首包慢、握手重传 让排队驻留时间上升:

  • 线路抖动/丢包 → SYN 重传、TLS 重传 → 队列膨胀
  • 连接跟踪/端口耗尽 → 新连接挂起
  • 应用层“串行点”(如单点 Redis、单线程校验)

8.1 内核连接跟踪与端口

# 连接跟踪
sysctl -w net.netfilter.nf_conntrack_max=2621440
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_established=120

# 临时端口范围已在 §4 设置为 10000–65000

8.2 应用层快取与分片

  • 登录态校验加本地缓存(memcached/Redis Cluster),失败再回源。
  • 验证码/短信等三方接口,加异步队列与熔断,避免拖后腿。
  • 网关无状态化:JWT/短令牌,减少粘连。

9. 可观测与“秒级”切线:MTR / Smokeping / 一键回滚

9.1 观测项

  • 按地域:广州/成都/北京/上海/深圳 + 曼谷/新加坡/雅加达 mtr 每 60s;
  • 四分位:p50/p90/p95/p99 延迟,抖动(StdDev),丢包率;
  • 登录阶段:从 SYN 到第一个业务包(或 200/成功码)的耗时。

9.2 自动降级与回滚

  • 当 p99 > 350ms 或 丢包 > 1% 持续 2 分钟:
  • 切换 GeoDNS 使受影响地区回落到另一条 GIA;
  • GW 上 ip rule 切至备表(预设好 table gia_b)。
  • 所有切换写成 Ansible Playbook 与 一键脚本,控制台双确认。

10. 效果数据(实测)

连续 7 天压力回放 + 线上灰度

指标 优化前 优化后(CN2/ASEAN 分流 + TCP 调优)
登录首包 p50 138 ms 46 ms
登录首包 p95 420 ms 112 ms
排队平均驻留 4.6 s 1.3 s
排队峰值长度 5,800 1,200
丢包率(晚高峰) 0.9% 0.2%
抖动(StdDev) 38 ms 11 ms

11. 进阶:BGP / GRE 叠加与对称性强化(可选)

如果你具备 BGP 能力(自有 /30 段、上游开 BGP 会话):

  • 同一前缀分别在两家上游公告,使用 Community 与 LocalPref 控制不同国家/AS 的入口择优;
  • 对 CN/ASEAN 设更高 LocalPref 到 GIA,上游按社区做优选;
  • 灰度时期用 MED 或 prepend 做细粒度分流;
  • BFD 保证掉线秒级收敛。
  • 若无 BGP,可在 GW 与上游 POP 建 GRE/IPIP 隧道,将特定地域的出站强制走 GIA POP,实现“去 GIA、回 GIA”。

12. 常见坑与现场解法

“伪 GIA”只在华南好

解法:按省/运维商分桶评估,写入合同可换线;上线前让运营商提供 AS-Path 与 LG 证据。

入/出不对称(入口是 GIA,回程走了普通国际)

解法:EIP 绑定上联、对内 SNAT 到对应 EIP;必要时分前缀公告或DNS 强绑定。

xt_geoip 规则被内核升级打断

解法:写 systemd ExecStartPre 重新加载 ipset;有条件用 ASN ipset 降低频繁更新。

端口耗尽/conntrack 满

解法:扩大 ip_local_port_range、调 nf_conntrack_max;HAProxy 开启 reuseport、提升 maxconn。

TLS 0-RTT 导致偶发重复提交

解法:仅对 幂等 GET 或 幂等验证接口开启,写防重放逻辑。

13. 交付清单(可直接照搬)

  •  两条上联:CN2 GIA + Intl/ASEAN 优选
  •  GeoDNS:地区 → EIP 映射,健康检查 + 回退
  •  GW:sysctl 基线、ip rule + fwmark、ipset(CN/ASEAN)
  •  LB:HAProxy L4、Nginx TLS1.3/0-RTT(幂等接口)
  •  可观测:mtr/smokeping + p95/p99 看板,SLA 告警
  •  应急:一键切线剧本 + 回滚

14. 附录:脚本与配置片段

14.1 ipset 重载脚本(systemd)

/usr/local/bin/reload-geoip.sh

#!/bin/bash
set -e
ipset restore < /etc/ipset/geoip.restore

/etc/systemd/system/geoip-reload.service

[Unit]
Description=Reload GeoIP ipset

[Service]
Type=oneshot
ExecStart=/usr/local/bin/reload-geoip.sh

/etc/systemd/system/geoip-reload.path

[Unit]
Description=Watch ipset restore file

[Path]
PathChanged=/etc/ipset/geoip.restore

[Install]
WantedBy=multi-user.target

14.2 Ansible 片段(切换到备用 GIA)

- name: switch to gia_b
  hosts: gateways
  tasks:
    - name: add rule to use table gia_b
      command: ip rule add fwmark 0x1 table 201
    - name: change default gw of table gia
      command: ip route change default via 10.10.20.1 dev eth0 table gia

凌晨 3:10,香港机房的嗡鸣声像白噪音,曲线回到顺滑的形状。微信群里有人仍在讨论“为什么昨晚排队这么快就下来了”。我没回,拎着工具包去楼下买了一杯冻柠茶。
说到底,登录排队不是怪在玩家多,也不是某一段代码“运气不好”。线路是否干净、路径是否对称、队列是否短链路,这些细节凑在一起,才决定了玩家点下“开始游戏”后的那几秒是不是顺滑。
如果你现在也在机房里对着曲线发愁——就从上面这份清单开始:入口分流、出口策略、CN2 GIA 收敛、TCP 栈打磨、观测与回滚。
等你把这些都跑通了,再回头看“排队”,它多半已经变成了“眨眼就进"。