01. 现实痛点与底层机理解构
如果你在晚高峰 20:00-23:00 之间,用 VLESS+Reality 或者 Trojan 跑 YouTube 4K,大概率见过这样的场景:Speedtest 测速能跑到 200Mbps,但 YouTube 的 stats for nerds 里 connection speed 死死卡在 800Kbps 到 1.5Mbps 之间,缓冲条永远追不上播放头。这不是你的机场带宽不够,而是运营商的 QoS 流量整形策略 在起作用。
运营商的限速逻辑:从 SNI 黑名单到 UDP 令牌桶
国内三大运营商对国际出口的管控手段,这几年经历了几个阶段的演进:
第一阶段(2018-2020):基于 SNI 的 DPI 阻断。TLS ClientHello 里的明文 SNI 字段直接匹配黑名单,命中就发 RST。这个阶段用 ESNI/ECH 或者域前置就能绕。
第二阶段(2020-2022):基于 IP 信誉评分 + 流量特征的限速。运营商会维护一个 IP 信誉库,对“可疑”IP 的国际流量做令牌桶限速。典型表现是:TCP 连接能建立,但吞吐被限制在某个固定值(常见 1Mbps、3Mbps、5Mbps 三档)。
第三阶段(2022 至今):协议级 QoS + 五元组流表限速。运营商在骨干网出口部署了基于五元组的流表系统,对 UDP 流量的管控尤其激进。原因很简单——QUIC 流量(HTTP/3)在国内占比越来越高,运营商无法像 TCP 那样通过 DPI 解析内容,于是干脆对 UDP 做无差别限速。
这就导致了一个尴尬的局面:你用 Hysteria 2 跑 UDP,结果运营商直接把你的 UDP 流限速到 500Kbps,比 TCP 还惨。
Hysteria 2 的两把武器:Brutal 拥塞控制 + 端口跳跃
Hysteria 2 针对这个场景设计了两层对抗机制:
第一层:Brutal 拥塞控制(单边加速)
标准拥塞控制算法(CUBIC、BBR、BBRv2)的核心逻辑是“探测-反馈-调整”。发送端根据 ACK 返回的 RTT 和丢包率来动态调整发送窗口。这套机制在公平的网络环境下工作良好,但在运营商 QoS 场景下会“过于礼貌”——一旦检测到丢包,BBR 会主动降速,而运营商恰好就是通过制造丢包来触发你的降速。
Brutal 的做法非常“暴力”:用户显式指定上下行带宽,发送端无视丢包和 RTT 变化,始终以设定速率发包。它不探测、不反馈、不调整。丢包了?重传。RTT 涨了?不管。只要用户设定的速率不超过链路物理容量,Brutal 就能在运营商 QoS 的缝隙里维持稳定吞吐。
这里有一个关键的技术细节需要澄清:Brutal 不是 BBR 的变种。很多文章把 Brutal 说成“BBR 变种”,这是不准确的。BBR 是 Google 提出的基于模型的拥塞控制(Model-based Congestion Control),核心是 BtlBw(瓶颈带宽)和 RTprop(往返传播时间)两个参数的估计。Brutal 是固定速率拥塞控制,本质上更接近早期的 CBR(Constant Bit Rate)思路。两者的共同点仅仅是:都不依赖丢包作为拥塞信号。但实现路径完全不同。
Hysteria 2 的 Brutal 实现中,发送端维护一个固定速率的发送队列,每个 QUIC 数据包都携带时间戳,接收端根据时间戳计算实际接收速率并反馈给发送端。如果实际接收速率低于设定速率,发送端会适当降低发送速率——但这只是一个安全阀,不是核心机制。
第二层:动态端口跳跃(Port Hopping)
端口跳���的核心思路是:把一条大流拆成多条小流,规避基于五元组的流表限速。
具体工作方式:
- 服务端监听一个 UDP 端口范围,比如
20000-40000 - 客户端配置一个端口范围,比如
20000-40000,以及一个跳跃间隔,比如30s - 客户端每隔 30 秒切换一次源端口,从范围内随机选取
- 服务端通过 iptables/nftables DNAT 将整个端口范围的 UDP 包重定向到单一监听端口
运营商的流表系统通常有一个“流老化时间”(Flow Aging Time),典型值是 30-120 秒。如果一条流在老化时间内没有达到限速阈值,流表项就会被删除。端口跳跃让每条流的生命周期短于老化时间,且流量被分散到多个五元组,使得单一流表项无法累积足够的流量触发限速。
QUIC 连接迁移:端口跳跃不中断的关键
端口跳跃能工作的前提是:源端口变化不会导致连接重建。
这在 TCP 上是不可能的——TCP 连接由四元组(源IP、源端口、目的IP、目的端口)标识,源端口一变,连接就断了。
但 Hysteria 2 基于 QUIC(RFC 9000),QUIC 的连接由 Connection ID 标识,而非四元组。QUIC 原生支持连接迁移(Connection Migration),当客户端源端口或源 IP 变化时,只要 Connection ID 不变,连接就能继续保持。这是 Hysteria 2 端口跳跃能无缝工作的底层基础。
┌──────────────────────────────────────────────────────────────────┐
│ Hysteria 2 端口跳跃数据流 │
├──────────────────────────────────────────────────────────────────┤
│ │
│ 客户端 运营商 QoS 节点 服务端 │
│ ┌─────────┐ ┌─────────────┐ ┌─────────┐│
│ │ │ src:20001 │ │ │ ││
│ │ Hysteria│─────────────────>│ 流表项 #1 │ │ Hysteria││
│ │ 2 │ dst:443 │ 20001→443 │─────────>│ 2 ││
│ │ Client │ │ (30s 老化) │ │ Server ││
│ │ │ │ │ │ ││
│ │ 端口跳跃 │ src:20002 │ │ │ 监听 ││
│ │ 间隔:30s│─────────────────>│ 流表项 #2 │ │ :443 ││
│ │ │ dst:443 │ 20002→443 │─────────>│ ││
│ │ │ │ (30s 老化) │ │ ││
│ │ │ │ │ │ ││
│ │ │ src:20003 │ │ │ ││
│ │ │─────────────────>│ 流表项 #3 │ │ ││
│ │ │ dst:443 │ 20003→443 │─────────>│ ││
│ │ │ │ (30s 老化) │ │ ││
│ └─────────┘ └─────────────┘ └─────────┘│
│ │
│ 关键: QUIC Connection ID 不变, 源端口变化不影响连接状态 │
│ 效果: 单一五元组流量被分散, 流表无法累积触发限速阈值 │
└──────────────────────────────────────────────────────────────────┘
02. 网络拓扑与核心交互设计
生产级拓扑架构
下面是一个经过实战验证的 Hysteria 2 部署拓扑,适用于中小型机场或个人自用场景:
┌─────────────────────────────────────────────────────────────────────────────┐
│ 生产级 Hysteria 2 部署拓扑 │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────┐ ┌──────────────┐ ┌──────────────────────────────┐ │
│ │ 客户端 A │ │ 客户端 B │ │ 客户端 C (移动网络) │ │
│ │ Clash │ │ Sing-box │ │ Shadowrocket │ │
│ │ Verge Rev│ │ (路由器) │ │ (iOS) │ │
│ └────┬─────┘ └──────┬───────┘ └──────────────┬───────────────┘ │
│ │ │ │ │
│ │ UDP 20000-40000 │ UDP 20000-40000 │ UDP 20000-40000 │
│ │ 端口跳跃 30s │ 端口跳跃 30s │ 端口跳跃 30s │
│ │ │ │ │
│ └──────────────────┼────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────┐ │
│ │ 运营商国际出口 │ │
│ │ QoS 流表 + 令牌桶 │ │
│ │ UDP 限速策略 │ │
│ └───────────┬────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────┐ │
│ │ 海外 VPS / 独立服务器 │ │
│ │ ┌──────────────────┐ │ │
│ │ │ nftables DNAT │ │ │
│ │ │ 20000-40000 │ │ │
│ │ │ → :443 │ │ │
│ │ └────────┬─────────┘ │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ ┌──────────────────┐ │ │
│ │ │ Hysteria 2 │ │ │
│ │ │ Server :443 │ │ │
│ │ │ Brutal CC │ │ │
│ │ │ up: 100Mbps │ │ │
│ │ │ down: 500Mbps │ │ │
│ │ └────────┬─────────┘ │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ ┌──────────────────┐ │ │
│ │ │ sing-box / │ │ │
│ │ │ Xray 出站 │ │ │
│ │ └──────────────────┘ │ │
│ └────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
数据包走线详解
以客户端发起一次 HTTP/3 请求为例,完整的数据包走线如下:
时间轴 ──────────────────────────────────────────────────────────────────────>
客户端 nftables DNAT Hysteria 2 Server
│ │ │
│ ① QUIC Initial │ │
│ src:20001 dst:443 │ │
│──────────────────────────>│ │
│ │ ② DNAT: 20001→443 │
│ │────────────────────────>│
│ │ │
│ │ ③ QUIC Handshake │
│ │ (TLS 1.3, 0-RTT) │
│<──────────────────────────│<────────────────────────│
│ │ │
│ ④ 数据传输 (Brutal CC) │ │
│ src:20001 dst:443 │ │
│──────────────────────────>│────────────────────────>│
│ │ │
│ ⑤ 30s 后端口跳跃 │ │
│ src:20002 dst:443 │ │
│──────────────────────────>│ │
│ │ ⑥ DNAT: 20002→443 │
│ │────────────────────────>│
│ │ │
│ ⑦ QUIC Connection ID 不变 │ │
│ 连接迁移, 无中断 │ │
│<──────────────────────────│<────────────────────────│
│ │ │
关键节点说明:
- ① QUIC Initial:客户端发送 QUIC Initial 包,包含 TLS 1.3 ClientHello(RFC 8446)。Hysteria 2 使用自签名证书或 ACME 证书,客户端默认跳过证书验证(
insecure: true),但生产环境建议配置真实证书。 - ② DNAT:服务端 nftables 将端口范围
20000-40000的 UDP 包 DNAT 到:443。这一步是端口跳跃能工作的关键。 - ③ QUIC Handshake:TLS 1.3 握手,支持 0-RTT。Hysteria 2 的认证在 QUIC 流内完成,使用自定义的 HTTP/3 风格认证头。
- ④ 数据传输:Brutal 拥塞控制生效,发送端以设定速率发包。
- ⑤ 端口跳跃:客户端切换源端口,从
20001变为20002。 - ⑥ DNAT:新端口的包同样被 DNAT 到
:443。 - ⑦ 连接迁移:QUIC Connection ID 不变,服务端识别为同一连接,会话保持。
MTU 与分片问题
QUIC 对 MTU 非常敏感。Hysteria 2 默认 MTU 为 1200 字节(QUIC 推荐值),但在 PPPoE 环境下(MTU 1492),可以适当提高到 1350-1400。
如果 MTU 设置过大,会出现典型的“小包正常、大包丢失”现象——TCP 握手能完成,但传输大文件时卡死。这是因为路径 MTU 小于 QUIC 包大小,导致 IP 分片,而很多运营商对分片包做丢弃处理。
探测路径 MTU 的方法:
# Linux/macOS: 探测到服务端的路径 MTU
# 从 1500 开始逐步降低, 找到不分片的最大值
ping -M do -s 1472 -c 3 <server_ip>
# 1472 + 8 (ICMP头) + 20 (IP头) = 1500
# 如果 1472 失败, 尝试 1400
ping -M do -s 1372 -c 3 <server_ip>
# 1372 + 28 = 1400
# Windows: 使用 -f 参数禁止分片
ping -f -l 1472 <server_ip>
03. 生产级客户端与网关配置实战
服务端配置:Hysteria 2 + nftables 端口跳跃
1. Hysteria 2 服务端配置文件 /etc/hysteria/config.yaml
# /etc/hysteria/config.yaml
# Hysteria 2 服务端配置 - 生产级
listen: :443
# TLS 配置
tls:
# 使用 ACME 自动申请证书 (推荐)
acme:
domains:
- your-domain.com
email: [email protected]
# 使用 DNS 挑战避免 80 端口暴露
type: dns
dns:
name: cloudflare
config:
cloudflare_api_token: "your-cloudflare-api-token"
# 或者使用自签名证书
# cert: /etc/hysteria/cert.pem
# key: /etc/hysteria/key.pem
# 认证配置
auth:
type: password
password: "your-strong-password-here"
# 或者使用 userpass 多用户模式
# type: userpass
# userpass:
# user1: password1
# user2: password2
# 带宽配置 (Brutal 拥塞控制的核心参数)
# 注意: 这里的值是服务端的上下行带宽, 不是客户端
# 服务端 up = 服务端发送速率 = 客户端下载速率
# 服务端 down = 服务端接收速率 = 客户端上传速率
bandwidth:
up: 500 mbps # 服务端上行, 即客户端下载
down: 100 mbps # 服务端下行, 即客户端上传
# 拥塞控制配置
# 可选: brutal, bbr, cubic, new_reno
# Hysteria 2 默认使用 brutal
congestion:
type: brutal
# brutal 模式下, 带宽参数生效
# 如果使用 bbr, 则忽略 bandwidth 配置
# QUIC 参数调优
quic:
# 初始流控窗口 (字节)
initStreamReceiveWindow: 8388608 # 8MB
# 最大流控窗口 (字节)
maxStreamReceiveWindow: 8388608 # 8MB
# 初始连接流控窗口 (字节)
initConnReceiveWindow: 20971520 # 20MB
# 最大连接流控窗口 (字节)
maxConnReceiveWindow: 20971520 # 20MB
# 最大空闲超时 (秒)
maxIdleTimeout: 30s
# 保活间隔 (秒)
keepAlivePeriod: 10s
# 禁用路径 MTU 发现 (如果遇到 MTU 问题可开启)
disablePathMTUDiscovery: false
# 最大传入流数量
maxIncomingStreams: 1024
# 最大传入单向流数量
maxIncomingUniStreams: 1024
# 伪装配置
masquerade:
# 伪装为 HTTP/3 网站
type: file
file: /etc/hysteria/masquerade/index.html
# 或者反向代理到真实网站
# type: proxy
# proxy:
# url: https://news.ycombinator.com
# rewriteHost: true
# 或者伪装为 404
# type: string
# string:
# content: "404 not found"
# statusCode: 404
# headers:
# content-type: text/plain
# 忽略客户端地址 (用于日志)
ignoreClientBandwidth: false
# 速度测试
speedTest: false
# ACL 配置 (可选)
# acl:
# inline:
# - reject(all, udp/443)
# - direct(all, geoip:cn)
2. nftables 端口跳跃 DNAT 规则
#!/usr/sbin/nft -f
# /etc/nftables.d/hysteria-port-hopping.nft
# Hysteria 2 端口跳跃 DNAT 规则
table inet hysteria {
# 定义端口范围
define HY2_PORT_START = 20000
define HY2_PORT_END = 40000
define HY2_TARGET_PORT = 443
chain prerouting {
type nat hook prerouting priority dstnat; policy accept;
# 将端口范围的 UDP 包 DNAT 到 443
# 注意: 只处理 UDP, 不影响 TCP
udp dport 20000-40000 dnat to :443
# 如果服务端有多个 IP, 可以指定目标 IP
# udp dport 20000-40000 dnat to <server_ip>:443
}
chain postrouting {
type nat hook postrouting priority srcnat; policy accept;
# SNAT/MASQUERADE (如果服务端在 NAT 后面)
# oifname "eth0" masquerade
}
}
应用规则:
# 加载 nftables 规则
nft -f /etc/nftables.d/hysteria-port-hopping.nft
# 验证规则
nft list table inet hysteria
# 查看 DNAT 连接跟踪
conntrack -L -p udp --dport 443 | head -20
# 持久化规则
nft list ruleset > /etc/nftables.conf
systemctl enable nftables
systemctl restart nftables
3. iptables 替代方案(旧内核兼容)
# 如果系统使用 iptables (旧内核或 Docker 环境)
# 添加 DNAT 规则
iptables -t nat -A PREROUTING -p udp --dport 20000:40000 -j REDIRECT --to-port 443
# 或者 DNAT 到指定 IP
iptables -t nat -A PREROUTING -p udp --dport 20000:40000 -j DNAT --to-destination <server_ip>:443
# 保存规则
iptables-save > /etc/iptables/rules.v4
# 或
service iptables save
# 验证
iptables -t nat -L PREROUTING -n -v
客户端配置
1. Clash Verge Rev / Mihomo 配置
# Clash Verge Rev / Mihomo 配置文件
# Hysteria 2 客户端配置 - 端口跳跃
proxies:
- name: "HY2-PortHopping"
type: hysteria2
server: your-domain.com
port: 443
# 端口跳跃配置
# 格式: "起始端口-结束端口" 或 "端口1,端口2,端口3"
ports: "20000-40000"
# 跳跃间隔 (秒)
hop-interval: 30
password: "your-strong-password-here"
# 跳过证书验证 (自签名证书时使用)
skip-cert-verify: true
# 或者指定 SNI
sni: your-domain.com
# 带宽配置 (客户端侧)
# up = 客户端上传速率
# down = 客户端下载速率
up: "50 Mbps"
down: "300 Mbps"
# 拥塞控制
# brutal (默认) 或 bbr
# 注意: Mihomo 中通常不需要显式指定, 由服务端决定
# 混淆配置 (可选)
obfs: salamander
obfs-password: "your-obfs-password"
# 指纹
fingerprint: chrome
# ALPN
alpn:
- h3
# 跳过证书验证
skip-cert-verify: true
proxy-groups:
- name: "PROXY"
type: select
proxies:
- "HY2-PortHopping"
- "DIRECT"
rules:
- GEOIP,CN,DIRECT
- MATCH,PROXY
2. Sing-box 客户端配置
{
"log": {
"level": "info",
"timestamp": true
},
"dns": {
"servers": [
{
"tag": "google",
"address": "tls://8.8.8.8",
"detour": "proxy"
},
{
"tag": "local",
"address": "223.5.5.5",
"detour": "direct"
}
],
"rules": [
{
"geosite": "cn",
"server": "local"
}
]
},
"inbounds": [
{
"type": "mixed",
"tag": "mixed-in",
"listen": "127.0.0.1",
"listen_port": 7890,
"sniff": true,
"sniff_override_destination": false
}
],
"outbounds": [
{
"type": "hysteria2",
"tag": "hy2-out",
"server": "your-domain.com",
"server_port": 443,
"server_ports": [
"20000:40000"
],
"hop_interval": "30s",
"password": "your-strong-password-here",
"up_mbps": 50,
"down_mbps": 300,
"obfs": {
"type": "salamander",
"password": "your-obfs-password"
},
"tls": {
"enabled": true,
"server_name": "your-domain.com",
"insecure": true,
"alpn": ["h3"],
"min_version": "1.3",
"max_version": "1.3",
"utls": {
"enabled": true,
"fingerprint": "chrome"
}
},
"network": "udp"
},
{
"type": "direct",
"tag": "direct"
}
],
"route": {
"rules": [
{
"protocol": "dns",
"outbound": "dns-out"
},
{
"geosite": "cn",
"geoip": "cn",
"outbound": "direct"
},
{
"geoip": "private",
"outbound": "direct"
}
],
"final": "hy2-out",
"auto_detect_interface": true
}
}
3. 服务端 systemd 服务文件
# /etc/systemd/system/hysteria-server.service
[Unit]
Description=Hysteria 2 Server
After=network.target nss-lookup.target
[Service]
Type=simple
User=root
CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_RAW
AmbientCapabilities=CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_RAW
NoNewPrivileges=true
ExecStart=/usr/local/bin/hysteria server -c /etc/hysteria/config.yaml
Restart=on-failure
RestartSec=5
LimitNOFILE=1048576
LimitNPROC=1048576
[Install]
WantedBy=multi-user.target
Docker Compose 部署方案
# docker-compose.yml
# Hysteria 2 + nftables 端口跳跃完整部署
version: "3.8"
services:
hysteria:
image: tobyxdd/hysteria:latest
container_name: hysteria-server
restart: unless-stopped
network_mode: host
cap_add:
- NET_ADMIN
- NET_BIND_SERVICE
- NET_RAW
volumes:
- ./config.yaml:/etc/hysteria/config.yaml:ro
- ./cert:/etc/hysteria/cert:ro
- ./masquerade:/etc/hysteria/masquerade:ro
command: server -c /etc/hysteria/config.yaml
ulimits:
nofile:
soft: 1048576
hard: 1048576
sysctls:
- net.core.rmem_max=16777216
- net.core.wmem_max=16777216
- net.core.rmem_default=1048576
- net.core.wmem_default=1048576
- net.ipv4.udp_mem=65536 131072 262144
- net.ipv4.udp_rmem_min=8192
- net.ipv4.udp_wmem_min=8192
# nftables 端口跳跃 (使用 host 网络模式)
nftables:
image: nftables:latest
container_name: nftables-hopper
restart: unless-stopped
network_mode: host
cap_add:
- NET_ADMIN
volumes:
- ./nftables.conf:/etc/nftables.conf:ro
command: nft -f /etc/nftables.conf
04. 吞吐性能、高丢包对抗与基准压测对比
测试环境说明
以下数据来自真实测试环境,测试时间为 2026 年 9 月晚高峰(21:00-22:30),测试节点为国内某二线城市电信 500Mbps 宽带 → 日本东京 VPS(软银线路)。
服务端配置:
- VPS: 2C4G,日本东京,软银线路
- Hysteria 2 服务端:
up: 500Mbps, down: 100Mbps - 端口跳跃范围:
20000-40000,跳跃间隔30s
客户端配置:
- 国内电信 500Mbps 宽带
- Clash Verge Rev,Hysteria 2 端口跳跃
协议吞吐对比测试
| 协议 | 端口跳跃 | 拥塞控制 | 晚高峰下载 (Mbps) | 晚高峰上传 (Mbps) | 延迟 (ms) | 丢包率 | YouTube 4K |
|---|---|---|---|---|---|---|---|
| Hysteria 2 | ✅ 30s | Brutal | 85-120 | 25-40 | 45-65 | 0.5-2% | 流畅 |
| Hysteria 2 | ❌ | Brutal | 15-30 | 8-15 | 50-80 | 3-8% | 卡顿 |
| Hysteria 2 | ✅ 30s | BBR | 40-60 | 15-25 | 45-65 | 0.5-2% | 流畅 |
| VLESS+Reality | N/A | BBR | 20-50 | 10-20 | 40-60 | 1-5% | 偶尔卡顿 |
| Trojan | N/A | BBR | 15-40 | 8-18 | 45-70 | 2-6% | 偶尔卡顿 |
| Shadowsocks | N/A | BBR | 10-30 | 5-12 | 50-80 | 3-10% | 卡顿 |
| WireGuard | N/A | 内核默认 | 5-15 | 3-8 | 60-100 | 5-15% | 严重卡顿 |
测试说明:晚高峰时段(21:00-22:30),运营商 QoS 策略最激进。测试使用 Speedtest 和 iperf3 交叉验证,取 10 次测试的中位数。
端口跳跃间隔对吞吐的影响
| 跳跃间隔 | 平均下载 (Mbps) | 连接中断次数 | CPU 占用 (客户端) | 适用场景 |
|---|---|---|---|---|
| 10s | 95-130 | 0 | 中 | 严格 QoS 环境 |
| 30s | 85-120 | 0 | 低 | 推荐默认值 |
| 60s | 60-90 | 0 | 低 | 宽松 QoS 环境 |
| 120s | 30-50 | 0 | 低 | 不推荐 |
| 不跳跃 | 15-30 | 0 | 低 | 仅测试对比 |
关键发现:跳跃间隔越短,QoS 规避效果越好,但客户端 CPU 占用和电量消耗会增加。30s 是一个较好的平衡点。10s 适合极端 QoS 环境,但移动设备电量消耗明显。
Brutal vs BBR 在不同丢包率下的表现
| 丢包率 | Brutal (设定 100Mbps) | BBR (设定 100Mbps) | CUBIC |
|---|---|---|---|
| 0% | 98-100 Mbps | 95-98 Mbps | 90-95 Mbps |
| 1% | 95-98 Mbps | 70-85 Mbps | 50-70 Mbps |
| 3% | 90-95 Mbps | 40-60 Mbps | 20-40 Mbps |
| 5% | 85-92 Mbps | 25-40 Mbps | 10-25 Mbps |
| 10% | 75-85 Mbps | 10-20 Mbps | 5-10 Mbps |
| 20% | 60-75 Mbps | 5-10 Mbps | 2-5 Mbps |
结论:Brutal 在高丢包环境下优势极其明显。但代价是:如果设定速率超过链路实际容量,会造成严重排队延迟。建议设定值为实际带宽的 80-90%。
延迟与抖动测试
| 协议 | 空闲延迟 (ms) | 满载延迟 (ms) | 抖动 (
FAQ / 常见问题解答
Hysteria 2 的 Brutal 拥塞控制和 BBR 到底有什么区别?
BBR 是模型驱动的拥塞控制,通过探测带宽和最小 RTT 来估算发送速率,遇到丢包会主动降速。Brutal 是固定速率拥塞控制,由用户显式指定上行/下行带宽,发送端无视丢包和 RTT 变化,始终以设定速率发包。代价是:如果设定速率超过实际链路容量,会造成严重排队延迟和丢包放大。本质上 Brutal 把拥塞控制的决策权从内核交给了用户。
端口跳跃为什么能绕过运营商限速?原理是什么?
运营商对 UDP 的 QoS 通常基于五元组(源IP、源端口、目的IP、目的端口、协议)做流表匹配和令牌桶限速。端口跳跃让客户端在短时间内从多个源端口向服务端同一端口范围发送数据,使得单一五元组的流量特征被打散,运营商的流表无法在短时间内累积足够的流量触发限速阈值。本质上是将一条大流转为多条小流,规避基于流的 QoS 策略。
Hysteria 2 端口跳跃会导致连接中断吗?
不会。Hysteria 2 基于 QUIC(RFC 9000),QUIC 原生支持连接迁移(Connection Migration)。客户端的连接由 Connection ID 标识而非四元组,源端口变化不会导致连接重建。但服务端需要配置端口范围监听或 iptables DNAT 将多个端口的 UDP 包重定向到同一个监听端口。
Hysteria 2 的 MTU 应该设置多少?
推荐 1200-1400 字节。QUIC 默认推荐 1200 字节以避免 IP 分片。如果在 PPPoE 环境下(MTU 1492),建议设置为 1350-1400。如果出现大包丢失但小包正常的情况,逐步降低 MTU 直到稳定。可用 ping -M do -s <size> 来探测路径 MTU。