网络耗时及其优化

[toc]

第2节:网络耗时及其优化

一、网络耗时流程及优化方案结论

发起请求 -> 域名DNS解析 -> TCP三次握手 ( -> TLS握手 -> ) -> request -> response -> json解析 -> 业务

1、过程中的优化方案

序号 阶段 耗时根源 优化方案
1 发起请求 每个接口都要建立连接 前端配置想要的数据,后台通过一个接口返回
如商品详情页,请求[Base,Detai,Images]:商品基础信息+详情+图片
其他减少请求参数的body数据。
2 域名DNS解析 DNS解析过程不受控制,⽆法保证解析到最快的IP 方案1:IP直连 点击链接可跳转到下文介绍
HTTP(HTTPS)请求,底层基于TCP连接,需要有IP和端口信息。
⾃⼰做域名解析⼯作,通过HTTP请求后台去拿到域名对应的IP地址。
方案2:HTTPDNS
阿里云的DNS SDK:AlicloudPDNSAlicloudHTTPDNS
附:iOS14原生加密DNS方案
3 TCP三次握手 TCP:面向连接的协议
UDP:无连接协议
TCP 比 UDP 要慢
方案1:用HTTP实现长连接 点击链接可跳转到下文介绍
方案2:使用HTTP/3.0 采用了基于 UDP 的 QUIC 协议来替代传统的 TCP 协议
HTTP协议各版本使用情况
4 TLS握手 —— ——
5 request 服务端排查是否有耗时逻辑
6 response 数据体积大 删减冗余数据,开启gzip,数据分页、Protobuf、WebP等方式进行优化
Protobuf:见我的另一篇文章 protobuf的安装.md
分页:见我的另一篇文章 分页规范.md
7 json解析 解析耗时 采用解析效率更高的库,如 YYModel
8 业务 —— ——

上述优化方案的参考文档来源于:

2、其他优化方案

2.1、弱网优化:针对不同的网络,做不同超时,重试设置,以及取不同质量的图片数据。

2.2、缓存(必备:API缓存+可考虑加:Last-Modified/ETag)

见我的另一篇文章:

发布的内容,优先写入数据库,视频切片使用另一个请求异步获取。

二、网络耗时分布统计

1
2
3
4
5
6
7
8
9
class ResponseModel {
int statusCode;
String? message;
dynamic result;
bool? isCache;
bool? isSameToBefore; // 网络新数据是否和之前数据一样(重试/缓存)
final ResponseDateModel dateModel; // 这次结果的时间。
List<ResponseDateModel>? cacheDateModels; // 请求缓存接口过程的所有时间段(缓存数据获取时间、缓存数据执行时间、网络数据获取时间)。因为有时候得到一个结果是不仅经过一次,而是多次请求才得到的(如缓存),所以一个请求有多条时间线的时候。
}

1、ResponseDateModel dateModel; // 这次结果的时间

2、List? cacheDateModels; // 请求缓存接口过程的所有时间段(缓存数据获取时间、缓存数据执行时间、网络数据获取时间)。因为有时候得到一个结果是不仅经过一次,而是多次请求才得到的(如缓存),所以一个请求有多条时间线的时候。

1、网络请求各阶段的耗时(iOS)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didFinishCollectingMetrics:(NSURLSessionTaskMetrics *)metrics API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0)) 
{
// 首先检查是否是iOS 10.0或更高版本,如果不是,则退出方法
if (!@available(iOS 10.0, *)) {
return; // 退出方法
}

// 由于使用了@available注解,下面的代码默认只在iOS 10.0或更高版本上执行
for (NSURLSessionTaskTransactionMetrics *sMetric in metrics.transactionMetrics) {
NSInteger dom = timeDiff(sMetric.domainLookupStartDate, sMetric.domainLookupEndDate); // 域名解析
NSInteger sec = timeDiff(sMetric.secureConnectionStartDate, sMetric.secureConnectionEndDate);// TLS
NSInteger con = timeDiff(sMetric.connectStartDate, sMetric.connectEndDate); // 连接耗时(包括TLS)
NSInteger req = timeDiff(sMetric.requestStartDate, sMetric.requestEndDate); // 请求
NSInteger res = timeDiff(sMetric.responseStartDate, sMetric.responseEndDate); // 回调
NSInteger tot = timeDiff(sMetric.fetchStartDate, sMetric.responseEndDate); // 总耗时

NSString *locip = @"";
NSString *remip = @"";
if (@available(iOS 13.0, *)) {
locip = [NSString stringWithFormat:@"%@", sMetric.localAddress];
remip = [NSString stringWithFormat:@"%@", sMetric.remoteAddress];
}

NSLog(@"metric path:%@ 总耗时:%ldms, 域名解析:%ldms, 连接耗时:%ldms(包括TLS:%ldms), 请求:%ldms, 回调:%ldms l:%@ r:%@", sessionMetric.request.URL.lastPathComponent, (long)tot, (long)dom, (long)con, (long)sec, (long)req, (long)res, locip, remip);
}
}

// 辅助方法,计算两个NSDate之间的时间差,单位为毫秒
- (NSInteger)timeDifferenceInMilliseconds:(NSDate *)start to:(NSDate *)end {
return (NSInteger)((end.timeIntervalSince1970 - start.timeIntervalSince1970) * 1000);
}

Next:第3节:弱网优化空间探索

附1:HTTP协议各版本使用情况

类型 发布时间与现状
HTTP/1.1 在1997年被标准化,是目前互联网上广泛使用的HTTP协议版本
HTTP/2.0 于2015年发布,也是目前互联网上广泛使用的HTTP协议版本 不是对HTTP/1.1的重写,而是在性能方面的改进
HTTP/3.0 目前尚未成为主流,还在逐步推广和应用中 是基于Google的QUIC协议开发

附2:DNS

1、DNS介绍

1.1、DNS劫持/DNS污染前后

未劫持 VS 劫持

dns flow

1.2、DNS劫持模拟

1.3、如何检测 DNS 劫持

  • iOS 用户推荐 iNetTools
  • Android 用户推荐 LanDroid
  • 如何检测 DNS 劫持

    ping 一个不存在的 IP 地址却仍获得解析,则 DNS 很可能已被黑客入侵。

2、DNS的优化

方案1:IP直连

方案2:HTTPDNS

2.1、IP直连

iOS IP 直连原理剖析

为什么大家会选择直接使用 IP 来进行连接呢?它具有多方面的优势:

  • 防劫持,可以绕过运营商 LocalDNS 解析过程,避免域名劫持,提高网络访问成功率
  • 降低延迟,DNS 解析是一个相对耗时的工作,跳过这个过程可以降低一定的延迟
  • 精准调度,运营商解析返回的节点不一定是最优的,自己获取 IP 可以基于自己的策略来获取最精准的、最优的节点

对于获取 IP,我了解到的是两种方案,

一种是直接接入腾讯或者阿里的 HTTPDNS 服务,在发起请求的时候是通过 HTTPDNS 获取 IP,然后直接使用 IP 来进行业务访问;一种是内置 Server IP,可以在启动等阶段由服务端下发域名和 IP 的对应列表,客户端来进行缓存,发起网络请求的时候直接根据缓存 IP 来进行业务访问。

附3:用HTTP实现长连接

长连接:长连接的特点是一旦通过三次握手建立链接之后,该条链路就一直存在,而且该链路是一种双向的通行机制,适合于频繁的网络请求,避免 Http 每一次请求都会建立链接和关闭链接的操作,减少浪费,提高效率。

在首部字段中设置Connection:keep-alive 和Keep-Alive: timeout=60,表明连接建立之后,空闲时间超过60秒之后,就会失效。如果在空闲第58秒时,再次使用此连接,则连接仍然有效,使用完之后,重新计数,空闲60秒之后过期。

设置HTTP长连接,无过期时间:
在首部字段中只设置Connection:keep-alive,表明连接永久有效。

其他文章:tcp长短连接、http长短连接、心跳包、tcp KeepAlive保活机制

  1. TCP 是 HTTP 的默认传输层协议:HTTP 通常运行在 TCP 之上,因为 TCP 提供了可靠的、面向连接的服务,确保数据按顺序、完整无误地从源传送到目的地。这对于 Web 浏览器和服务器之间的通信非常重要,因为它们需要确保请求和响应的完整性。

End

其他参考文档:

项目 :iOS-Monitor-Platform 中的网络部分 https://github.com/aozhimin/iOS-Monitor-Platform?tab=readme-ov-file#network