这段时间,负责的App底座登录时,因为用户所处网络环境有问题,导致登录失败,而用户级别挺高,是业务的高层,直接投诉。导致我们必须优化登录和网络检测监控,除了加强链路和用户行为跟踪、修改提示语外,还必须添加一个网络诊断,让用户明白,这就是网络的锅,和我们代码或逻辑实现木有关系。
为此,经过搜索了网络诊断的资料,经过整理,还需要考虑移动App的实现,得出以下技术方案。
上述是真正背景和需求缘由。
1、背景
一个App功能的整体表现,往往与用户当前的网络状况密不可分。当客户端处于弱网或本地网络异常时,我们的App存在两个缺点:
1、目前没有收集此时客户端的本地网络信息导致用户报障时无法准确排查问题。
2、目前客户端没有提供用户主动网络诊断的入口,用户无法直观知道究竟是自己网络问题还是App后端服务问题。
如果可以为App提供一个的网络诊断功能,让用户明确功能出现阻断的原因,既可以提高用户体验,还可以收集那些能够衡量当前网络状况的重要信息。然后在征得用户同意的情况下,将信息上报到服务端进行分析,可以有针对性地对网络链路中的薄弱环节进行优化。
这里的网络诊断主要是针对特定的域名或者ip,也就是说App的网络诊断是对当前网络到域名指向的服务端的连通性和带宽情况。
1.1 导致本地网络异常的原因可能有
- 断网
- DNS挟持、DNS解析出错
- 本地代理异常
- 防火墙拦截
1.2 对应的诊断方式
- 系统API判断是否有网络接连
- 查看本地DNS服务
- 查看本地代理配置
- Traceroute拨测相关域名
- 通过HTTP发送HEAD或GET请求模拟浏览器的访问行为来检查会请求到的后端服务
2. 网络诊断的工具
常用的网络工具或者方式,包括ping、DNS、traceroute、网络测速
2.1 PING 测试
通过 ping 后端服务地址得到的信息诊断当前网络跟服务器是否畅通以及丢包率。比如:
正在 Ping xxx.xxx [10.18.43.243] 具有 32 字节的数据:
来自 10.18.43.243 的回复: 字节=32 时间=5ms TTL=250
来自 10.18.43.243 的回复: 字节=32 时间=4ms TTL=250
来自 10.18.43.243 的回复: 字节=32 时间=4ms TTL=250
来自 10.18.43.243 的回复: 字节=32 时间=5ms TTL=250
10.18.43.243 的 Ping 统计信息:
数据包: 已发送 = 4,已接收 = 4,丢失 = 0 (0% 丢失),
往返行程的估计时间(以毫秒为单位):
最短 = 4ms,最长 = 5ms,平均 = 4ms
android可以通过下边的代码发送命令:
val command = "ping -c $packageCount -w 15 -t $ttl $url"
Runtime.getRuntime().exec(command)
2.2 DNS 解析
DNS(Domain Name System),它的作用就是根据域名,查出对应的 IP 地址,它是 HTTP 协议的前提。只有将域名正确的解析成 IP 地址后,后面的 HTTP 流程才可以继续进行下去。
DNS 服务器的要求,一定是高可用、高并发和分布式的服务器。它被分为多个层次结构。
- 根 DNS 服务器:返回顶级域 DNS 服务器的 IP 地址。
- 顶级域 DNS 服务器:返回权威 DNS 服务器的 IP 地址。
- 权威 DNS 服务器:返回相应主机的 IP 地址。
这三类 DNS 服务器,类似一种树状的结构,分级存在。
当开始 DNS 解析的时候,如果 LocalDNS 没有缓存,那就会向 LocalDNS 服务器请求(通常就是运营商),如果还是没有,就会一级一级的,从根域名查对应的顶级域名,再从顶级域名查权威域名服务器,最后通过权威域名服务器,获取具体域名对应的 IP 地址。
如果LocalDNS 被挟持时,可以将服务器host解析成其他IP地址。例如xxx.xxx 本应解析为10.18.43.243,被挟持后解析成10.33.1.1,导致应用访问这个host连接都失败。
同样地,本地DNS缓存没有时,如果LocalDNS 解析host错误或无法解析host同样时导致应用访问这个host连接都失败。
应用可以通过API查询LocalDNS 服务器,例如
> var dns =require('node:dns');
> dns.getServers()
< ['10.18.0.100', '10.16.11.106']
ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE);
for (Network network : connectivityManager.getAllNetworks()) {
NetworkInfo networkInfo = connectivityManager.getNetworkInfo(network);
if (networkInfo.isConnected()) {
LinkProperties linkProperties = connectivityManager.getLinkProperties(network);
return linkProperties.getDnsServers();
}
}
查询LocalDNS 域名解析
node js
> dns.lookup('xxx.xxx', (err, address) => {
console.log(address);
});
< 10.18.43.243
android
InetAddress.getAllByName("xxx.xxx")
2.3 Traceroute 拨测
Traceroute (Windows 系统下是tracert) 命令利用ICMP 协议定位您的计算机和目标计算机之间的所有路由器。TTL 值可以反映数据包经过的路由器或网关的数量,通过操纵独立ICMP 呼叫报文的TTL 值和观察该报文被抛弃的返回信息,Traceroute命令能够遍历到数据包传输路径上的所有路由器。
Traceroute是用来侦测主机到目的主机之间所经路由情况的重要工具,也是最便利的工具。尽管ping工具也可以进行侦测,但是,因为ip头的限制,ping不能完全的记录下所经过的路由器。所以Traceroute正好就填补了这个缺憾。
Traceroute收到目的主机的IP后,首先给目的主机发送一个TTL=1的UDP数据包,而经过的第一个路由器收到这个数据包以后,就自动把TTL减1,而TTL变为0以后,路由器就把这个包给抛弃了,并同时产生 一个主机不可达的ICMP数据报给主机。主机收到这个数据报以后再发一个TTL=2的UDP数据报给目的主机,然后刺激第二个路由器给主机发ICMP数据 报。如此往复直到到达目的主机。这样,traceroute就拿到了所有的路由器ip。从而避开了ip头只能记录有限路由IP的问题。
通过最多 30 个跃点跟踪
到 xxx.xxx [10.18.43.243] 的路由:
1 8 ms 8 ms 4 ms 10.74.31.1
2 3 ms 3 ms 2 ms 210.73.1.94
3 5 ms 5 ms 4 ms 310.16.252.210
4 3 ms 3 ms 3 ms 410.16.252.254
5 11 ms 6 ms 5 ms 510.16.252.233
6 * * * 请求超时。
7 11 ms 4 ms 6 ms 710.18.240.18
8 * * * 请求超时。
9 13 ms 5 ms 4 ms 910.18.43.243
跟踪完成。
发送命令的实现方式与ping一样
3 计划
3.1 网络异常时上报本地网络信息
上报内容为 网络类型,本地IP地址、本地DNS 服务器、域名解析地址、设备出口IP,本地代理。
设备出口IP需要提供HTTP接口来获取,具体为客户端请求HTTP接口,服务端把请求的接入IP返回给客户端。
大致上报信息为
|
3.2 客户端网络诊断功能
竞品界面
具体检查点:
- 检查网络是否断开
- 检查是否设置了代理
- 检查是否能拿到本地DNS服务、检查HOST是否能解析成功
- 检查服务器稳定性,通过HTTP HEAD 后台服务的HOST列表,列出那些服务不正常
流程图:
检查的结果要写入到日志文件,格式待定。
参考:
手把手教你搭建应用的网络诊断模块(1)——Ping与TraceRoute - 简书