网络自助诊断1: 基础篇

叁叁肆2018-10-25 11:29

此文已由作者徐城利授权网易云社区发布。

欢迎访问网易云社区,了解更多网易技术产品运营经验。

前言

相信大家平时都碰到过一些网络相关的问题,如服务无法访问或比较慢,VPN不通等;有时自己写的程序碰到一些问题总觉得像是网络的原因。可等找到别人来诊断时,当时的场景已经不在了。那有没有简便的方法先自己来做个初步的分析呢?其实这也不难,就让这篇文章先来个抛砖引玉吧。

网络分层与地址

网络课程最开始就教我们一个OSI七层模型,平时我们说得最多的二层、三层、四层、七层一般也基于这个模型,(如果连这个七层模型都不记得了,那先去墙角反省一下)。 不过有人说了,现在都是TCP/IP协议了,明明只有四层,那TCP/IP协议的分层到底如何对应OSI分层呢?简单来说,第二层的IP/ICMP对应OSI的三层,即网络层,第三层的TCP/UDP等对应第四层的传输层,第四层的HTTP/DNS/IRC等等对应第七层(之前有没有奇怪为什么都说L4负载均衡和L7负载均衡,而没有L5/L6负载均衡?) 为什么没说TCP/IP的第一层,是否对应物理层加数据链路层?严格来说不对:TCP/IP只定义了和物理层的接口(如用于以太网的ARP/RARP),而没有定义下面的协议,因此有人把ARP称作2.5层协议。

L2: 以太网 (Ethernet)

说起以太网,大家第一个想起的是不是共享介质什么的?因为以前的书上都这么说的,不过那都是远古年代的东西了,现在大部分都是点到点的连接。不过以上不是今天的重点,纯粹用来凑字数的。

MAC地址、单播、多播与广播

MAC (Media Access Control Address) 用于标识网络接口的物理地址,现在用得最广的是48位,例如 "01:23:45:67:89:ab"。Linux上可以通过ip link命令,或ifconfig命令查看本地设备的MAC地址。

~$ ip l show dev eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UPmtu 1500 qdisc mq state UP mode DEFAULT group default qlen 1000
link/ether e4:1f:13:7b:cf:28 brd ff:ff:ff:ff:ff:ff

当目标MAC地址第一个字符的最低位为0时,表示这个帧将被唯一的一个网络接口设备接收,其他在非混淆模式下的网络接口设备会忽略它,即单播(Unicast),如云计算中为每个端口分配的MAC地址都是以fa(11111010)开头。相应的,如果第一个字符最低位为1是,表示这个帧将被所有配置了这个地址的网络接口设备接收,即多播(multicast)。而当每一位都是1(ff:ff:ff:ff:ff:ff)时,位于同个网络内的所有设备都会接收这个帧,即广播(broadcast)。

VLAN

Virtual LAN将网络在二层分隔成各个不同的广播域,用于隔离和减少广播风暴,简化网络的部署与管理。在使用上,VLAN一般有两种模式:

  • Trunk mode: 当一个口被配置成trunk模式时,可以有多个VLAN的帧通过这个端口,而每个帧头中都会带VLAN信息(802.1q,如果配置了默认VLAN,那属于默认VLAN的帧可能没有VLAN头,即没VLAN头的都属于默认VLAN)

  • Access mode: 当一个口被配置成access模式时,只有这个VLAN的帧可以通过这个端口,这时从这个端口出来的帧头中一般没有VLAN头。

例如,在Linux中,如果eth0对应的交换机端口配置成trunk模式且允许100和101两个VLAN,如果我们直接在eth0上抓包,那每个帧都会带有VLAN头,VID可能是100或101,Linux中一般通过VLAN设备eth0.100和eth0.101来接收对应的VLAN的帧。而当eth0对应的交换机端口配置成access模式且VLAN Tag为100时,这时eth0上收到的帧是没有VLAN头的,而eth0接入的是VLAN 100。

L3: IP与路由

IPv4

IPv4使用32位长度来表示网络地址,其中每个地址又包含了两部分信息:网络标识和主机标识。早期按网络标识的长度,将IP地址分成A、B、C、D和E类(Classful),随着IP地址需求的增加,后来使用CIDR(Classless Inter-Domain Routing)代替,使得网络标识可以是任意位,并能拆分成更小的地址空间。例如,192.168.0.0/16,当它的后16位(主机标识位)全为0时,即192.168.0.0表示这个网络,而当后16位全是1地,即192.168.255.255表示到这个网络的广播,这段地址又能被拆成两个子网络,192.168.0.0/17和192.168.128.0/17。 在Linux中可以通过ifconfig或ip address命令对IP地址进行管理。

~$ ip a show eth0.100
5: eth0.100@eth0: <BROADCAST,MULTICAST,UP,LOWER_UPmtu 1500 qdisc noqueue state UP group default
link/ether e4:1f:13:7b:cf:28 brd ff:ff:ff:ff:ff:ff
inet 10.180.0.86/22 brd 10.180.3.255 scope global eth0.100
inet6 fe80::e61f:13ff:fe7b:cf28/64 scope link
   valid_lft forever preferred_lft forever

路由

路由(Routing)一般指在网络中选择相对较优的路径,这里主要讨论Linux内核中的实现。Linux的实现适合在简单的网络环境下定义路由规则,而在互联网等这种复杂而巨大的网络中,一般有专业的路由设备使用BGP等路由协议。 路由一般到少分为两类:

  • local: 如果目标IP地址属于系统本身(无论配置在哪个网络设备上)

  • link: 目标地址和本机器在同一个二层网络内

  • global: 其他地址都属于每三类,即不是本机地址,也没有直接相连,这种情况下需要一个在同个二层内的网关或路由器。

在Linux中,我们可以使用ip route或route命令查看当前的路由:

~$ ip r show
default via 115.236.124.1 dev eth1
10.0.1.0/24 dev ovsbr  proto kernel  scope link  src 10.0.1.1
10.160.252.0/22 via 10.180.0.223 dev eth0.100
10.180.0.0/22 dev eth0.100  proto kernel  scope link  src 10.180.0.86
10.180.8.0/22 dev eth0.102  proto kernel  scope link  src 10.180.8.86
115.236.124.0/24 dev eth1  proto kernel  scope link  src 115.236.124.86

也可以测试哪条路由生效以及可能选择的源地址:

~$ ip r get 127.0.0.1
local 127.0.0.1 dev lo  src 127.0.0.1
    cache <local ipid 0xd7aa
~$ ip r get 10.180.0.24
10.180.0.24 dev eth0.100  src 10.180.0.86
    cache
~$ ip r get 114.114.114.114
114.114.114.114 via 115.236.124.1 dev eth1  src 115.236.124.86
    cache

L4: 五元组与socket

在网络程序或防火墙等应用中,我们经常接触到连接这个概念,那怎样才算是一条连接呢,或者一个系统的最大连接数受哪些限制呢?这其中就不得不提五元组:传输层协议、源IP、源端口、目标IP和目标端口,这五个要素确定了一条连接,因此一个客户端往同个服务一般只能发起6万个连接,但作为服务端却可以接受几十万甚至百万的连接。 在Unix-like系统中,使用socket来处理一条连接的数据读写,因此每个socket都由一个五元组确定。socket不仅是开发网络程序必不可少的接口,也是诊断网络问题时必须关注的。 Linux经常用netstat或ss命令查看socket相关信息: 例如查看下当前系统使用socket的总览信息:

~$ ss -s
Total: 136 (kernel 0)
TCP:   23 (estab 4, closed 4, orphaned 0, synrecv 0, timewait 2/0), ports 0

Transport Total     IP        IPv6
*         0         -         -
RAW       0         0         0
UDP       14        11        3
TCP       19        13        6
INET      33        24        9
FRAG      0         0         0

如果看到大量的time_wait、synrecv、close_wait、orphaned等状态的socket,可能就要引起注意了。 接下来可以查看具体的连接状态,比如查看本地1046端口相关的连接:

~$ ss -io ss state established src :1046
Netid  State      Recv-Q Send-Q   Local Address:Port   Peer Address:Port
DIAG answers 22
tcp    ESTAB      0      80      115.236.124.86:1046   125.120.208.178:55705
 timer:(on,228ms,0)
         sack cubic wscale:8,7 rto:232 rtt:32/20 ato:40 mss:1452 cwnd:10 send 3.6Mbps unacked:1 rcv_rtt:149212 rcv_space:40256

其中,Local表示本系统(无论是服务端或客户端),Peer或Foregin表示无端的地址和端口,除了状态等信息,比较需要关注的是Recv-Q和Send-Q这两个数值,在Established状态下,如果Recv-Q中的数值一直很高一般表示使用这个socket的应用程序来不及处理或程序本身有问题,如果Send-Q中的数值一直很高,那可能是网络拥塞,也可以是对端接收方处理不及时,这时需要检查对端socket的Recv-Q。

最后

这一篇介绍了一些很基本但在处理网络问题中又必须的一些知识,当然由于篇幅和能力也没法详细展开了。其中介绍的一些工具也有更多的功能,manpage和官方文档是个很好的学习资料。在一下篇中,我们将结合这篇中介绍基本知识,看看如何诊断一些常见的问题。


网易云免费体验馆,0成本体验20+款云产品! 

更多网易技术、产品、运营经验分享请点击


相关文章:
【推荐】 iOS安装包瘦身(上篇)