v2ray 性能与稳定性优化记录
起因:v2ray 频繁出现
websocket: close 1006 (abnormal closure): unexpected EOF+common/mux: failed to ...三连日志,伴随偶发掉连。
范围:mux 多路复用、Sockopt TCP 选项、Linux 服务端内核参数。
未改项:传输协议、TLS、Sniffing、路由、DNS、Policy、loglevel 保持原状。
改动概览
| # | 项 | 端 | 改动 | 需重启 |
|---|---|---|---|---|
| 1 | Mux | 客户端 | 关闭 (enabled: false) | v2ray |
| 2 | Sockopt | 客户端 + 服务端 | 启用 TFO / KeepAlive / NoDelay;服务端额外指定 tcpcongestion: bbr | v2ray |
| 3 | 内核 sysctl + systemd | 服务端 | BBR+fq、TFO=3、收发缓冲区、连接队列、fd 上限 | sysctl 实时生效;systemd 改 NOFILE 需 daemon-reload + restart |
一、Mux 多路复用:关闭
背景
Mux 把多条逻辑流复用到一条底层 TCP/WS 连接。一旦底层连接被 CDN / 中间设备断开,所有复用流同时报错——这就是日志里 1006 后跟一片 closed pipe 的根源。走 CDN 或长距离弱网时,关 mux 比开启更稳。
配置位置
仅客户端 config.json 的 outbounds[],每个 vmess/vless 出口节点都加:
"outbounds": [{
"protocol": "vmess",
"settings": { /* ... */ },
"streamSettings": { /* ... */ },
"mux": {
"enabled": false
}
}]服务端 inbound 没有对应的 mux 开关,自动识别并解复用,不需要改服务端。
操作步骤
编辑客户端 v2ray 配置:
Windows v2rayN:UI 节点编辑界面将 "Mux" 关闭,或直接编辑
guiNConfig.jsonLinux/macOS:
/usr/local/etc/v2ray/config.json或~/.config/v2ray/config.json其它 UI(Qv2ray / Nekobox / Clash Meta):在节点设置里关闭 Mux
保存后重启客户端:
# systemd sudo systemctl restart v2ray # GUI 客户端:在系统托盘菜单选 "重启" 或重连节点
验证
日志级别保持
warning时,不应再出现成对的common/mux: failed to fetch all input/failed to process data。老的偶发
1006仍可能出现(取决于上游链路),但不再"一断连一片"。
回滚
把 "enabled": false 改回 true(或删除整个 mux 块走默认),重启 v2ray。
二、Sockopt:双端开启 TCP 调优
背景
让 v2ray 在创建 socket 时开启 TCP Fast Open、KeepAlive、TCP_NODELAY,并指定服务端发送方向的拥塞控制为 BBR。注意 必须双端都配 才能完整生效(TFO 要双端协商;BBR 设在哪端,那端发送时才走 BBR)。
配置位置
客户端 outbounds[].streamSettings:
"outbounds": [{
"streamSettings": {
"sockopt": {
"tcpFastOpen": true,
"tcpKeepAliveInterval": 30,
"tcpKeepAliveIdle": 300,
"tcpNoDelay": true
}
}
}]服务端 inbounds[].streamSettings(额外加 tcpcongestion):
"inbounds": [{
"streamSettings": {
"sockopt": {
"tcpFastOpen": true,
"tcpKeepAliveInterval": 30,
"tcpKeepAliveIdle": 300,
"tcpNoDelay": true,
"tcpcongestion": "bbr"
}
}
}]字段说明
| 字段 | 作用 | 备注 |
|---|---|---|
tcpFastOpen | 启用 TFO,三次握手最后一包就带数据,省 1 个 RTT | 需双端 + 内核 tcp_fastopen=3 配合 |
tcpKeepAliveIdle | 多久空闲后开始发心跳(秒) | 300s |
tcpKeepAliveInterval | 心跳间隔(秒) | 30s,可对抗 NAT / CDN idle 超时 |
tcpNoDelay | 关闭 Nagle,小包立即发出 | 降低小请求延迟 |
tcpcongestion | 拥塞算法 | 仅 Linux 有效,设在发送端;代理下载方向大头是服务端发,故服务端配 bbr |
操作步骤
客户端:在 outbound 加
sockopt块。服务端:在 inbound 加
sockopt块(含tcpcongestion: "bbr")。验证配置语法:
/usr/local/bin/v2ray test -config /usr/local/etc/v2ray/config.json
重启服务:
sudo systemctl restart v2ray
验证
# 服务端确认 v2ray 启动无错 sudo journalctl -u v2ray -n 50 --no-pager # 内核层 TFO 是否启用(不开内核 TFO,sockopt 也无效) sysctl net.ipv4.tcp_fastopen # 期望 3
可选:用 tcpdump 抓 SYN 包确认 TFO Cookie:
sudo tcpdump -i any -nn 'tcp[tcpflags] & tcp-syn != 0' -vv # 关注输出里是否出现 "tfo cookie"
回滚
删除 sockopt 块整体,或将关心的字段单独置 false / 移除,重启 v2ray。
三、Linux 服务端内核参数
背景
长肥管道(高带宽 + 高 RTT)下 Linux 默认的 cubic + 约 6MB 缓冲跑不满线路;高并发新连接也会撞默认 somaxconn=128 与 LimitNOFILE=1024 上限。本节全部在服务端 Linux 主机上操作,与 v2ray 配置文件无关。
配置位置
新建 /etc/sysctl.d/99-v2ray.conf
或者在/etc/sysctl.conf追加下面内容也可以,然后systemctl -p也可以
# ---- 拥塞控制(吞吐量提升最大)---- net.core.default_qdisc = fq net.ipv4.tcp_congestion_control = bbr # ---- TCP Fast Open(与 sockopt 配合)---- net.ipv4.tcp_fastopen = 3 # ---- 缓冲区(长肥管道)---- net.core.rmem_max = 26214400 net.core.wmem_max = 26214400 net.ipv4.tcp_rmem = 4096 87380 26214400 net.ipv4.tcp_wmem = 4096 16384 26214400 # ---- 连接队列 ---- net.core.somaxconn = 4096 net.ipv4.tcp_max_syn_backlog = 8192 net.ipv4.tcp_tw_reuse = 1 # ---- 文件描述符(系统级)---- fs.file-max = 1000000
修改 systemd 服务(/etc/systemd/system/v2ray.service 或 /lib/systemd/system/v2ray.service),在 [Service] 段加:
[Service] LimitNOFILE=1000000
⚠️ 小内存机器(< 1 GB)需按比例下调缓冲区,否则连接数一多 OOM。 ⚠️ 容器场景:
sysctl改的是宿主机内核,容器要么用--privileged,要么docker run --sysctl ...显式声明。
操作步骤
# 1. 加载 sysctl 配置(不需要重启系统) sudo sysctl --system # 2. 若 BBR 模块未自动加载 sudo modprobe tcp_bbrecho tcp_bbr | sudo tee /etc/modules-load.d/bbr.conf # 开机自加载 # 3. systemd 改动必须 daemon-reload + restart,光改文件无效 sudo systemctl daemon-reload sudo systemctl restart v2ray
验证
逐项检查:
# BBR sysctl net.ipv4.tcp_congestion_control # 期望: bbr sysctl net.core.default_qdisc # 期望: fq lsmod | grep tcp_bbr # 期望有输出 # TFO 内核层 sysctl net.ipv4.tcp_fastopen # 期望: 3 # 缓冲区 sysctl net.core.rmem_max # 期望: 26214400 sysctl net.ipv4.tcp_rmem # 期望: 4096 87380 26214400 # 连接队列 sysctl net.core.somaxconn # 期望: 4096 sysctl net.ipv4.tcp_max_syn_backlog # 期望: 8192 # fd 系统级 sysctl fs.file-max # 期望: 1000000 # fd 进程级(最容易漏的一项) cat /proc/$(pgrep -n v2ray)/limits | grep "Max open files" # 期望: Max open files 1000000 1000000
一键自查脚本:
cat <<'EOF' | sudo bash echo "=== BBR ===" sysctl net.ipv4.tcp_congestion_control net.core.default_qdisc lsmod | grep -E "^tcp_bbr" || echo "[!] bbr module NOT loaded" echo; echo "=== TFO & buffers ===" sysctl net.ipv4.tcp_fastopen net.core.rmem_max net.core.wmem_max sysctl net.ipv4.tcp_rmem net.ipv4.tcp_wmem echo; echo "=== Conn queue ===" sysctl net.core.somaxconn net.ipv4.tcp_max_syn_backlog net.ipv4.tcp_tw_reuse echo; echo "=== File limits ===" sysctl fs.file-max PID=$(pgrep -n v2ray) if [ -n "$PID" ]; then grep "Max open files" /proc/$PID/limits else echo "[!] v2ray process not running" fi EOF
回滚
# 撤销 sysctl sudo rm /etc/sysctl.d/99-v2ray.conf sudo sysctl --system # 撤销 systemd 改动:删除 LimitNOFILE 那一行 sudo systemctl daemon-reload sudo systemctl restart v2ray
常见踩坑速查
| 现象 | 原因 | 处理 |
|---|---|---|
sysctl: cannot stat .../tcp_bbr | 内核版本 < 4.9 | uname -r 确认,升级内核 |
| BBR 设了 sysctl 但仍显示 cubic | tcp_bbr 模块未加载 | modprobe tcp_bbr + 写入 /etc/modules-load.d/bbr.conf |
LimitNOFILE=1000000 但 /proc/$PID/limits 仍 1024 | 没 daemon-reload,或没 restart 服务,或服务文件路径不对 | systemctl cat v2ray 确认 systemd 实际读的文件 |
| 容器内 sysctl 报 read-only | 容器无内核权限 | 宿主机改,或 docker run --sysctl net.ipv4.tcp_fastopen=3 ... |
| TFO 仍不生效 | 客户端 / 服务端 / 内核 三处缺一 | 三处都开(sockopt 双端 + tcp_fastopen=3) |
| 关 mux 后速度变慢但更稳 | 预期行为,mux 本就是用稳定性换吞吐 | 直连快线可重新开 mux;走 CDN 保持关闭 |
发表评论