2. 网络延迟组成:DNS解析、连接建立、数据传输、TLS协商
做SDK接入优化,第一件事就是搞清楚时间都花在哪了。我见过不少团队,一上来就冲数据压缩猛搞,结果发现大头根本不在那。你想想看,一次网络请求,从你调用接口到拿到响应,中间要过多少关?
说白了就四个阶段:DNS解析、连接建立(TCP三次握手)、TLS协商(如果走HTTPS)、数据传输。每个阶段都有自己的"坑",咱们一个一个拆。
2.1 DNS解析:第一个瓶颈
DNS解析是把域名转成IP地址。别小看这一步,我在项目中遇到过,一个DNS查询就能吃掉200ms,甚至更久。尤其是在移动端,网络环境差的时候,DNS解析经常成为"沉默的杀手"。
为什么会这么慢?
- 递归查询链路长:从客户端到本地DNS,再到根服务器、顶级域、权威服务器,来回好几趟。
- 缓存命中率低:很多App没有做DNS缓存,每次请求都走一遍完整流程。
- 运营商DNS劫持:有些ISP会故意返回慢的IP,甚至插广告。
关键指标:一条完整DNS解析的合理耗时应该在20-80ms之间。超过100ms就要警惕了。
我的建议:SDK内部做DNS预解析 + 本地缓存。我习惯在App启动后,闲时把最常用的一批域名提前解析好。这样真正请求来时,直接走缓存,几乎零耗时。
2.2 连接建立:三次握手的代价
TCP三次握手是绕不开的。客户端发SYN,服务端回SYN+ACK,客户端再回ACK。一来一回,至少一个RTT(往返时间)。
RTT是多少?取决于物理距离。你在国内访问国内服务器,RTT也就20-60ms。但要是跨海访问,150-300ms很正常。一次握手就要一个RTT,加上TLS协商又是一个RTT(甚至两个),光连接阶段就干掉几百毫秒。
| 阶段 | 最少RTT数 | 典型耗时(国内) | 典型耗时(跨海) |
|---|---|---|---|
| TCP三次握手 | 1个RTT | 20-60ms | 150-300ms |
| TLS 1.2 | 2个RTT | 40-120ms | 300-600ms |
| TLS 1.3 | 1个RTT | 20-60ms | 150-300ms |
我曾经踩过的坑:有一次SDK接入海外服务器,每次请求光连接就花掉400ms,用户反馈说"卡得不行"。查了半天发现,TLS协商用了TLS 1.2,整整两个RTT。后来强制升级TLS 1.3,直接砍掉一半耗时。嗯,这里要注意,服务端也要支持才行。
2.3 TLS协商:安全是有代价的
HTTPS不是免费的午餐。客户端和服务端要先交换证书、协商密钥、验证身份。TLS 1.2需要两个RTT(ClientHello → ServerHello、证书、ServerHelloDone → ClientKeyExchange、ChangeCipherSpec → 完成)。TLS 1.3优化到1个RTT,甚至可以用0-RTT模式。
但0-RTT有重放攻击风险,不是所有场景都适合。我个人习惯在内部SDK调用中,如果数据不那么敏感(比如埋点上报),可以用0-RTT;但涉及用户隐私的接口,老老实实用1-RTT。
另外有一个容易被忽略的点:证书链验证。我见过有些SDK依赖的根证书列表太旧,或者中间证书过大,光下载和验证证书就多花几十毫秒。
优化手法:证书固定(Certificate Pinning),可以跳过证书链验证,大幅减少TLS协商耗时。但要注意证书更换时做好灰度,否则服务会挂。
2.4 数据传输:带宽与拥塞
连接建好了,终于开始传数据。数据传输的耗时取决于两个维度:带宽和往返次数。
- 带宽:数据量大时,传输时间 = 数据量 / 带宽。但实际还受TCP拥塞控制影响,慢启动阶段发送窗口小,前面几轮传输很慢。
- 往返次数:如果每个请求都要等上一个响应才能发下一个(串行),那么总耗时 = 请求数 × RTT。很多SDK犯了这个错,多个请求串行发送,白白浪费。
举个例子:一个100KB的响应,带宽10Mbps,理论上8秒?不对,实际上因为慢启动,第一轮只能发几个包,可能前500ms只发了不到10KB。所以 减少数据量 + 启用HTTP/2多路复用 是王道。
2.5 一张图看懂网络延迟组成
下面这张流程图把整个请求拆解为四个阶段,方便你对照分析。
2.6 实战分析:一个请求的时间账本
假设用户在北京,服务器在上海(RTT≈30ms),走HTTPS,请求体2KB,响应体50KB。我们一笔笔算:
- DNS解析:命中本地缓存,0ms。
- TCP三次握手:1个RTT = 30ms。
- TLS 1.2协商:2个RTT = 60ms。
- HTTP请求发送:2KB,带宽10Mbps,理论上1.6ms,加上慢启动,算5ms。
- 服务器处理:假设50ms。
- 响应传输:50KB,带宽10Mbps,理论上40ms,慢启动拖累,算80ms。
总耗时 = 0 + 30 + 60 + 5 + 50 + 80 = 225ms。你看,连接和TLS协商占了90ms,数据传输占了85ms,服务器处理50ms。如果能把TLS换成1.3,立刻省30ms。
一个实用的诊断方法:用 curl 的 --trace-time 或 --trace-ascii 可以看到每个阶段的耗时。我每次排查问题,第一件事就是跑一遍 curl,看时间花在了哪。
curl -w "\n\nTime breakdown:\ntime_namelookup: %{time_namelookup}\ntime_connect: %{time_connect}\ntime_appconnect: %{time_appconnect}\ntime_starttransfer: %{time_starttransfer}\ntime_total: %{time_total}\n" -o /dev/null -s https://api.example.com
学会拆解这四个阶段,你就能精准定位瓶颈。不是所有优化都需要大动干戈——有时候换个TLS版本,或者加个DNS缓存,效果立竿见影。