你的服务真的在用UDP吗?——后端工程师不知道的网络盲区
做后端开发的,写了几年HTTP请求,调了无数次接口,自以为什么网络协议都了然于胸了。结果有一天线上出了问题:用户说「能登录,但头像加载不出来」「消息发出去了但对方没收到」。
查了一圈,发现是UDP丢包。
你说:你用的什么协议?
对方说:UDP啊,怎么了?
你愣了:UDP不是不可靠的吗?你们怎么能用UDP传重要数据?
对方也愣了:你不会用UDP做生产系统啊?
今天聊点不一样的:UDP不只是那个「不可靠」的协议,它是现代高并发系统的隐藏基石。而且,很多你以为「理所当然」的功能,背后都是UDP在撑着。
先破一个执念:UDP不是「低配版TCP」
很多人学网络的时候,课本告诉你:TCP是面向连接的、可靠的;UDP是无连接的、不可靠的。于是你就形成了这么一个印象:UDP = 阉割版TCP = 用在不重要的场景。
这个认知,害死人。
TCP可靠吗?可靠。但它可靠的代价是什么?三次握手建立连接、四次挥手断开连接、序列号追踪、确认应答、重传机制、流量控制、拥塞控制……这一套下来,每个数据包的传输都附带了一堆「保险」。这些保险在可靠传输的同时,也在大量场景下成为了性能杀手。
UDP呢?三个字:快、简单、裸。
没有连接建立,直接发。没有重传机制,发出去就不管了。没有流量控制,网卡能塞多少就塞多少。没有序列号,不保证顺序。
听起来像是缺点,但换个角度想:这些「没有」,恰恰是它的优势。
在延迟敏感的场景下,少一次握手可能就是几十毫秒的差距。在丢包率低的内网环境里,UDP的效率可以甩TCP几条街。在需要广播或多播的场景,TCP根本玩不转,只有UDP可以。
场景一:DNS查询——你每秒几万次的UDP请求
第一个要打破你认知的:DNS用的就是UDP。
你以为你访问一个域名,浏览器去DNS服务器查IP,这个过程用的是「靠谱」的协议?抱歉,53端口,默认UDP。除非响应太大(超过512字节)或DNS服务器不支持UDP,才会降级到TCP。
所以你的后端服务,每秒钟可能就在发起成千上万次UDP请求,只不过被SDK和系统库封装好了,你感觉不到。
但这里有个坑:DNS劫持。
TCP数据包在中间节点被篡改的难度很高,因为有校验和序列号。但UDP包?中间路由可以随便丢、随便改。几年前某著名CDN提供商就出过事,DNS解析结果被劫持,用户访问的其实是个假服务器。
解决方案是DNS over DTLS或者DNS over HTTPS(DoH)。这两个本质上是把DNS查询套了一层TLS/加密壳,走UDP传输。没错,又是UDP——只是这次UDP上面跑了一个安全层。
所以下次你遇到DNS解析慢的问题,记住:底层是UDP,它的「不可靠」可能在拖你后腿。
场景二:QUIC/HTTP/3——UDP让HTTPS飞起来
HTTP/3正式大规模铺开也就是这两年的事。它的底层协议叫QUIC,而QUIC,是基于UDP实现的。
为什么HTTP/3不用TCP?因为TCP的拥塞控制算法是内核层面的,改不了。而UDP?裸的,你想怎么玩就怎么玩。
QUIC自己做连接建立(0-RTT或1-RTT握手,比TCP+TLS的2-RTT甚至3-RTT快多了)、自己做丢包检测和重传、自己做流量控制、自己做多路复用。而且QUIC的连接是通过Connection ID而不是IP+端口来识别的——这意味着什么?切换网络(比如从WiFi切到4G)不用重建连接。这对移动端体验来说是革命性的提升。
实测数据:HTTP/3相比HTTP/2,页面加载时间减少15%到30%,在弱网环境下差距更明显。而这一切,都是建立在UDP的「简陋」之上的。
你的服务支持HTTP/3了吗?如果还没支持,至少了解一下QUIC的背景——它正在改变整个Web的性能标准。
场景三:实时音视频和游戏——UDP的「不可靠」才是正解
实时音视频(WebRTC)和在线游戏,这两个领域的底层传输协议,几乎清一色是UDP。
为什么?因为在实时场景下,迟到的数据包比丢失的数据包更可怕。
想象你在打王者荣耀,服务器告诉你「三秒钟前你打出了一发普攻」,这三秒的延迟已经让战局完全变了样。这发普攻的数据,丢了也就丢了,但你绝对不想让旧的、滞后的数据去「纠正」当前的游戏状态。
TCP的应答确认和重传机制,在这里是灾难。你发了一个数据包,对方没收到,TCP会卡住等你重传。重传完了,你发的后续数据包都得等着排队。这种「可靠性」在实时场景下反而会造成更大的延迟抖动。
UDP就不一样了。发了就是发了,没收到?没收到就没收到,应用程序自己决定怎么处理。可以无视(语音通话丢一帧无所谓)、可以用前帧填充(视频丢了一帧就用上一帧)、可以主动预测(游戏客户端预判你的走位)。
WebRTC的音视频传输,用的就是RTP(Real-time Transport Protocol),基于UDP。RTP本身不保证可靠,但它在应用层实现了自己的丢包补偿和抖动缓冲。这是更灵活的分层架构——网络层干网络层的事,应用层干应用层的事,而不是让TCP替你做所有决定。
场景四:内网服务发现和心跳——UDP的轻量优势
你可能在公司内网用过Consul或者etcd来做服务发现。这两个系统,节点之间的通信用的是gRPC,而gRPC默认是基于HTTP/2,但底下的服务探测和选举,用的是Raft协议,而Raft可以用UDP来实现心跳。
为什么心跳用UDP?因为心跳的目的是「我还活着」,不需要可靠,只需要快和轻。如果心跳丢了一次,下一轮自然就知道对方是不是还活着。重传机制反而会增加系统负担。
还有一个典型场景:SNMP网络监控。路由器、交换机、服务器的监控代理,收集数据用的都是UDP 161端口。为什么?因为监控数据丢一两帧不影响网络运维判断,但如果每个监控包都要等TCP握手确认,监控系统的开销会比被监控系统还大。
踩坑实录:一次UDP端口被封的经历
说个真实的坑。
之前有个项目,需要在内网搭一个实时消息推送系统,技术选型的时候选了UDP直推——数据量不大但要求低延迟。开发测试一切正常,部署到客户环境,傻眼了:消息收不到。
排查了整整两天。代码没问题,端口没冲突,防火墙规则也对了。最后发现:客户那边的安全设备(某著名防火墙)默认封锁了非标准端口的所有UDP入站流量。TCP的80、443、22这些端口放行,但其他的?统统挡掉。
这不是个例。很多企业网络、政务网络、校园网络,都有类似的安全策略。如果你打算在生产环境用UDP做点什么,先确认网络路径上有没有设备会拦截你的UDP端口。这一步做不好,你精心写的可靠UDP传输层就是空中楼阁。
解决方案:走CDN的UDP加速通道,或者在UDP外面套一层TLS(DTLS),伪装成「正常的HTTPS流量」。讽刺吧?为了让UDP可靠传输,你得把它包装成更像TCP的样子。
重新认识UDP:它不是备选,是基石
说了这么多,不是让你抛开TCP去用UDP。而是想让你明白:UDP不是TCP的低配版,它们是不同的工具。
该用TCP的场景:文件传输、HTTP API、数据库连接、SSH远程登录。任何「丢了数据必须重新发」的场景,TCP的可靠性保证是无可替代的。
该用UDP的场景:实时性要求高于可靠性的(音视频、游戏)、需要广播/多播的(服务发现、组播路由)、对性能敏感且愿意自己在应用层做可靠性控制的(QUIC、Raft心跳、DNS)。
更重要的是,很多你以为跟UDP无关的系统,其实底层都是UDP在干活。你的CDN加速、你的实时通信、你的DNS解析、你的HTTP/3——UDP无处不在,只是被层层封装,你感觉不到它的存在。
所以,下次遇到网络问题,别只盯着TCP了。抬头看看UDP,它可能才是真正的幕后功臣——或者,幕后黑手。
网络的世界比你想象的更复杂,也更有趣。
关注comck.com,带你用小龙虾的视角看技术真相。