网络环境模拟与恶劣网络测试

网络环境模拟

在解决日常的支持需求中,经常会遇到一些用户反馈一些无法简单复现的bug,有很大一部分的bug是由于用户自身的网络环境波动,或者是本身网络环境就较为恶劣,而服务在面对这种恶劣的网络环境的健壮性不够,导致会出现一些意想不到的bug。而在正常的开发自测过程中很难去营造出这种恶劣的网络环境,使得这些bug较难被提前发现和修复。另外一些服务在恶劣网络环境下虽然不会出现不可用的情况,但是用户体检很差,为了优化这个情况下的用户体验,也需要去在本地模拟这种环境来进行调优。 ^1
所以要去复现这些bug,甚至是去提前发现这些bug,就需要能够在开发环境中模拟出恶劣的网络环境,从而看到在这种恶劣的网络环境下的服务的表现等。当前模拟恶劣网络环境主要可以通过以下这些手段实现:

  • 通过应用层或者传输层的代理服务器,通过在代理服务器上设置一些模拟恶劣网络环境的参数,使得通过这些代理服务器的流量都被转化为恶劣网络环境下的流量。如利用Fiddler,Charles等具有代理服务器功能的网络流量分析软件来实现。
  • 通过利用一些更底层的驱动层面的服务,通过控制网卡的收包发包的行为,来模拟恶劣的网络环境。如dummynet的ipfw驱动等。
  • 通过建立一个可控的网关,在网关上部署模拟恶劣环境的相关程序,所有需要借助该网关进行转发的流量都会被模拟为恶劣网络条件。Linux下的netem就提供了这类支持。

  • fildder

  • dummynet
  • clumsy

内容

fildder

Fiddler的官网上是这样描述它自己的:The free web debugging proxy for any browser, system or platform,即跨浏览器、跨系统、跨平台的免费Web Debug代理服务器。当你的HTTP浏览经过Fiddler时,Fiddler可以监视流量,查看HTTP通讯的各种信息,设置断点查看和修改HTTP数据,甚至可以构造各种测试用的HTTP包以及重放已记录的包等。

其官网是http://www.fiddler2.com/fiddler2/,上面详细地介绍了Fiddler到底是什么。

官网是:https://www.telerik.com/fiddler ^2

Fiddler 是一款免费、灵活、操作简单、功能强大的 HTTP 代理工具,是目前最常用的 HTTP 抓包工具之一。可以抓取所有的 HTTP/HTTPS 包、过滤会话、分析请求详细内容、伪造客户端请求、篡改服务器响应、重定向、网络限速、断点调试等功能。

Fiddler是以代理web服务器形式工作的,在客户端和服务器之间,建立了一个HTTP代理服务器,当启动的时候,Fiddler会默认把自己设置为系统代理,来监听客户端的HTTP/HTTPS请求,默认代理地址为:127.0.0.1, 默认端口为:8888,浏览器访问WEB网站的时候,请求报文会先发送到Fiddler,Fiddler 再把请求报文转发给服务器,Web服务器返回的响应报文,也会先达到Fiddler,Fiddler再把响应报文返回给浏览器。

打开官网,选择经典版下载

Fiddler Everywhere 支持 win/linux/mac
Fiddler Classic 支持 win

默认状态下,Fiddler只能监听HTTP请求,想要抓取HTTPS请求包,需要进行设置,设置路径:Tool->Options->HTTPS

Fiddler本身已经预置提供了模拟Modem速度的选项,其位置位于: Rules – Performances – Simulate Modem Speeds 

勾选该选项后,所有通过Fiddler代理的流量都会变得和多年前的56k小猫时上网一般的慢。 

直接模拟Modem速度实在是慢爆了,事实上就算是在很差信号的情况下,手机移动网络的速度都已经超过了当年的56k Modem速度了,所以采用默认的配置模拟出来的环境过于恶劣,并不一定符合需求,此时就需要对限速的参数进行调整。 
  Fiddler本身就提供了一个配置文件供调整这些参数,点击: 
  Rules – Customize Rules… 
  就会用文本编辑器打开CustomRules.js文件,其默认位于用户目录的文档目录下的\Fiddler2\Scripts 位置,后缀名是js,其内容实质是JScript.NET——微软对ECMAScript规范的实现,与日常使用的javascript是属于同一个规范下的,但是在扩展的细节实现存在一定的不同。 
  打开该文件后,可以找到一个m_SimulateModem标志位:

if (m_SimulateModem) {
    // Delay sends by 300ms per KB uploaded.
    oSession["request-trickle-delay"] = "300";
    // Delay receives by 150ms per KB downloaded.
    oSession["response-trickle-delay"] = "150"
}

该标志位控制着oSession的两个参数值的设置,当勾选了Simulate Modem Speeds时,request-trickle-delay与response-trickle-delay就会被设置,其中request-trickle-delay中的值代表每KB的数据被上传时会被延时多少毫秒,response-trickle-delay则对应下载时每KB的数据会被延时多少毫秒,如果本身网速已经相当快的话,这里设置的值就可以近似地推算出开启模拟后的上传和下载带宽了,比如默认设置下下载延时为150ms,上传延时为300ms,对应可以推算出大致的模拟带宽为

$$
上传带宽=(18/1000)/0.300≈0.053Mbps\  
下载带宽=(1
8/1000)/0.150≈0.027Mbps
$$

然而实际情况下却得到了两倍于这个值的带宽,推测可能是Fiddler的内部实现上有一些和描述上的不同,为何为造成这个现象现在还不是很清楚,所以上述公式最后还需要修正一个2.0的系数,即:

$$
上传带宽=((18/1000)/0.300)2.0≈0.106Mbps \
下载带宽=((18/1000)/0.150)2.0≈0.053Mbps
$$

进一步地,我们可以扩展CustomRules.js里的逻辑,参照Jscript的文档可以在模拟恶劣环境中加入更多自定义的逻辑,这里实现了一个随机延时量设置,使得网络带宽不是恒定为一个低速的值,而是会在一定范围内随机抖动:

static function randInt(min, max) {
    return Math.round(Math.random()*(max-min)+min);
}
if (m_SimulateModem) {
    // Delay sends by 300ms per KB uploaded.
    oSession["request-trickle-delay"] = ""+randInt(1,50);
    // Delay receives by 150ms per KB downloaded.
    oSession["response-trickle-delay"] = ""+randInt(1,50);
}

通过进一步扩展CustionRules.js可以实现很多需要的恶劣环境模拟场景,如果场景较为复杂的话,也可以通过编写Fiddler的插件的方式,编写C#插件代码来进一步控制Fiddler的行为,在这里就不多做赘述了。详细可以参照:http://docs.telerik.com/fiddler/extend-fiddler/extendwithdotnet

Fiddler进行限速较为简单和灵活,配置也较为方便,但是由于它是一个应用层的HTTP的代理,只能模拟该层上的行为,对于一些复杂的网络层的丢包、重传等恶劣情况就不能很好的模拟出来,而且对于其他协议的应用也不支持,后续会介绍一些其他的模拟恶劣环境的方法和软件来弥补这些缺失。

dummynet

Dummynet的官网地址是:http://info.iet.unipi.it/~luigi/dummynet/,官网上对于dummynet的描述是这样的:dummynet is a live network emulation tool, originally designed for testing networking protocols, and since then used for a variety of applications including bandwidth management. 即Dummynet是一个实时的网络模拟工具,事实上dummynet是ipfw防火墙的一部分,ipfw是一个网络层的防火墙,并内建于FreeBSD之中。 
利用ipfw的options DUMMYNET选项,可以设置一系列的pipes,从而做到对网络流量进行控制的目的。

00-0000

如官网上提供的这张图所示,dummynet通过在两个网络层中(一般是在传输层和应用层之间或者网络层与传输层之间)建立一条条pipe的方式来控制网络流量,符合设定的规则中的网络流量会被引入这些管道中去,从而使得dummynet可以介入这些流量之中,控制带宽、延迟,甚至进一步控制丢包率等众多参数。

安装

Dummynet本身作为ipfw防火墙的一部分,其内建于FreeBSD,其本身支持FreeBSD,OSX,Linux,Windows多种操作系统下的安装和使用,在OSX和Linux下下载源码编译安装一般即可使用

windows 安装

Dummynet在Windows下是作为一个网卡上的服务驱动存在的,在官方给出的二进制文件包中已经包含了该驱动的sys与inf文件,但是该驱动是没有包含数字签名的,在并没有引入驱动强制签名机制的Windows操作系统(如Windows XP)上时,直接到官网下载到最新的二进制包,然后依照之后的操作步骤进行安装即可以完成ipfw+dummynet服务驱动的安装,但是在引入了驱动强制签名机制(一般是Windows 7以后的Windows版本,或者设置了比较严格的组策略)的操作系统上,是无法安装ipfw+dummynet服务驱动的,要解决这个问题可以使用两种方案:

  • 打开Windows的测试模式,关闭驱动强制签名机制,然后安装无签名的驱动 
    这种方式的实现也有两种方式,一种是在启动Windows时启动选项中关闭驱动强制签名校验机制,可以参考这篇文章 http://jingyan.baidu.com/article/7c6fb42879543380642c9036.html ,另
  • 外一种方式则是进入Windows的测试模式,可以参考 http://jingyan.baidu.com/article/acf728fd21c3e7f8e510a3ef.html 文章中的说明。
    为无签名的ipfw+dummynet服务驱动打上自签名或者可用的签名 
    如何进行自签名或者打上可用的签名可以参考MSDN上的说明 https://msdn.microsoft.com/en-us/library/windows/hardware/ff544865(v=vs.85).aspx ,具体如何签名并不在本文的范畴内。

本文主要使用第二种方式,为ipfw+dummynet服务驱动打上百度签名后,即可在Windows 7上正常安装。

  • 找到你需要限制带宽和流量的网卡,进入属性
  • 点击下方的安装,选择服务,然后选择从磁盘安装,并在浏览中找到ipfw+dummynet服务驱动的inf安装文件

00-0001

  • 在“此连接使用下列项目”中看到ipfw+dummynet之后,即代表ipfw+dummynet服务驱动安装成功,如果安装成功后遇到网卡无法使用的情况,一般会是前一次卸载没有卸载完全,重启电脑可以解决。 
    安装完成后可以以管理员权限运行binary目录下的testme.bat,如果运行结果中没有报警信息或者错误信息,则驱动安装是成功的

00-0002

利用Dummynet模拟恶劣网络环境

利用dummynet的pipe,可以设置一些特定的规则,就可以达到模拟恶劣网络环境的目的,且这些设置对于在操作系统中运行的应用程序来说是透明的、自动生效的,不需要像在使用Fiddler来进行模拟时还需要设置http代理。

  • 低带宽模拟 
    恶劣网络环境最基础的模拟方式就是模拟较小带宽下的情况,利用dummynet中的pipe设置,可以将所有的tcp流和udp流的带宽限制在一定的级别上,运行一个管理员的命令行,并利用binary目录下的ipfw.exe文件就可以设置dummynet中的pipe,在命令行中执行以下命令:

```sh 
ipfw add pipe 2 in proto tcp 
ipfw pipe 2 config bw 2Mbit/s 

即可将tcp的下行流量限制在2Mbit/s的带宽上,这里采用测速网站speedtest.net来验证限制带宽的效果

*  高延时模拟 

在管理员权限的命令行中执行以下命令: 

```sh
ipfw add pipe 10 ip from any to any 
ipfw pipe 10 config delay 200 

这会使得所有的包都被延时200ms,这里利用ping命令来ping百度的方式来直接测试延时

  • 高丢包率模拟 

在管理员权限的命令行中执行以下命令: 

ipfw add pipe 10 ip from any to any 
ipfw pipe 10 config plr 0.1 

这里设置的是10%的丢包率,这里利用ping -t指令继续ping百度,来观察丢包率的变化

  • 更加精细化的设置 
    可以看到相比Fiddler来说,利用dummynet可以更加精细化地从各个角度去设置一个恶劣网络环境的参数,上文中提到的带宽、延时和丢包率的模拟当然也可以组合起来使用,同时在设置pipe规则时还可以进一步设置更加精细的规则,比如指定的ip段,指定的协议等,比如这一段指令: 
ipfw add pipe 4 src-ip 10.1.2.0/24 in 
ipfw pipe 4 config bw 1Mbit/s delay 123 plr 0.1 

就设置了一个只会介入源ip来自10.1.2.0/24网段的数据包的pipe,并且这个pipe会限制1Mbit/s的带宽,延时123ms,并且有10%的丢包率,通过组合这些参数,可以模拟出很复杂的恶劣网络环境,从而满足开发和测试的需要。相关的设置参数的说明和设置方法可以参考官网的相关文档和其他的一些说明文档。

在最后,当完成模拟恶劣网络环境后,执行以下命令: 

ipfw -q flush 
ipfw -q pipe flush 

来清除所有设定的pipe和规则,进一步如果需要还原原来的环境的话可以将驱动删除,并重启计算机即可。

clumsy

clumsy 能在 Windows 平台下人工造成不稳定的网络状况,方便你调试应用程序在极端网络状况下的表现。

参考文献

苏ICP备19018690号-1