网络延迟的成因与解决策略

背景

网络对于提供在线服务应用程序的重要性自然是不言而喻的,因此如何监控也是一个非常耗费精力的问题。因为一般的内部监控无法满足此需求,许多大家耳熟能详的监控工具,例如:Prometheus,SkyWalking,Zabbix等,都是搭建在内部网络(Intranet)从内部进行监控,与来自世界各地的一般用户是完全不同的出发点,所以会有监控上的盲点,看着绿油油的仪表板想说一切都好好的啊!但真实用户却已经火冒三丈,客服电话也已经被打到满线。

这种情况就需要外部的监控服务来模拟一般用户行为,用以确保服务是否在正常运作中。而在外部网络的监控中,通常会有哪些重点需要注意,遇到问题的时候又该如何找出症结点,便是这篇文章想要分享的内容。

资源获取耗时组成

在开始提到网络监控之前,先来看看当一个用户发出HTTP请求时,到底经过了哪些过程,如此我们才能够知道所需要注意的重点有哪些。

  • 重定向:请求是否需要被重新定向,耗费的时间当然就是从重定向开始到结束。

  • 应用缓存:如果客户端在本地端已经有缓存的话,请求的内容就可以直接从本地端读取,不用再耗费网络资源。

  • DNS查询:网络世界的沟通通常都会使用网址,而不会直接使用IP地址,所以一定有通过DNS服务器查找真实IP地址的需求,耗费的时间就是从查询开始到取得结果的时间。

  • TCP连接:跟查询到的目标服务器创建TCP连接所需要的时间,不过需要特别注意假如要创建的是TLS或是SSL的安全加密连接的话,这边还会有握手的发生。

  • 请求:进行到请求阶段,就是请求被发送到服务器端所需要的时间。

  • 响应:这个阶段的时间就是远端服务器将结果回传给提出请求客户端的时间。

看完上面之后,可以发现要创建一个HTTP的连接要经过很多的步骤,在成功收到响应之前,必须要跟远端的服务器来来回回,因此任何一个阶段中客户端和服务器的连接出了问题,或是需要的时间变长了,都可能会导致应用程序出现不预期的结果。

常见网络问题

所以突然从外部监控服务收到警报时,但是内部监控系统都还好好的,就可以开始从上面提到的每个阶段来看看问题是出在哪里,不过在开始寻找问题之前,有一件很重要的事情要先做!确保自己使用的网络环境跟真实用户一样的!例如:hosts文件是干净的没有乱改过,不是使用可以连接到内联网的环境等,不然还是会跟内部监控一样地遇到盲点。

DNS查询

首先一定要试试看,可不可以解析的到请求网址的IP地址,因为搞不好就是DNS设置错误导致连接失败,下面是用google.com当作范例,可以看到去8.8.8.8 DNS Server后有问到google.com的IP地址,当查询出来的结果有符合预期的话,那表示问题不在这里,让我们继续往下找,不然就要去看看DNS记录哪里设置错误了。

makefile 复制代码
# 查询成功
~$ nslookup google.com 8.8.8.8
Server:  8.8.8.8
Address: 8.8.8.8#53
Non-authoritative answer:
Name: google.com
Address: 216.58.200.238
# 查询失败
> nslookup google.com 8.8.8.8
Server:  8.8.8.8
Address: 8.8.8.8#53

Telnet服务端口

接下来要怀疑到会不会是防火墙的设置有问题,假设服务开启的Port是443好了,一样以Google来当作范例,使用telnet的话应该可以发现连接可以被创建成功。

csharp 复制代码
# 连接成功
~$ telnet google.com 443
Trying 172.217.27.142...
Connected to google.com.
Escape character is '^]'.

遇到连接失败的话,通常是防火墙端设置有问题,可以先查看 443 端口是否真的有对外开放;而现在的外部监控服务通常都可以从多个区域同时监控,因此假如发现只有某一个或是某些区域遇到连接问题,就可以怀疑到CDN的设置,是不是有阻挡掉某一个区域,或是在防火墙上没有允许某一个区域的CDN Edge过来进行连接。

SSL证书

上面进行TCP连接阶段时,有提到想要创建的是安全连接的话,会进行SSL Handshake,所以连接失败也有可能是证书发生问题,譬如常见问题就是遇到证书过期了,而现在外部监控服务,其实也都有检查证书是否过期的功能,记得要把它设置起来。

ini 复制代码
# 用CLI查询网站的证书有效期限
cho | openssl s_client -servername www.google.com -connect www.google.com:443 2>/dev/null | openssl x509 -noout -dates
notBefore=Aug 11 08:59:33 2020 GMT
notAfter=Nov  3 08:59:33 2020 GMT

网络延迟问题

上面是比较常见一些的错误,都是完全无法连接且跟应用程序不相关的情况,但要是收到的警报是响应时间过长了,又该如何查出问题在哪里呢?但在开始找问题之前,可以先到 wondernetwork.com/pings 这个网站瞧一瞧,因为网络的速度对于地理上的位置/线路来说是影响很大的,自己的服务架设在哪里,而监控的区域/实际使用者又落在哪个地方,他们之间的网络延迟时间基本消费是多少,可以先在这个网站查到,让自己的心裡有个底。

Chrome DevTools

最简便又好用的分析问题工具,就是大家电脑都安装的Chrome DevTools,它可以拿来分析网络连接时每个阶段耗费的时间(Queueing & Stalled 是指开始执行动作前的等待时间,跟网络无关)。

  • DNS查询:查找真实IP地址时间应该会落在10 ms以内,但超过的话,可以试试看一些缩短时间的做法,例如使用比较快的DNS Provider,改变DNS Cache的TTL,减少需要连接的Domain,DNS Prefetching,使用ANAME Records等。

  • SSL:SSL Handshake 所需要耗费的时间可能会落在100 ms左右,不过要是测试时看到超过正常值很多的夸张数值,就可以试着去查查看问题在哪里。

  • TTFB:全名為 Time To First Byte,就是指客户端跟服务器端创建完连接后,收到第一个Byte所需要的时间,落在100ms以下算是很快的,Google PageSpeed Insights建议落在200ms以下,一般可能会落在300~500左右,但是超过600 ms可能就要注意了,要缩短时间的话,应用程序端有很多事情可以做,例如加快程序运行的速度,缩短数据库查询时间,增加Cache机制(不过这些跟网络都没有关系就是了);而为了让传递数据的速度变快,可以通过使用CDN缩短客户端和服务器间的实体传递距离。

  • 内容下载:则是从服务器端接收数据所需要的时间,这一段也跟网络传递速度比较有关系,理所当然可以通过CDN加速。

Curl

喜欢使用CLI工具查找问题的人可以直接使用Curl即可,创建名称为curl-format.txt的文件,然后内容如底下所示

css 复制代码
time_namelookup:  %{time_namelookup}s\n
       time_connect:  %{time_connect}s\n
    time_appconnect:  %{time_appconnect}s\n
   time_pretransfer:  %{time_pretransfer}s\n
      time_redirect:  %{time_redirect}s\n
 time_starttransfer:  %{time_starttransfer}s\n
                    ----------\n
         time_total:  %{time_total}s\n

接着就可以使用Curl来获取跟Chrome DevTools差不多的信息,从各个阶段所耗费的时间取得问题发生的主要原因是什么

php 复制代码
~$ curl -w "@curl-format.txt" -o /dev/null -s "https://www.google.com/"

MTR

在服务器端什么都没有修改,而且内部监控也显示响应时间正常,但从外部监控服务就是可以看到响应时间明显变长,而且持续了两三天以上,这时候就必须要请出MTR这个查找路由耗费时间的工具,然后把查询的结果附在Support Ticket内了。MTR其实算是Ping跟Traceroute/Tracert两个工具的合体,他会丢出数个ICMP数据包给客户端连线到服务器间的所有hop,因此可以从中得知很多有用的信息。

例如从上图可以知道连去Google总共会经过12个hop,数据包都没有遗失的现象,送出10个数据包的回复时间都相当的低,落在10 ms左右(他会列出平均,最佳,最差和最后的 时间值),而最后一栏标准差则是用来判定连线的稳定度。

当观察到前面三个hop数据包的频率很高或是花的时间特别久,那可能就是客户端的ISP比较有嫌疑,而如果是最后三个hop有问题的话,那就变成是服务器端的ISP比较有嫌疑;而通常会建议取得双向的MTR信息(从客户端到服务器,以及从服务器到客户端)这样分析问题起来比较准确。

有一种现象是观察到某一个hop漏数据包的频率冲高或是花的时间特别久,可以持续观察一下他的下一个或是下几个hop取得的数值是不是正常的,因为有时候可能只是某个hop有设定Rate Limit,所以导致数值在他身上会飙高,但后续的hop又会恢复正常,这样的情况很常见,而且是没有问题的。

结论

网络问题百百种,此文章把一些自己个人常见的问题写下来,除了当成自己的学习笔记之外,也希望可以不小心帮助到需要的人,不过当问题落在需要使用MTR的话,其实会花比较多时间,为什么呢?

因为现在的网路服务通常都是 CDN 搭配上公有云服务,甚至是其他的第三方服务, 假如 MTR 最后的 hop 落在 CDN ,公有云或是其他第三方服务的话,就要花比较多时间跟多间第三方厂商来来回回,有时会遇到自己这边什么事情都没有做,但问题就突然自己解决了,最苦的是最后通常也不会找到真正的原因,只能猜测是 ISP 或是第三方厂商的网络部门把路由又改回原本正常的状态了吧?!所以会建议等个两三天之后,情况一直没有改善再花时间去排查问题

相关推荐
Estar.Lee20 分钟前
查手机号归属地免费API接口教程
android·网络·后端·网络协议·tcp/ip·oneapi
傻啦嘿哟1 小时前
代理IP在后端开发中的应用与后端工程师的角色
网络·网络协议·tcp/ip
向阳12182 小时前
Dubbo HTTP接入之triple协议
网络协议·http·dubbo
2401_857610032 小时前
SpringBoot社团管理:安全与维护
spring boot·后端·安全
凌冰_3 小时前
IDEA2023 SpringBoot整合MyBatis(三)
spring boot·后端·mybatis
码农飞飞3 小时前
深入理解Rust的模式匹配
开发语言·后端·rust·模式匹配·解构·结构体和枚举
一个小坑货3 小时前
Rust 的简介
开发语言·后端·rust
monkey_meng3 小时前
【遵守孤儿规则的External trait pattern】
开发语言·后端·rust
Estar.Lee3 小时前
时间操作[计算时间差]免费API接口教程
android·网络·后端·网络协议·tcp/ip
新知图书4 小时前
Rust编程与项目实战-模块std::thread(之一)
开发语言·后端·rust