作为一个服务端开发,强烈意愿需要一个性能检测工具,而时间是性能一个重要的指标。而curl 请求输出可以根据自己需要设置(time_namelookup、time_connect、time_appconnect、time_pretransfer、time_starttransfer、time_total)时间相关的输出。但是搜索了google、baidu不止一天两天,得到的答案都是man curl,而没有一个更精准、容易理解的答案。最终无意中搜索到<引用>的文章,茅塞顿开,建议读到本篇文章的都耐心读完。
预备知识
curl标准化输出
在一个请求结束时,curl会根据-w,–write-out 选项打印出来定制化信息到标准输出。format 包含有占位符的字符串,curl会替换占位符为预定义的变量的值。
比如 HTTP状态码:%{http_code}
会被替换为 HTTP状态吗: 200
时间指标官方解释
时间指标的单位都是秒,计时开始都是curl请求开始时间,也就是dns开始查询那一刻的时间。
- time_namelookup:开始到dns查询完成花费时间
- time_connect:开始到tcp三次握手完成花费时间
- time_appconnect:开始到ssl握手时间完成花费时间
- time_pretransfer: 开始到文件传输即将开始花费时间
- time_starttransfer: 从开始到第一个字节即将被传输,包含time_pretransfer和服务器计算结果所需时间
- time_total 整个操作所有花费时间
理解重点
一个容易被忽略的前提,curl作为一个客户端工具,计算所有时间的前提都代表着网路传输的客户端。理解每个时间,必须先提醒自己这个前提。
探究过程
请求例子
/usr/local/opt/curl/bin/curl -L -w '@curl.txt' 'localhost:8080/a.php'
time_namelookup: 0.002783
time_connect: 0.002928
time_appconnect: 0.000000
time_redirect: 2.104259
time_pretransfer: 0.002981
time_starttransfer: 6.177934
----------
time_total: 6.178134
例子详情:
// a.php
<?php
sleep(2);
header("location:./b.php");
// b.php
<?php
sleep(4);
time_namelookup指标
这个很好理解,dns查询时间,即curl访问某个域名的时候,需要先从dns服务器以下该域名对应的ip。这个过程一般会很快,是因为服务器在首次获取到ip的时候,会缓存结果一段时间。我在本地测试/etc/hosts解析的域名,时间保持在2~3ms左右。
time_connect指标
网络建立socket需要经历三次握手,该指标的值就是开始到建立socket成功的时间。time_connect-time_namelookup
即curl和服务器建立socket所花费的时间,对应上面的例子花费了0.145ms。测试了baidu,该指标为21ms。
time_appconnect指标
真正的传输建立完socket便可以,比如http便是直接在tcp协议上传输内容。但是https为了网络内容的安全会在tcp上再次进行ssl层的建立,该阶段百度测试120ms。所以该指标也是一个很重要的查询整体性能的因子。上面的例子由于是http,故该指标值为0。
time_redirect指标
从上例子中可以看出,该指标是截止点在于跳转到b之前的瞬间。由于a文件在跳转之前先等待了2s,所以curl接收到301请求之后,由于-L(follow redirects),会立马请求b.php,但是b.php的返回是4s之后,所以该时间点,应该是接收到301之后,再次请求服务端的瞬间。
这里就牵扯到一个问题:如果header location 是其他网站,是不是要重新计算namelookup的时间,以及建立链接的时间。
// a.php
<?php
sleep(2);
header("location:https://www.baidu.com");
time_namelookup: 0.090075
time_connect: 0.158963
time_appconnect: 0.214078
time_redirect: 2.412030
time_pretransfer: 0.308881
time_starttransfer: 2.570669
----------
time_total: 2.577325
可以看到time_namelookup、 time_connect、time_appconnect都有较大的变化,如果单独请求百度得到的三个值也会小于上面三个值。所以三个指标如果包含跳转,应该是跳转前后两次的对应加和。
该指标指最后一个请求开始的瞬间,只考虑整个链条的最后一次请求。
最困惑的time_pretransfer指标
从上面的例子可以发现该指标会比time_appconnect(https)或time_connect(http)多几十微秒,如果是跳转会多点,但是相对于网络来回来说,这个时间太小。所以有的文档说,该指标只是为了和connect概念上做区分。但是从细微的时间上的差别来看,足够cpu做很多事情,所以它表示的应该是,在connect之后处理了一些协议相关的初始化操作,然后将数据放到网卡之前的瞬间。
通俗的说,该指标结束点在于开始往服务器发送真正的http、https请求的瞬间。
time_starttransfer和time_total指标
这两个指标应该是比较好理解的。time_starttransfer 对应TTFB,即curl收到服务端传来的第一个字节的瞬间。time_total整个curl操作周期的总时间。
指标应用
- dns解析快慢,直接使用
time_namelookup
- 链接创建时间,根据http\https, 使用
time_connect\time_appconnect - 直接使用time_namelookup
- 服务端处理时间,
time_starttransfer - time_pretransfer
- 内容下载时间,
time_total - time_starttransfer
总结
curl的几个时间指标真实反应一次请求的各个阶段,对于服务时间性能方面的测试是一个很大的助力。关于本文,主要针对无法理解curl man的解释,做了各个方面的探究。这些探究都是针对实际操作而得出的结论,可能无法真实反应curl本身源代码方面的设计。
不过针对平时的应用,参考<指标应用>小节,完全可以满足平时所用。如果针对某个具体的指标有疑问,可以深入到具体的指标实验中做对比。
引用
https://speedtestdemon.com/a-guide-to-curls-performance-metrics-how-to-analyze-a-speed-test-result/