Xray 的 Hysteria2 协商和官方不一样,服务端没填 brutalUp 就按 BBR 跑
本文依据 Xray-core issue #7353(2026 年 11 月 9 日提交)与双方源码整理。issue 作者在同一台机器的回环环境里实测了 8 组对照;官方一侧作者只读了源码、未跑官方程序——原文写明了这一点,本文照实转述,未在本站复现。
现象:只配一端,另一端就失效
Xray 的 Hysteria2 在默认 brutal 模式下,Brutal 的启用条件和官方 Hysteria 不一致:
- 服务端没配
brutalUp时,客户端声明的下行不起作用,下载方向用 BBR; - 服务端没配
brutalDown时,Xray 客户端上传也用 BBR。
也就是说,你在客户端 finalmask.quicParams 里填了 brutalDown: 20 mbps,以为下载会按 20 Mbps 跑 Brutal,实际上只要服务端没填 brutalUp,这一行就等于没写。
代码在哪:两端都是同一行判断
问题出在 Xray 两端的同一行判断上。服务端在 transport/internet/hysteria/hub.go 第 78–83 行,客户端在 transport/internet/hysteria/dialer.go 第 207–212 行(v26.10.31,当前 main 里还是同一段代码):
1 | if quicParams.BrutalUp == 0 || down == 0 { |
两端都要求本端的 brutalUp 和对端声明的值同时不为 0,否则直接用 BBR。
官方是怎么做的:声明即用,上限才卡
官方 Hysteria v2.13.0 的做法不一样(依据官方源码,issue 作者未运行官方程序实测):
- 服务端:客户端声明了下行就使用 Brutal,服务端配了上限时取较小值(
core/server/server.go第 178–196 行); - 客户端:服务端的 Rx 为 0 时,按客户端自己的上行使用 Brutal(
core/client/client.go第 149–162 行)。
差别就一句话:官方是“对端声明了就用 Brutal,己方配置只作上限”,Xray 是“两边都得填,不填一边就回落 BBR”。如果你是从官方 hy2 换到 Xray 的 hysteria 出站/入站,照着官方文档配单边带宽,速度表现会和预期不一样。
8 组实测对照
issue 作者用 Xray 26.10.31 在同一台机器上做了回环实测:本地起一个 HTTP 测速服务,分别测 4 秒下载和上传。这台机器上 BBR 约 150 Mbps,Brutal 组被限制在 20 Mbps 以下——所以表格里的速率本身就是判断依据:
| 服务端 quicParams | 客户端 quicParams | 官方预期 | Xray 下载 | Xray 上传 | Xray 实际 |
|---|---|---|---|---|---|
| 无 | 无 | 两向 BBR | 167.3 | 130.1 | 两向 BBR |
| 无 | brutalDown: 20 mbps |
下载 Brutal 20 | 163.0 | 161.1 | 两向 BBR |
brutalUp: 40 mbps |
brutalDown: 20 mbps |
下载 Brutal 20 | 11.9 | 182.6 | 下载 Brutal |
brutalUp: 20 mbps |
brutalDown: 80 mbps |
下载 Brutal 20 | 11.6 | 156.3 | 下载 Brutal |
brutalUp: 20 mbps |
无 | 两向 BBR | 145.0 | 154.8 | 两向 BBR |
| 无 | brutalUp: 20 mbps |
上传 Brutal 20 | 171.0 | 163.2 | 两向 BBR |
brutalDown: 20 mbps |
brutalUp: 40 mbps |
上传 Brutal 20 | 149.5 | 18.2 | 上传 Brutal |
| 无 | brutalUp、brutalDown 均为 20 mbps |
两向 Brutal 20 | 164.6 | 176.6 | 两向 BBR |
(速率单位 Mbps;表格来自 issue #7353,作者回环实测,未经本站复现)
看第二行和第六行最清楚:客户端单边填了带宽,Xray 两边还是 BBR 的速度;只有两端都填了,对应方向才真的按 Brutal 跑。
怎么判断你是不是撞上了
如果你用的是 Xray 的 Hysteria2 出站或入站(finalmask.quicParams 里配 brutalUp/brutalDown),且出现下面这种现象,可以先按这条排查:
- 客户端填了带宽,速度却卡在 BBR 的水平,怎么调都不提速;
- 检查服务端有没有填对应的
brutalUp/brutalDown——只填一端是不够的; - 两端都填上再测一次,如果对应方向的速度下来了(被限制在设定值附近),说明之前确实在跑 BBR。
代码里另有 force-brutal 分支,不经过这套协商、直接按 brutalUp 用 Brutal;这是代码里看到的选项,本文未实测,是否适合你先看 FinalMask 文档再决定。
注意这条只影响 Xray 的 Hysteria2,官方 hy2 程序不受影响。本站那篇Hysteria2 速度慢怎么办讲的是官方客户端的 bandwidth 写法,那篇的结论不受这条影响——两件事别混在一起。
文档也写错了
FinalMask 文档里写协商行为和 Hysteria brutal 一致,服务端为 0 表示不限制客户端——这和上面那段代码的行为是矛盾的。issue 作者的建议是二选一:要么改行为、要么改文档。如果当前行为是有意设计,至少文档应该写清楚。
现状与影响范围
- issue #7353 于 2026 年 11 月 9 日提交,截至发稿仍是 open 状态,无官方回应、无修复;
- 影响的是用 Xray 跑 Hysteria2 的人:入站和出站都受这套判断管;
- 如果你一直两端都填带宽,这条对你没影响;如果只填一端还觉得速度不对,先按上面三步对照一次。
依据来源
- Xray-core issue #7353(现象描述、8 组实测对照、完整配置与日志):https://github.com/XTLS/Xray-core/issues/7353
- Xray-core
transport/internet/hysteria/hub.go第 78–83 行(服务端判断,v26.10.31):https://github.com/XTLS/Xray-core/blob/v26.10.31/transport/internet/hysteria/hub.go#L78-L83 - Xray-core
transport/internet/hysteria/dialer.go第 207–212 行(客户端判断,v26.10.31):https://github.com/XTLS/Xray-core/blob/v26.10.31/transport/internet/hysteria/dialer.go#L207-L212 - Hysteria 官方
core/server/server.go第 178–196 行(服务端协商,v2.13.0):https://github.com/apernet/hysteria/blob/app/v2.13.0/core/server/server.go#L178-L196 - Hysteria 官方
core/client/client.go第 149–162 行(客户端协商,v2.13.0):https://github.com/apernet/hysteria/blob/app/v2.13.0/core/client/client.go#L149-L162 - Xray FinalMask 文档(quicParams,协商行为与官方一致的说法):https://xtls.github.io/config/transports/finalmask.html#quicparams
- 本站已有文章:Hysteria2 速度慢怎么办:https://vpsjq.com/2026/10/02/hysteria2-slow-speed/