Skyline Speeder 一套单边 TCP 加速软件

来源: skyline-speeder/README.zh.md at main · CYBERVERSE-Research/skyline-speeder · GitHub

这是什么

Skyline Speeder 是一套单边 TCP 加速软件:以 eBPF 程序的形式只运行在发送数据的服务器上,面向丢包严重、往返时延长、标准 TCP 在其上几乎跑不起来的链路。它的做法是让发送速率保持在这条路径实际能交付的水平,而不是每丢一个包就把速率砍下来,以此提高这类链路上的吞吐。接收端不做任何改动。

原理

BBR 靠估计带宽而不是对每次丢包作出反应,但它仍会向丢包让步:内核里的 BBR 每次进入丢包恢复都会先退到"包守恒"(收到几个确认才发几个包),每次超时重传后更是从 1 个包重新开始。在一条与排队无关、随机丢掉 10%-20% 报文的链路上,丢包恢复和超时成了常态,RTT 在 100-300 ms 时它的吞吐逐次运行起伏很大,经常直接崩掉。Skyline Speeder 在发送端用 eBPF 实现的 tcp_congestion_ops(struct_ops)替换拥塞控制,并只基于一个前提:丢包本身不携带拥塞信息。

  • 速率来自测量,而不是丢包。 每一轮测量投递速率(取最近几轮的峰值)和基准 RTT;每个 ACK 到来时,在包括丢包恢复在内的所有 TCP 状态下,直接把窗口设为 带宽 × 基准 RTT × 增益。丢包本身永远不会让窗口缩小,也没有需要慢慢爬出来的"包守恒"阶段。
  • 丢包补偿。 在丢包率为 p 的路径上,投递速率比实际需要发送的量少了 (1 - p)。窗口和速率会按这条流自己测得的丢包率放大 1 / (1 - p),最多放大到配置的上限。
  • Pacing。 数据经 fq 队列以 带宽 × 增益 × 补偿系数 的速率均匀发出,而不是成批倾泻,并受硬性速率上限约束;窗口只需要不成为瓶颈。
  • 两个阶段。 STARTUP 用较高的增益尽快摸到路径带宽;带宽连续几轮不再增长后,进入 CRUISE。
  • 拥塞护栏。 只有两个信号算真实拥塞:排队时延超过阈值(固定值与基准 RTT 的一定比例取较大者),以及 ECN 标记。任一出现,这一轮的增益就降到 guardrail_gain,低于测得的带宽;下一轮信号消失即恢复。
  • 有上限的 RTO(可选)。一个 cgroup sockops 程序按连接限制内核的重传超时,避免线路抖一下就让连接最长等上两分钟。
  • 首轮冗余(默认开启)。在这样的链路上,拖慢短响应的不是窗口,而是等丢包恢复:尾丢探测约两个往返、重传超时约三个往返、丢了 SYN-ACK 固定等一秒。一个 TC 出方向程序把每条 skyline_cc 连接的握手包和前 64 KiB 各发两份,第二份比原包晚 10 ms,丢一个包只多等这几毫秒,而不是等一个计时器。代价是每条连接最多多发 64 KiB。

Rust 编写的 skyline-speederd 负责加载 BPF 对象(每个对象加载时都要过内核验证器),并通过双缓冲槽在线下发新系数,每条流在 RTT 边界切换过去;ssctl 是它的命令行。

Important

这个前提只对与排队无关的丢包成立。 如果链路的丢包其实是拥塞瓶颈上的排队溢出,丢包补偿与排队护栏会朝相反方向用力,只会更糟。简单判断:固定速率的 UDP 打流不丢包、TCP 却大量重传,说明丢包是自身突发造成的排队溢出,这时不该用本工具。它也不追求公平:不会刻意和竞争的流平分链路。

实测性能

bbr、tcp-brutal 与 skyline_cc 在一条真实跨境链路上的对比,三者都只部署在服务端,通过同一套按目的地前缀的路由覆盖生效,客户端全程使用原生 TCP。

位置 角色
服务端 新加坡 KVM VPS · 10 Gbps 发送方,唯一被加速的一端
客户端 阿里云 ECS,华南(广东) · 200 Mbps 接收方,原生 TCP,不做任何改动

RTT 70-73 ms、丢包 10%-30%,测于晚高峰。skyline_cc 使用 0.1.0 时随附的默认系数,即现在 使用与调参指南 里的「高随机丢包档」;当前的默认系数没有在这条链路上测过。tcp-brutal 为 v2.0.0,速率 200 Mbps;bbr 为内核自带版本。

8 轮 × 3 算法 × 5 场景 = 120 次运行,119 次完成。每轮轮换算法顺序,避免链路在测试中劣化时偏袒先跑的那个。各场景赢家按轮统计:

场景 赢家 幅度
视频(6 MB 分块 @ 48 Mbps) tcp-brutal 启动延迟赢 7/8 轮,分块 p95 赢 6/8 轮
游戏(ping-pong,60 msg/s) skyline_cc 抖动 5/8 轮,卡顿 >150 ms 4/8 轮
大文件 · 4 并发 skyline_cc 与 tcp-brutal,都领先 bbr 中位数 117 / 115 vs 77 Mbps
大文件 · 单流 bbr 与 skyline_cc 打平,tcp-brutal 垫底 4/8、4/8、0/8 轮;中位数 59 / 53 / 46 Mbps
网页加载 无稳定赢家 逐轮波动大于三者差异
服务端重传率(全部场景累计) bbr 最低 bbr 10.0%、skyline_cc 11.6%、tcp-brutal 12.3%

最能说明三种设计差别的是单流结果。tcp-brutal 发得最多、传得最少:它发出的报文段有 13.9% 是重传,bbr 为 9.9%,skyline_cc 为 11.1%,而它的中位吞吐只有 46 Mbps。 在 10%-30% 丢包下,它固定的 200 Mbps 远高于这条路径能交付的速率,而"丢了就多发"的开环控制把这个差距全部变成了重传。skyline_cc 自己估计速率,没有一个会被设得过高的目标速率。

Note

这是一条链路上的现场测量,不是本仓库正式结论所依据的受控双 VM 测试床,也不代表你的链路。它 70 ms 的 RTT 还低于本项目 100-300 ms 的目标区间,在这个 RTT 下 bbr 从丢包中恢复要容易得多。请把它当作三种算法行为特点的证据,而不是吞吐量跑分。逐轮数据与原始记录见 research/experiments/single-ended/;受控测试床结果见 性能验证报告。

三者的设计差别

bbr tcp-brutal Skyline Speeder
控制结构 闭环,探测带宽 开环:速率由你给定 闭环,自己估带宽
因丢包降速 间接 否 否
需要预知链路带宽 否 是 否
拥塞自保护 有 无 排队时延 + ECN 护栏
形态 内核内置 内核模块(DKMS) eBPF CO-RE,过验证器
内核门槛 任意 5.10 6.12 LTS

如果你知道出口带宽、它基本固定、且内核较老,tcp-brutal 是更简单的答案。Skyline Speeder 适合带宽未知或会变、需要拥塞护栏与可观测性、且能跑 6.12+ 内核的场景。真正拥塞的瓶颈链路上,两者都不合适。

来源: skyline-speeder/docs/usage.md at main · CYBERVERSE-Research/skyline-speeder · GitHub

使用与调参指南(新手向)

这份文档假设你不懂 eBPF、不懂拥塞控制算法,只想把服务器调快。全程复制粘贴即可。

术语只需要知道三个:

  • 丢包:数据包在路上弄丢了。线路噪声造成的叫随机丢包;发太快把设备缓冲撑爆 造成的叫拥塞丢包。本项目只对随机丢包有效。
  • RTT:数据包一来一回的时间,单位毫秒。国内到国外一般 100–300ms。
  • 发送端加速:只装在发数据的那一头(你的服务器)。客户端什么都不用装、不用改。

所以:用户下载会变快,用户上传不会。这是设计如此,不是没生效。

一、先确认你该不该用

用错场景会更慢。花两分钟测一下:

sudo apt-get install -y iperf3 # 对端跑 iperf3 -s,然后从你的服务器发固定速率 UDP iperf3 -c <对端IP> -u -b 100M -t 10 iperf3 -c <对端IP> -u -b 400M -t 10

看 Lost/Total Datagrams 那一列:

测试结果 说明 建议
各速率都稳定丢包(5% 以上) 线路噪声,随机丢包 适合,效果明显
低速不丢,速率一高才丢 你把线路撑满了,拥塞丢包 不适合,可能更糟
各速率都不丢 线路干净 差别不大

Warning

别用 ping 的丢包率判断。 绝大多数网络对 ping 限速,它显示的丢包和真实数据传输 无关。我们实测过一条线路 ping 显示丢 6%,实际 UDP 打到 1.1Gbps 都零丢包。

个人点评:

不错,相当专业,而且还进行了丢包线路实测,skyline-speeder/docs at main · CYBERVERSE-Research/skyline-speeder · GitHub 文档值得细看

个人感觉缺点就是没有实时速率图,有实时速率图就能开始分析速度上升到多少开始丢包,然后这个算法怎么进行补足,补足后效果又如何

bbr tcp-brutal Skyline-Speeder 三张图叠一块就能看出三套算法各自在什么情况下出现了什么不一样的处理