使用OpenVPN一段时间,发现Windows客户端速度一直远小于Linux客户端。我的网络环境两边都是百兆IPv6共享接入服务端是
OpenVZ
VPS。linux下客户端和服务端单个TCP连接速度在500KB/s上下波动,通过OpenVPN后速度差别不大。未优化时,Windows下速度明
显降低,全局下载带宽只能到100KB/s左右。优化后部分问题能够得到明显改善。
OpenVPN有TCP和UDP两种连接方式,虽然OpenVPN over TCP不被推荐。
Windows下情况有些复杂,对于IPv6 TCP,Vista/Win7没有问题但之前版本Windows处理得很不好。首先Windows Server 2003系统下有个BUG,见KB966321, 简单说被动打开的TCP连接接收窗口大小固定为16384且不随注册表项相应的设定值影响。我发现XP情况更坏,所有IPv6 TCP连接窗口大小都固定为最大44800,在我这里260ms的RTT下,单IPv6 TCP连接的带宽最大只有约160KB/s,该问题尚未解决。微软并未发布Win32 XP平台的补丁。
关于RTT、TCP窗口和最大带宽的关系,在IP数据包没有发生失序的情况下,最大带宽发生在RTT时间内对方发送数据流填满整个TCP接收窗口,比如我的情况,
Windows下IPv4 TCP也可能存在问题,XP默认没有开启TCP窗口扩大选项,最大窗口限制为65535,往返时间RTT=260ms时,
使用IPv4 UDP或IPv6 UDP模式应该修改rcvbuf,在OpenVPN的配置文件中加入
rcvbuf选项指Windows UDP套接字的接收缓冲区大小。对OpenVPN速度影响非常明显,尤其对于单核处理器。我的PC是2003年的Pentium 4-M,在优化前整体速度很难超过100KB/s,而此时加上其他应用,CPU使用率还不到30%。优化后与linux下接近(~500KB/s)。设置 过小影响速度的原因可能是内核接收UDP数据包过快填满缓冲区而OpenVPN尚未去读取造成丢包。
要求服务端配置文件使用ccd固定每个客户的IP地址与网关地址,
当VPN连接时,静态路由由于TAP-Win32设备的打开而自动生效,关闭时相应静态路由不起作用,仍使用原路由/默认网关。静态路由保存于注册表
开启comp-lzo,本身针对数据包的lzo的压缩率并不好,但是如果大量空白数据在传输的话,作用还是非常明显的。
(1)VPS等环境下,cpu被共享,服务器能用于压缩和加密的计算资源不多
(2)客户端设备繁多,可能存在性能瓶颈。
对SSL,OpenVPN先查看可用的加密方法:
注意区别于
后者是指在交换密钥时用到的加密方法,而前者是指对于数据通道的加密方法。前者真正影响传输性能。
速度比较快的加密方法也只有bf-cbc和aes-128-cbc两种。然后分别在服务端和客户端进行一下OpenSSL性能测试,Win下的OpenSSL在OpenVPN安装目录下的bin文件夹内。
根据实际速度选择合适的加密算法,然后在服务器和客户端的openvpn配置文件中用cipher BF-CBC或者cipher
AES-128-CBC指明,服务端和客户端配置文件都需要更改。注意部分Intel i5/i7和AMD的Bulldozer处理器支持AES-NI指令集,搭配OpenSSL的AES-NI补丁可以将AES-128-CBC的速度提升7倍。
对lzo我没有找到简单科学的的测试方法,我的测试方法是运行
然后把上面的结果处以top里面看到的lzop的cpu占用率,得到lzop真实效率。在我的测试中,Xeon(R) CPU X3220@2.40GHz的一个核心上,占用14%的cpu时间,只能处理5.0MB/s的压缩。官方的数据在这里。
OpenVPN有TCP和UDP两种连接方式,虽然OpenVPN over TCP不被推荐。
优化Windows TCP接收窗口(RWIN)
作用有二,优化运行于OpenVPN上的TCP连接,在使用TCP模式时优化OpenVPN所使用的TCP连接。这里Vista/Win7无需优化。Windows下情况有些复杂,对于IPv6 TCP,Vista/Win7没有问题但之前版本Windows处理得很不好。首先Windows Server 2003系统下有个BUG,见KB966321, 简单说被动打开的TCP连接接收窗口大小固定为16384且不随注册表项相应的设定值影响。我发现XP情况更坏,所有IPv6 TCP连接窗口大小都固定为最大44800,在我这里260ms的RTT下,单IPv6 TCP连接的带宽最大只有约160KB/s,该问题尚未解决。微软并未发布Win32 XP平台的补丁。
关于RTT、TCP窗口和最大带宽的关系,在IP数据包没有发生失序的情况下,最大带宽发生在RTT时间内对方发送数据流填满整个TCP接收窗口,比如我的情况,
最大带宽=RWIN/RTT=44800Bytes/260ms=168KB/s,与实测接近。
Windows下IPv4 TCP也可能存在问题,XP默认没有开启TCP窗口扩大选项,最大窗口限制为65535,往返时间RTT=260ms时,
单TCP连接带宽=65536Bytes/260ms=246KB/s如何调整窗口大小及开启窗口扩大选项见KB224829,也可用TCP Optimizer,调整后,单TCP连接速度与Linux接近。如上所述,该方法对IPv6 TCP无效。Vista/Win7系列无需修改,窗口扩大选项默认已经打开。
优化OpenVPN接收缓冲区大小
这个优化可以避免Win32下OpenVPN的UDP接口默认缓冲区太小,导致丢包的问题。无论是XP/Vista/Win7,都建议设置。使用IPv4 UDP或IPv6 UDP模式应该修改rcvbuf,在OpenVPN的配置文件中加入
rcvbuf 65536rcvbuf最大可取到999999,超过这个值或者未设定,rcvbuf=8192。
rcvbuf选项指Windows UDP套接字的接收缓冲区大小。对OpenVPN速度影响非常明显,尤其对于单核处理器。我的PC是2003年的Pentium 4-M,在优化前整体速度很难超过100KB/s,而此时加上其他应用,CPU使用率还不到30%。优化后与linux下接近(~500KB/s)。设置 过小影响速度的原因可能是内核接收UDP数据包过快填满缓冲区而OpenVPN尚未去读取造成丢包。
设置OpenVPN的mssfix选项
建议设置OpenVPN的mssfix选项,这个选项限制VPN隧道上的TCP连接的MSS(Maximum Segment Size)(OpenVPN的mssfix与TCP的mssfix似乎并不等同,具体还是参考OpenVPN官方文档)。以我的情况为例,服务器端网卡 venet0的MTU为1500,IPv6由TunnelBroker接入,故IPv6最大包长等于1500减去封装其的20字节IP首部等于1480, 再减去IPv6的40字节首部等于1440,然后则减去8字节UDP首部等于1432。若为IPv4 UDP,mssfix等于1500减去20字节IP首部再减去8字节UDP首部等于1472。#for UDP6 mssfix 1432 #for UDP mssfix 1472设置后可防止单个IP片经过OpenVPN时被再次分两个数据包发送。但对于丢包率极低的链路,优化mssfix作用不大。
使用路由表
配合路由表,将需要的流量导入VPN。以前提过动态路由RIP over OpenVPN偶尔会不稳定,建议还是使用静态路由:1 | route.exe -p ADD 8.0.0.0 MASK 252.0.0.0 10.8.0.5 METRIC 40 |
client-config-dir ccd服务器ccd文件夹下建立clinet1,内容:
1 | ifconfig -push 10.8.0.6 10.8.0.5 |
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\PersistentRoutes不随接口启动/断开或关机而消失。
几个细节
无论是服务端还是客户端,OpenVPN的verb选项都不应过大,verb提供Debug信息,过大可能导致Debug信息的写入占用过多磁盘IO或者CPU资源。开启comp-lzo,本身针对数据包的lzo的压缩率并不好,但是如果大量空白数据在传输的话,作用还是非常明显的。
OpenSSL加密与LZO压缩的影响(2011年1月2日更新)
对于不是特别古老的CPU,这两项都不会成为性能瓶颈。然而:(1)VPS等环境下,cpu被共享,服务器能用于压缩和加密的计算资源不多
(2)客户端设备繁多,可能存在性能瓶颈。
对SSL,OpenVPN先查看可用的加密方法:
1 | openvpn --show-ciphers |
1 | openvpn --show-tls |
速度比较快的加密方法也只有bf-cbc和aes-128-cbc两种。然后分别在服务端和客户端进行一下OpenSSL性能测试,Win下的OpenSSL在OpenVPN安装目录下的bin文件夹内。
1 | openssl speed bf-cbc aes-128-cbc |
对lzo我没有找到简单科学的的测试方法,我的测试方法是运行
1 | dd count=10240 if =/dev/urandom | lzop -c >/dev/null |