UDP的误区

 我发现很多人不太爱用UDP,对UDP存有偏见,爱憎分明的我不得不为它吐吐槽。

比起TCP来,UDP的优势在于速度快,而且不需要维护数据流,还能防止意想不到的欺骗。我遇到这么一个项目,在nginx上设计一个add-on模块做局域网转发。由于最终实现的服务部署在本机或局域网中,我建议通过UDP方式实现服务的调用。当时就有人跳起来跟我争论,反对使用 UDP。理由是UDP是无连接的,容易丢包,有时序问题,不可靠。

首先在本地或局域网中不存在时序问题。时序问题的产生是因为数据包可能走过不同路由。局域网内不存在这种情况,也就不用理会它。另外我可以负责任地说,虽然UDP 是无连接,它在局域网中传输丢包的概率是微乎其微的。局域网使用的交换机对数据有很强的恢复功能。如果在局域网中你的程序出现丢包的现象,你还是先检查一下自己程序写得是否合理。一般的丢包都是应用写的不合理造成的,比如接收不及时导致接收缓冲区满了,后面的包覆盖了前面的包,从而导致“丢包”。接收 UDP 数据包的函数尽量不要和处理UDP数据包的函数在一个线程,否则就可能导致收包不及时的问题发生。收包线程的全部工作就是不停地读,把接收完的数据放在队列中。

还有人提出峰值数据量过大会引起计算机忙而丢包。我做过24路1080p 30mbps码流的视频直播服务,画面清晰不丢帧,没有马赛克。运算设计得简单,如果是CBR的视频流,使用720mbps带宽,在千兆网环境下是没有任何问题的。到目前为止我做的转发服务还没有超过这个峰值数据量。有人使用tcpdump验证我的说法,向我反映即便是局域网也有“x packets dropped by kernel”。但是造成这种丢包的原因是由于libcap抓到包后,tcpdump上层没有及时地取出,导致libcap缓冲区溢出,从而覆盖了未处理包。虽然tcpdump工具显示被kernel丢弃,但是并不是说真正是被Linux内核抛弃的,而是被其所使用的动态库libcap抛弃。这时候如果是你写的服务,还是可以正常获取数据的。当然我们是有办法来改善tcpdump上层的处理效率减少丢包。例如抓包时最小化抓取过滤范围,即通过指定网卡、端口、包流向、包大小来减少处理包的数量;添加-n参数,禁止反向域名解析;调节/proc/sys/net/core/rmem_default和/proc/sys/net/core/rmem_max 参数改变sk_rcvbuf的大小等。

可能还有人会问:“很多教科书上都说 UDP 容易丢包呀。”这要看在什么应用场景下。不能生搬硬套。在经过路由器的情况有时是会出现丢包的。依我的实际经验,在过二三级路由以后,由于数据流量繁忙和TTL等原因可能会出现丢包的现象。

所以凡涉及到本机或局域网内通讯的案例,都可以考虑使用UDP。因为这个东西无连接,处理起来相当简单,性能极高。这种情况下使用TCP很浪费CPU资源。因为根本都不丢包,每次TCP的流控还要评估网络环境。


你可能感兴趣的:(技术)