多VPS带宽聚合
stable搞了几台廉价美西 VPS 后发现一个尴尬的事:单台出去带宽就 8-50Mbps,下个 YouTube 高清视频慢得不行。
如果能把几台 VPS 的带宽凑一起,聚合出一条 SOCKS5 代理,下载工具直接走这条线,理论上就能用多台便宜货的总带宽顶一台高价大带宽 VPS。
先试的方案:sing-box + HAProxy
第一版搭了两个容器:
sing-box 跑四路 Hysteria2 客户端,各占一个本地 SOCKS5 端口,HAProxy 在前面做 roundrobin 分发。
用了一阵发现几个烦人的地方:
- 加一台 VPS 要改两套配置(sing-box 的 outbound + HAProxy 的 backend)
- 想临时关掉某个节点?没有 toggle,得改配置重启
- HAProxy 不支持热重载,改完必须重启整个链路
- 没有 Web 界面,想看各节点状态只能看日志
本质问题:两个容器各管各的,生命周期不同步,运维起来像在同时维护两个系统。
干脆自己写一个:Rally-go
后来干脆用 Go 写了个单二进制,把 Hysteria2 客户端和 SOCKS5 负载均衡塞到一起:
和旧方案的核心区别:
- 一个进程搞定所有事,不再伺候两个容器的编排
- 负载均衡从 roundrobin 换成 leastconn(谁闲谁接活)
- 加了个简陋的 Web UI,实时看各节点流量和延迟
- 支持 SIGHUP 热重载,改完配置发个信号就行
- 每条线路可以单独 toggle,不用重启
配置长这样
listen: ":1080"
web_listen: ":9090"
backends:
- name: "节点A"
addr: "node-a.example.com:443"
auth: "your-auth-password"
insecure: true
down_mbps: 50
up_mbps: 10
- name: "节点B"
addr: "node-b.example.com:443"
auth: "your-auth-password"
insecure: true
down_mbps: 50
up_mbps: 10Hysteria2 的 bandwidth auto-detect 有个坑:它会严重低估可用带宽。一开始没设 down_mbps,某一台节点只能跑到 375KB/s,设了之后直接飙到 4MB/s。手上有的几台 VPS 最后都手动给了值。
信号处理踩了个坑
热重载实现的时候犯了个低级错误。一开始 ReloadConfig 里直接调了 r.Run(),这是个阻塞调用——结果 SIGHUP 信号处理协程被卡住了,第二次发信号根本没反应。
修起来很简单:go r.Run() 丢到独立协程里跑,别阻塞信号循环。同时给 Forwarder.Stop() 加了 sync.Once 保证幂等,避免重复关闭 panic。
go func() {
r.Stop()
if err := r.Run(); err != nil {
log.Fatal(err)
}
}()Docker 部署
services:
rally:
image: ghcr.io/your-org/rally-go:latest
container_name: rally
network_mode: "host"
restart: unless-stopped
volumes:
- ./rally.yaml:/etc/rally.yaml:ro实测能跑多少
拿三台美西 VPS 试了一下 YouTube 视频下载:
| 节点 | 延迟 | 单节点带宽 | |------|------|-----------| | 节点A | 200ms | 111Mbps | | 节点B | 190ms | 119Mbps | | 节点C | 210ms | 123Mbps | | 聚合 | - | ~120Mbps |
leastconn 均分得还不错,三路误差不到 2%。
接入 MeTube 后,下载速度从单节点的 ~5MB/s 提到 ~15MB/s,一个 2GB 视频从 7 分钟缩到 2-3 分钟。
目前状态
代码放 GitHub 了(私有仓库,MIT),Docker 跑在 NAS 上,日常在用。遇到过某个节点因为 Cloudflare 封 HTTP 000 被踢出池子,其他三路一直稳定。