12月 032010
 

August 24, 2010 by LostRiver

        使用OpenVPN一段时间,发现Windows客户端速度一直远小于Linux客户端。我的网络环境两边都是百兆 IPv6共享接入服务端是OpenVZ VPS。linux下客户端和服务端单个TCP连接速度在500KB/s上下波动,通过OpenVPN后速度差别不大。未优化时,Windows下速度明显降低,全局下载带宽只能到100KB/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 65536

        rcvbuf最大可取到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偶尔会不稳定,建议还是使用静态路由:

route.exe -p ADD 8.0.0.0 MASK 252.0.0.0 10.8.0.5 METRIC 40

        要求服务端配置文件使用ccd固定每个客户的IP地址与网关地址,

client-config-dir ccd

        服务器ccd文件夹下建立clinet1,内容:

ifconfig-push 10.8.0.6 10.8.0.5

        当VPN连接时,静态路由由于TAP-Win32设备的打开而自动生效,关闭时相应静态路由不起作用,仍使用原路由/默认网关。静态路由保存于注册表

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\PersistentRoutes

        不随接口启动/断开或关机而消失。
几个细节

        无论是服务端还是客户端,OpenVPN的verb选项都不应过大,verb提供Debug信息,过大可能导致Debug信息的写入占用过多磁盘IO或者CPU资源。

        开启comp-lzo,本身针对数据包的lzo的压缩率并不好,但是如果大量空白数据在传输的话,作用还是非常明显的。
意义

        不使用OpenVPN时,下载有多线程工具,视频网站有CDN加速,RWIN和RTT的限制都被很好地避免了。然而OpenVPN需要将所有流量全部经由单个UDP/TCP连接传输,保证单个接口/连接的吞吐率就非常重要了。

===================
jaleo says:
September 23, 2010 at 11:08 pm

多谢,按你提供的链接,得到信息是:
MTU = 1452
MTU is not fully optimized for broadband. Consider increasing your MTU to 1500 for better throughput. If you are using a router, it could be limiting your MTU regardless of Registry settings.
MSS = 1412
MSS is not optimized for broadband. Consider increasing your MTU value.

这里我有疑问,我用这个网站提供的TCPOptimizer工具测得MTU是1492,为何和页面检测的不一样?会不会是我用了无线路由器的关系,MTU由路由器决定,不管OS下设置如何?
Reply

    *
      LostRiver says:
      September 24, 2010 at 2:24 am

      @jaleo ,
      软件发送多个ping包测得的MTU是真实MTU,网站测试MTU利用了TCP协议的MTU发现机制,看起来speedguide网站确定MTU是设置 DF比特,三次握手时观察TCP的MSS,然后浏览器发送一个足以导致分开传送的数据段,确定MTU。这个MTU虽然可能较小但是确是TCP协议真正利用的MTU。
      1492已经是PPPoE协议可能达到的MTU的最大值。MTU当然由链路中最小的一个决定。
      speedguide网站给出的MSS是客户端发给网站的TCP首部中声明的TCP MSS,一般是系统把接口MTU减去20字节IP首部和20字节TCP首部作为MSS值。与OpenVPN的mssfix max含义不一样。OpenVPN“Announce to TCP sessions running over the tunnel that they should limit their send packet sizes such that after OpenVPN has encapsulated them, the resulting UDP packet size that OpenVPN sends to its peer will not exceed max bytes. ”
      我感觉在丢包率不高的线路上MSS、MTU的问题只要不发生严重丢包无需深究(ADSL的饱和速度是已经确定的吧)。如果对性能优化比较高,一定要抓包验证,观察TCP批量传输时VPN是否对上层数据包分片。

 回复

您可以使用这些 HTML 标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>