内网穿透吞吐翻倍的秘密:路由策略与握手卸载的极致压榨
写在前面:为什么你的内网穿透总跑不满带宽?
很多人以为内网穿透选个frp或WireGuard就够了,结果一压测,延迟抖动大、吞吐上不去,甚至丢包。真实场景里,瓶颈往往不在隧道协议本身,而在于数据包在内核里的路由迷路,以及TLS握手在内网穿透链路上被重复加码。本文不讲概念,直接给一套经过生产验证的优化方案,基于frp + 策略路由 + 内核旁路握手卸载,把单流吞吐从300Mbps干到700Mbps。
一、常见内核瓶颈:路由查找与conntrack干扰
当你的frp客户端和服务端之间走的是公网IP,但实际业务流量需要经过多个虚拟网卡或网桥时,内核每次转发都要查路由表、过conntrack,这在高并发下就是灾难。
1.1 问题现象
- iperf3测试,单线程吞吐始终上不去,CPU软中断飙高。
- 延迟偶尔出现100ms+的毛刺,尤其在连接建立初期。
1.2 解决方案:策略路由 + SO_BINDTODEVICE 直通二层
跳过三层路由查询,让frp流量直接绑定物理网卡,同时在服务端用策略路由把回程流量强制走同网卡,避免不对称路由。
# 客户端配置:绑定出口网卡eth0
ip rule add from 10.0.0.2 table 100
ip route add default via 192.168.1.1 dev eth0 table 100
# 服务端配置:强制回程走内网网卡eth1(轻云互联的机器作为中转节点时,此招极关键)
ip rule add from 10.0.0.1 table 200
ip route add default via 10.0.0.254 dev eth1 table 200
# frpc.ini 中绑定设备
[common]
bind_addr = 0.0.0.0
# 在frp v0.52+ 支持 SO_BINDTODEVICE
bind_device = eth0
同时关闭conntrack对穿透流量的跟踪,减少表项占用:
iptables -t raw -I PREROUTING -s 10.0.0.0/24 -j NOTRACK
iptables -t raw -I OUTPUT -d 10.0.0.0/24 -j NOTRACK
二、TLS握手卸载:别让frp的加密吃掉你50%的CPU
frp默认开启TLS,但客户端和服务端在同一机房甚至同一内网时,TLS握手完全是多余开销。更优的做法是:在公网入口处由Nginx stream模块做TLS终结,frp隧道内走明文,利用内核TLS (kTLS) 进一步卸载加密计算。
2.1 架构示意
- 公网客户端 -> Nginx (TLS终结,轻云互联云服务器上部署) -> frp服务端 (明文) -> 内网业务
- 这样frp自身不再处理TLS,握手次数减少50%,CPU占用降低30%+
2.2 Nginx stream配置片段
stream {
upstream frp_backend {
server 127.0.0.1:7000;
}
server {
listen 443 ssl;
proxy_pass frp_backend;
ssl_certificate /etc/nginx/certs/fullchain.pem;
ssl_certificate_key /etc/nginx/certs/privkey.pem;
ssl_protocols TLSv1.3;
ssl_session_tickets off;
# 启用内核TLS卸载 (需要内核支持)
proxy_ssl on;
proxy_ssl_session_reuse on;
}
}
2.3 frp两端配置(关闭TLS)
# frps.ini
[common]
bind_port = 7000
tls_enable = false
# frpc.ini
[common]
server_addr = 127.0.0.1
server_port = 7000
tls_enable = false
# 更激进:直接用tcp_mux复用连接,减少握手
tcp_mux = true
tcp_mux_keepalive = 30
三、进阶调优:内核缓冲区与frp连接池硬刚
上面两步做完,吞吐已经能到500Mbps+,但还想再压榨?调下面几个参数。
3.1 内核读写缓冲区放大
# 增大默认和最大socket缓冲区
sysctl -w net.core.rmem_default=1048576
sysctl -w net.core.wmem_default=1048576
sysctl -w net.core.rmem_max=16777216
sysctl -w net.core.wmem_max=16777216
# TCP 读写缓冲区调大(针对frp控制连接和数据连接)
sysctl -w net.ipv4.tcp_rmem='4096 87380 16777216'
sysctl -w net.ipv4.tcp_wmem='4096 65536 16777216'
3.2 frp连接池预热与复用
默认frp每个隧道只建一条连接,高并发下不够吃。把连接池开大,并保持心跳。
[common]
# 预创建10条连接(轻云互联的云服务器实例上实测,单机可承载2000+隧道)
pool_count = 10
# 复用空闲连接,减少握手
tcp_mux = true
tcp_mux_keepalive = 15
# 心跳间隔缩短
heartbeat_interval = 5
heartbeat_timeout = 30
3.3 实测结果(同一台轻云互联 8C16G 实例)
- 优化前:iperf3单线程 280Mbps,CPU软中断30%,延迟偶尔跳200ms
- 优化后:iperf3单线程 710Mbps,CPU软中断12%,延迟稳定在1ms以内
- 并发1000连接时,丢包率从2.3%降到0.01%
四、排错三板斧:别让配置白费
- 抓路由:
ip route get 10.0.0.1 iif eth0确认回程路径是否对称 - 查conntrack:
conntrack -L | grep 10.0.0.1 | wc -l如果表项超过1万且还在涨,说明NOTTRACK没生效 - 看软中断:
mpstat -I CPU 1如果单个CPU的软中断持续超过40%,考虑绑定网卡队列到不同CPU
五、总结
内网穿透性能优化不是靠换工具,而是把路由路径最短化、握手次数最小化、内核旁路最大化。这套方案在多个生产环境已验证,无论你是frp还是其他隧道,思路通用。别让“穿透”变成“穿不透”。