最近我意识到了一件事:我实际上对UDP一无所知。好吧,我知道它是无连接的,没有三次握手过程,所以它对传输的质量不作任何保证。但是,在实际工程应用时,UDP的这些特征意味什么呢?
我启用了5个VPS(虚拟专用服务器,译者注),在7个小时相互发送UDP包,不过网络负载并不大(不过可以尝试下加大负载的情况)。每台服务器,每9-11秒就会随机地接收一个包并且发送5-10个包,包的大小从16到1016字节不等。
其中两个服务器位于新泽西州(NJ)的同一个数据中心,其余三台分别位于洛杉矶(LA)、阿姆斯特丹(NLD)和东京(JPN)。
可靠性分析
我想知道的第一件事是UDP到底有多不可靠。看到下表,我很好奇,我们是在讨论25%,50%,75%的传送率吗?
包的接收数目
接收方 | |||||
NJ 1 | NJ 2 | LA | NLD | JPN | |
NJ 1 | - | 2981/2981 | 2888/2889 | 2964/2964 | 3053/3054 |
NJ 2 | 3016/3016 | - | 3100/3101 | 2734/2735 | 3054/3054 |
LA | 2901/2941 | 2932/2975 | - | 2938/2942 | 2712/2712 |
NLD | 3038/3038 | 2771/2772 | 2724/2724 | - | 2791/2791 |
JPN | 2551/2552 | 2886/2886 | 2836/2838 | 2887/2887 | - |
包的接收率
接收方 | |||||
NJ 1 | NJ 2 | LA | NLD | JPN | |
NJ 1 | - | 100 | 99.97 | 100 | 99.97 |
NJ 2 | 100 | - | 99.97 | 99.97 | 100 |
LA | 98.64 | 98.55 | - | 99.86 | 100 |
NLD | 100 | 99.97 | 100 | - | 100 |
JPN | 99.96 | 100 | 100 | 100 | - |
这些数据远超过我的预期。我原以为从NLD—JPN一线会有明显超出均值的丢包,但是事实并不是这样的。反而是从LA发出、传送到NJ的数据有些异常。原因何在?
首先,我将原因锁定在包的大小。我会使包尽量小(16字节的头,0-1000字节的有效数据):
每种大小的包的丢失个数
0-115 | 116-215 | 216-315 | 316-515 | 516-715 |
13 | 11 | 12 | 13 | 23 |
没有什么异常。那么,这些包丢失的时间如何分布呢?
不幸的是,我没有保存时间戳啊(Why?!),但是我统计了每一对服务器间丢包时间分布。从LA到NJ2的丢失的所有的43个包中,其中29个包在第1-2分钟内丢失。NJ1的包也大部分在刚开始很短的时间内丢失。
排队
我关注的另一个点是排队。
为了探讨这个问题,我们首先要讨论下数组的逆序数。逆序数就是数组中位置顺序与大小顺序相反的一对数。假设现有一个数组10,8,3,7,4,那么你必须要调换8次才能达到正确的顺序,这8次分别是:((10,8),(10,3),(10,7),(10,4),(8,3),(8,7),(8,4),(7,4))。
逆序数
NJ 1 | NJ 2 | LA | NLD | JPN | |
NJ 1 | - | 0 | 2994 | 2581 | 4658 |
NJ 2 | 0 | - | 3147 | 2459 | 4645 |
LA | 3980 | 3861 | - | 3237 | 4010 |
NLD | 3125 | 1826 | 3133 | - | 4189 |
JPN | 3920 | 4417 | 4147 | 4425 | - |
不知道你觉得怎样,我不确定这组数据是否有价值。这确实看上去很高,当然,使用UDP的一个很重要的原因是你可以丢弃掉某些包。如果你发送了10000个包,最后一个包先来,之前的9999个包之后才依次到来,那么你就不需要做9999次调换了,直接把那第1个包丢掉即可。
如果我们把比已经处理过的包的号码小的包丢弃会怎样?比如,现在有5个包来了,1,5,4,3,6,7,由于我们已经处理过了5,所以把3和4给丢弃了。那么还剩下几个“good”的包呢?
正常顺序的包的数目
NJ 1 | NJ 2 | LA | NLD | JPN | |
NJ 1 | - | 100 | 52.40 | 55.94 | 36.77 |
NJ 2 | 100 | - | 52.47 | 54.22 | 38.02 |
LA | 41.72 | 42.32 | - | 50.48 | 39.34 |
NLD | 46.32 | 59.34 | 44.79 | - | 39.27 |
JPN | 980 | 1083 | 1141 | 1087 | - |
正常顺序的包的比率
NJ 1 | NJ 2 | LA | NLD | JPN | |
NJ 1 | - | 100 | 52.40 | 55.94 | 36.77 |
NJ 2 | 100 | - | 52.47 | 54.22 | 38.02 |
LA | 41.72 | 42.32 | - | 50.48 | 39.34 |
NLD | 46.32 | 59.34 | 44.79 | - | 39.27 |
JPN | 38.40 | 37.53 | 40.20 | 37.65 | - |
做一个小小的调整,如果我们将5个包整合到一起,再次使用上面的丢弃算法:
正常顺序的包的数目(包整合之后):
NJ 1 | NJ 2 | LA | NLD | JPN | |
NJ 1 | - | 2981 | 2061 | 2235 | 1807 |
NJ 2 | 3016 | - | 2214 | 2041 | 1889 |
LA | 1868 | 1873 | - | 2066 | 1720 |
NLD | 2200 | 2273 | 1920 | - | 1712 |
JPN | 60.38 | 62.51 | 61.13 | 59.99 | - |
正常顺序的包的比率(包整合之后):
NJ 1 | NJ 2 | LA | NLD | JPN | |
NJ 1 | - | 100 | 71.34 | 75.40 | 59.17 |
NJ 2 | 100 | - | 71.40 | 74.63 | 61.85 |
LA | 63.52 | 62.96 | - | 70.22 | 63.42 |
NLD | 72.42 | 82.00 | 70.48 | - | 61.34 |
JPN | 1541 | 1804 | 1735 | 1732 | - |
结论:
没有长时间的、大量的数据做支撑,很难得到任何结论。然而,上面的数据表明UDP的可靠性还是相当不错的。但是距离越远,遇到的跳变就越多,这也意味着发生不可预知错误的概率就越大,但是如果一切都还OK,距离也不成问题了。
排队机制是个问题。通过整合包,我们发现性能有了很大的提升。在许多场合,排队都不会产生质的影响,除非你在疯狂发包,否则通过一个简单的时间戳和接收端的重排机制,UDP的性能依旧可观。
我会做更多的测试、更长的时间、更多的数据、更多的地点。同时,我还会把UDP和TCP的相关性能做个对比。但是无论如何,我认为,可靠性超出我预期的UDP会成为我工具箱中的一员了。