近期 Ricky 有一个监控链接响应时间的需求,需要测试某个站点的接口在
- 使用内网 IP 地址直接访问
- 经过内网 DNS
- 经过内网 DNS 和内网负载均衡
- 经过外网 DNS 、外网负载均衡和 https
时响应时间上的区别;以及在不同时间段内响应时间的区别;以及 KVM 虚拟机和物理服务器在响应时间上的区别。
KVM 虚拟机上的操作系统为 CentOS Linux 5.4 ,物理服务器上的操作系统为 CentOS Linux 6.2 。
监控命令说明:
监控命令主要是这几句:
W_PARAMETER='REDI:%{time_redirect}s - DNS:%{time_namelookup}s - CONN:%{time_connect}s - APP_CONN:%{time_appconnect}s - PRE_TRAN:%{time_pretransfer}s - START_TRAN:%{time_starttransfer}s - TOTAL:%{time_total}s\n' TIME=$(date "+%F %H:%M:%S") LOG_FILE=/root/monitor_link.log echo $TIME - 192.168.1.1 - webcheck - `curl -m 2 -o /dev/null -s -w "$W_PARAMETER" http://192.168.1.1/webcheck.htm` >> $LOG_FILE
这里解释说明一下使用到的 curl 命令:
(1)curl 命令:
W_PARAMETER='REDI:%{time_redirect}s - DNS:%{time_namelookup}s - CONN:%{time_connect}s - APP_CONN:%{time_appconnect}s - PRE_TRAN:%{time_pretransfer}s - START_TRAN:%{time_starttransfer}s - TOTAL:%{time_total}s\n' curl -m 2 -o /dev/null -s -w "$W_PARAMETER" http://192.168.1.1/webcheck.htm
- -m 2 :设置最大传输时间,单位是秒;
- -o /dev/null :屏蔽原有输出信息;
- -s :silent 模式,不输出任何东西;
- -w “$W_PARAMETER“:控制额外输出。
(2)curl 命令使用到的计时器说明(即 W_PARAMETER 这个变量里存储的字符串):
- time_namelookup:从起始至域名解析完成的耗时;
- time_connect:从起始至建立到 Web 服务器的 TCP 连接的耗时;
- time_appconnect:从起始至建立到 Web 服务器的应用层( SSL )连接 / 握手完成的耗时;
- time_pretransfer:从起始至准备开始传输数据的耗时;
- time_starttransfer:从起始至收到 Web 服务器返回数据的第一个字节的耗时;
- time_total:总的耗时;
- time_redirect:整个过程中重定向的耗时。
一个 HTTP 请求,涉及多个阶段(下列 7 条与上面的 7 条基本对应):
- DNS 解析域名;
- 请求从 Clinet 路由至 Server,Clinet 与 Server 建立 TCP 连接;
- 如果使用了 HTTPS,还涉及 SSL 连接的建立;
- Server 开始准备数据(开始逻辑计算、调后端接口、查数据库缓存等);
- Server 开始传输数据(数据准备完成,开始给 Client 传数据);
- 数据传输完毕;
- 整个过程可能还涉及多次重定向。
一些简单的时间计算:
- TCP 建立连接的耗时 = time_connect – time_namelookup;
- 从建立 TCP 连接到 Server 返回 Client 第一个字节的时间 = time_starttransfer – time_connect;
- Server 处理数据的时间 = time_starttransfer – time_pretransfer;
- Client 接收数据的耗时(开始接收至接收完成)= time_total – time_starttransfer 。
echo 命令的作用是将输出的信息按照一定的格式写入到这个 /root/monitor_link.log 文本文件:
TIME=$(date "+%F %H:%M:%S") LOG_FILE=/root/monitor_link.log echo $TIME - 192.168.1.1 - webcheck - `curl ...(命令略)` >> $LOG_FILE
部署:
1、编写脚本,在命令行界面输入:
[root@host ~]# vi /root/monitor_link.sh
键入小写字母 i ,进入编辑模式,将以下脚本复制粘贴进去(请根据实际需要进行相应地修改):
#!/bin/bash # curl 命令 -w 的参数 W_PARAMETER='REDI:%{time_redirect}s - DNS:%{time_namelookup}s - CONN:%{time_connect}s - APP_CONN:%{time_appconnect}s - PRE_TRAN:%{time_pretransfer}s - START_TRAN:%{time_starttransfer}s - TOTAL:%{time_total}s\n' # 获取当前时间 TIME=$(date "+%F %H:%M:%S") # 日志文件存放位置 LOG_FILE=/root/monitor_link.log # /webcheck.htm 是一个静态文件 # /webservice 是需要测试的接口 #(1)192.168.1.1 为物理服务器,直接通过内网 IP 地址去访问静态文件 #(排除掉业务接口的干扰,仅测试单纯的 Web 服务器响应时间) echo $TIME - 192.168.1.1 - webcheck - `curl -m 2 -o /dev/null -s -w "$W_PARAMETER" http://192.168.1.1/webcheck.htm` >> $LOG_FILE #(2)www.test.local 为内网域名,该域名指向 192.168.1.1 这台物理服务器,通过内网域名去访问静态文件 #(排除掉业务接口的干扰,仅测试单纯的 Web 服务器响应时间 + 内网 DNS 域名解析的响应时间) echo $TIME - www.test.local - webcheck - `curl -m 2 -o /dev/null -s -w "$W_PARAMETER" http://www.test.local/webcheck.htm` >> $LOG_FILE #(3)192.168.1.1 为物理服务器,直接通过内网 IP 地址去访问需要测试的接口 echo $TIME - 192.168.1.1 - webservice - `curl -m 2 -o /dev/null -s -w "$W_PARAMETER" http://192.168.1.1/webservice` >> $LOG_FILE #(4)www.test.local 为内网域名,该域名指向 192.168.1.1 这台物理服务器,通过内网域名去访问需要测试的接口 echo $TIME - www.test.local - webservice - `curl -m 2 -o /dev/null -s -w "$W_PARAMETER" http://www.test.local/webservice` >> $LOG_FILE #(5)192.168.1.2 为 KVM 虚拟机,直接通过内网 IP 地址去访问需要测试的接口 echo $TIME - 192.168.1.2 - webservice - `curl -m 2 -o /dev/null -s -w "$W_PARAMETER" http://192.168.1.2/webservice` >> $LOG_FILE #(6)f5.test.local 为内网域名,该域名指向 F5 硬件负载均衡设备,F5 再指向 192.168.1.2 这台 KVM 虚拟机 ,通过指向 F5 的内网域名去访问需要测试的接口 echo $TIME - f5.test.local - webservice - `curl -m 2 -o /dev/null -s -w "$W_PARAMETER" http://f5.test.local/webservice` >> $LOG_FILE #(7)www.test.com 为外网域名,该域名先指向 A10 硬件负载均衡设备,A10 再指向 haproxy 代理服务器,haproxy 再指向 192.168.1.1 这台物理服务器,同时还要做 https 的加解密,通过外网域名去访问需要测试的接口 echo $TIME - https://www.test.com - webservice - `curl -m 2 -o /dev/null -s -w "$W_PARAMETER" https://www.test.com/webservice` >> $LOG_FILE echo ========================================================================================================================================================================= >> $LOG_FILE
按一次 ESC 键退出编辑模式,然后键入 “ :wq ” 保存并退出。
2、为上述脚本赋予可执行权限,并创建日志文件:
[root@host ~]# chmod +x /root/monitor_link.sh [root@host ~]# touch /root/monitor_link.log
3、让上述脚本每 30 秒钟自动运行一次,在命令行界面输入:
[root@host ~]# crontab -e
先键入大写字母 G ,跳到最后一行;再键入小写字母 o ,插入新的一行,并将以下命令复制粘贴进去:
* * * * * sleep 5; /root/monitor_link.sh * * * * * sleep 35; /root/monitor_link.sh
如果需要按分钟来执行,只需要这么写就可以了:
# 每分钟执行一次 */1 * * * * /root/monitor_link.sh # 每 3 分钟执行一次 */3 * * * * /root/monitor_link.sh # 每 30 分钟执行一次 */30 * * * * /root/monitor_link.sh
按一次 ESC 键退出编辑模式,然后键入 “ :wq ” 保存并退出。
因为 crontab 的最小时间单位是分钟,所以采用 sleep 的方式来实现秒级的运行。即同时创建两个自动任务:
- 第一个任务每分钟执行一次,是先休眠 5 秒钟后再执行 monitor_link.sh ;
- 另一个任务也是每分钟执行一次,是先休眠 35 秒钟后再执行 monitor_link.sh 。
这样就相当于只有一个任务,且每 30 秒钟执行一次。
至此,部署完成。
日志格式说明:
[root@host ~]# tail -11 monitor_link.log ========================================================================================================================================================================= 2018-06-29 22:10:31 - 192.168.1.1 - webcheck - REDI:0.000s - DNS:0.000s - CONN:0.001s - APP_CONN:0.000s - PRE_TRAN:0.001s - START_TRAN:0.006s - TOTAL:0.006s 2018-06-29 22:10:31 - www.test.local - webcheck - REDI:0.000s - DNS:0.006s - CONN:0.006s - APP_CONN:0.000s - PRE_TRAN:0.006s - START_TRAN:0.012s - TOTAL:0.012s 2018-06-29 22:10:31 - 192.168.1.1 - webservice - REDI:0.000s - DNS:0.000s - CONN:0.000s - APP_CONN:0.000s - PRE_TRAN:0.001s - START_TRAN:0.010s - TOTAL:0.011s 2018-06-29 22:10:31 - www.test.local - webservice - REDI:0.000s - DNS:0.006s - CONN:0.006s - APP_CONN:0.000s - PRE_TRAN:0.006s - START_TRAN:0.015s - TOTAL:0.016s 2018-06-29 22:10:31 - 192.168.1.2 - webservice - REDI:0.000s - DNS:0.000s - CONN:0.001s - APP_CONN:0.000s - PRE_TRAN:0.001s - START_TRAN:0.021s - TOTAL:0.022s 2018-06-29 22:10:31 - f5.test.local - webservice - REDI:0.000s - DNS:0.006s - CONN:0.006s - APP_CONN:0.000s - PRE_TRAN:0.006s - START_TRAN:0.034s - TOTAL:0.035s 2018-06-29 22:10:31 - https://www.test.com - webservice - REDI:0.000s - DNS:0.006s - CONN:0.006s - APP_CONN:0.151s - PRE_TRAN:0.151s - START_TRAN:0.175s - TOTAL:0.176s ========================================================================================================================================================================= [root@host ~]#
日志格式为:时间 – IP 地址或域名 – webcheck 静态文件或 webservice 接口 – REDI 时间 – DNS 时间 – CONN 时间 – APPCONN 时间 – PRE_TRAN 时间 – START_TRAN 时间 – TOTAL 时间
其中:
- REDI 时间是 time_redirect
- DNS 时间是 time_namelookup
- CONN 时间是 time_connect
- APPCONN 时间是 time_appconnect
- PRE_TRAN 时间是 time_pretransfer
- START_TRAN 时间是 time_starttransfer
- TOTAL 时间是 time_total
分析:
为了便于理解,先对上述脚本中的 7 个检测做一个简述:
- 测试机 → 物理服务器 192.168.1.1 → /webcheck.htm
- 测试机 → www.test.local → 物理服务器 192.168.1.1 → /webcheck.htm
- 测试机 → 物理服务器 192.168.1.1 → /webservice
- 测试机 → www.test.local → 物理服务器 192.168.1.1 → /webservice
- 测试机 → 虚拟机 192.168.1.2 → /webservice
- 测试机 → f5.test.local → F5 → 虚拟机 192.168.1.2 → /webservice
- 测试机 → www.test.com → A10 → haproxy → 物理服务器 192.168.1.1 → /webservice
上述 7 个检测的总延迟时间:
- 总延迟 = 网络延迟 + 不跑业务代码的情况下物理服务器的处理延迟
- 总延迟 = 网络延迟 + DNS 处理延迟 + 不跑业务代码的情况下物理服务器的处理延迟
- 总延迟 = 网络延迟 + 物理服务器的处理延迟
- 总延迟 = 网络延迟 + DNS 处理延迟 + 物理服务器的处理延迟
- 总延迟 = 网络延迟 + KVM 物理主机的处理延迟 + 虚拟机的处理延迟
- 总延迟 = 网络延迟 + DNS 处理延迟 + F5 处理延迟 + KVM 物理主机的处理延迟 + 虚拟机的处理延迟
- 总延迟 = 网络延迟 + DNS 处理延迟 + A10 处理延迟 + haproxy 代理服务器的处理延迟 + 物理服务器的处理延迟
从 “ 日志格式说明 ” 中的那份日志输出可以看出:
1、这里需要先说明的是:
- 如果请求没有使用到 DNS 域名解析,那么 DNS:0.000s;
- 如果请求没有使用到 https,那么 APP_CONN:0.000s;
- 如果请求没有使用到重定向,那么 REDI:0.000s 。
2、DNS 处理延迟大约为 6 毫秒( DNS:0.006s ),而且每次通过域名进行访问均要做一次 DNS 域名解析,如果使用 IP 地址直接访问则可以省下这 6 毫秒。
3、从第 1 条和第 2 条日志输出我们可以看到,从收到 Web 服务器返回数据的第一个字节到传输完成花费了 0 毫秒(以第 1 条为例:TOTAL:0.006s – START_TRAN:0.006s = 0.000s );而从第 3 、4 、5 、6 和 7 条日志输出我们可以看到,从收到 Web 服务器返回数据的第一个字节到传输完成均花费了 1 毫秒(以第 3 条为例:TOTAL:0.011s – START_TRAN:0.010s = 0.001s );因为静态文件 /webcheck.htm 里并没有存储几个字符,而接口 /webservice 返回的数据会比较多,所以花费的时间也多。
4、从第 1 条和第 3 条日志输出我们可以看到,第 1 条显示的总延迟为 6 毫秒( TOTAL:0.006s ),第 3 条显示的总延迟为 11 毫秒( TOTAL:0.011s ),那么访问接口 /webservice 比访问静态文件 /webcheck.htm 慢了大约 5 毫秒,毕竟在 Web 容器里跑业务接口的代码需要时间、将返回的数据传输到测试机也需要时间。
5、从第 3 条和第 5 条日志输出我们可以看到,第 3 条显示的总延迟为 11 毫秒( TOTAL:0.011s ),第 5 条显示的总延迟为 22 毫秒( TOTAL:0.022s ),那么虚拟机比物理服务器的总延迟慢了大约 11 毫秒。
6、从第 5 条和第 6 条日志输出我们可以看到,第 5 条显示的总延迟为 22 毫秒( TOTAL:0.022s ),第 6 条显示的总延迟为 35 毫秒( TOTAL:0.035s ),则第 6 条比第 5 条要慢了大约 13 毫秒,而这 13 毫秒的延迟中又有 6 毫秒是 DNS 处理延迟(第 5 条的 DNS 处理延迟为 DNS:0.000s ,第 6 条的 DNS 处理延迟为 DNS:0.006s ),那么剩下的 7 毫秒主要为 F5 硬件负载均衡设备的处理延迟。
7、从第 7 条日志输出我们可以看到,第 7 条的总延迟竟然高达 176 毫秒( TOTAL:0.176s ),而时间主要花费在了从 TCP 连接建立完成到应用层(SSL)连接 / 握手完成上,这段时间共花费了 145 毫秒( APP_CONN:0.151s – CONN:0.006s = 0.145 s );从应用层(SSL)连接 / 握手完成、准备开始传输数据至收到 Web 服务器返回数据的第一个字节共花费了 24 毫秒( START_TRAN:0.175s – PRE_TRAN:0.151s = 0.024 s )。
其他:
- NAMELOOKUP:从开始计算,域名解析完成的耗时
CURLINFO_NAMELOOKUP_TIME. The time it took from the start until the name resolving was completed. - CONNECT:从开始计算,TCP 建立完成的耗时
CURLINFO_CONNECT_TIME. The time it took from the start until the connect to the remote host (or proxy) was completed. - APPCONNECT:从开始计算,应用层(SSL,在 TCP 之上的应用层)连接 / 握手完成的耗时
CURLINFO_APPCONNECT_TIME. The time it took from the start until the SSL connect/handshake with the remote host was completed. (Added in in 7.19.0) - PRETRANSFER:从开始计算,准备开始传输数据的耗时
CURLINFO_PRETRANSFER_TIME. The time it took from the start until the file transfer is just about to begin. This includes all pre-transfer commands and negotiations that are specific to the particular protocol(s) involved. - STARTTRANSFER:从开始计算,开始传输数据的耗时(libcurl 接收到第一个字节)
CURLINFO_STARTTRANSFER_TIME. The time it took from the start until the first byte is received by libcurl. - TOTAL:总的耗时
CURLINFO_TOTAL_TIME. Total time of the previous request. - REDIRECT:整个过程重定向的耗时,如果整个过程没有重定向,这个时间为 0
CURLINFO_REDIRECT_TIME. The time it took for all redirection steps include name lookup, connect, pretransfer and transfer before final transaction was started. So, this is zero if no redirection took place.
发表评论?