(2)网络世界的机器是如何连接起来的

221 阅读12分钟

网络的组织结构

所有的故事从一张图开始

机器之间是怎么连接的.png

图中的网络结构由三个虚线框组成,每一个虚线框表示一个网段,同一网段内部的机器都插在二层交换机上,而网段之间靠三层交换机连起来。

可以看众多机器之间是靠交换机来组成网络的,但是二层交换机和三层交换机有什么区别呢?

二层交换机

二层交换机作用于数据链路层(从物理层往上数第二层)。它的核心功能就是,从接收到的网络包中,取出MAC头,拿到目标机器的MAC地址后,找到目标机器的MAC地址该从哪一个端口出去,然后把网络包复制到这个端口上。

Docker中有个docker0网桥、Kubernetes中有个cni0网桥,这都是作用于数据链路层的设备,干的就是这个活。

[容器网络]  近期在学习kubernetes时网络模型时,跨住容器间的网络模型,如Flannel,Calico,原理理解起来有点绕,通过复习网络相关的基础知识后清晰了不少,后面打算整理下容器网络的学习过程。

机器刚接入二层交换机某个端口的时候,是不知道这个端口对应机器的MAC地址的。更复杂的情况是,这个端口可能接入另一台交换机B,而交换B也可能接入多台机器,那这个端口可能对应着多个MAC地址。那交换机怎么知道这些信息呢?

这需要一个学习的过程。比如图中网段A的机器1对机器2发起一个HTTP请求时:

  • 机器1的HTTP网络包到了交换机之后,目前交换机虽然不知道该往哪个端口复制,但是网络包一定有源MAC地址,于是它知道了机器1的MAC地址对应哪一个端口。
  • 接下来它对其他所有端口都复制了网络包,其他连上这台交换机的机器以及另一台交换机都会收到数据包,另一条交换机在不知所措的时候自然也会广播所有端口。
  • 机器2收到广播后会主动响应。在这个过程过后,交换机都知道了机器2的MAC地址对应哪一个端口。
  • 交换机在这个过程后,会把学习成果记在地址表中。以后找机器1和机器2都不需要广播了。学习的次数越多,地址表就越趋近于完善。

这个地址表,大概是这个样子

MAC地址端口其他信息
08:00:20:0A:8C:6D1......
08:00:20:0A:8C:7D1......
08:00:20:0A:8C:8D2......
08:00:20:0A:8C:9D3......

二层交换机主要实现了转发的功能,它不会改变网络包中的源MAC地址和目标MAC地址,更不可能改变源IP地址和目标IP地址,这和下面要介绍的三层交换机是不同的。

三层交换机

似乎只用二层交换机就能组织网络了,事实是不可能的,都在同一个网段,先不说机器足够多的时候,IP地址够不够用,一台交换机要它学习那么多机器的MAC地址,也是不现实的。

不同的网段得靠三层交换机来连接它们。

三层交换机作用于网络层。它会取出MAC头和IP头,找到目标IP的对应的端口,然后把网络包复制到该端口。

和二层交换机不同的是:二层交换机的端口对应的是具体的MAC地址。而IP地址具有定位功能的,所以三层交换机可以做到端口和网段对应上。

在讨论二层交换机的时候,交换机本身是没有MAC地址和IP地址,它只会转发自己接收到的网络包。而三层交换机则不一样,它充当了网段的网关,所以会和网段内的其他机器一样,有自己的MAC地址和IP地址。而且三层交换机是个"多面手",从图中可以看到,这个三层交换机同时充当了三个网段的网关,所以它有三个IP地址和三个MAC地址。

路由器就是一个三层交换机

三层交换机充当网关,当网关也有不同的情况

转发网关

当机器1向机器4发起跨网段的HTTP请求时:

  • 假设机器1的IP地址是192.168.1.10,机器4的IP地址是192.168.2.10

  • 机器1发现机器4和自己不在同一个网段,它是没法知道对方的MAC地址的

    • 二层交换机学不了其它网段的机器信息
  • 于是机器1只能先把网络包先发给网关,让它去想办法

    • 先要通过ARP协议获取网关的MAC地址
    • 机器1构建MAC头的时候,目标MAC地址实际上是网关的地址,而不是真正的目标MAC地址
  • 三层交换机拿到网络包后,取出IP头中的目标IP地址,根据路由规则,要去192.168.2.10/24得走192.168.1.1这张网卡对应的端口,就找到了目标机器4。

    • 交换机构建网络包转发到目标机器4时,源MAC地址是交换机的,目标MAC地址是机器4的

从这个例子中发现机器1发到机器4的网络包的MAC头经过"每一跳"是会变化的,而IP头是没变过的。但是三层交换机一定不会改变IP头吗?肯定不是,以上的那种不变的情况的网关叫转发网关,下面要提到的是NAT网关

NAT网关

如果不同的网段,网段号是一样的怎么办?在大型一点网络中,这个是很常见的情况。

NAT网关过程.png

比如机器1的IP地址192.168.1.10,机器4的IP地址也是192.168.1.10,它们之间通信该怎么发包。

前提条件是,每个机器都需要一个唯一的IP,可以理解为这个大的网络内的公网IP,比如机器1的公网IP是192.168.58.10,机器2的公网IP是196.168.59.10

  • 机器1发包构建IP头的时候,需要把目标IP地址,换成它对应的公网IP,然后发给了网关。此时源IP是机器1的普通IP,目标IP是机器2的公网IP。
  • 网关1解出IP头,由于机器A发出的网络包也要在这个网络上流通,它会将源IP改成机器1的公网IP。通过路由规则,它发现去196.168.59.10对应的端口,将网络包转发出去。
  • 网关2收到包后,它的配置发现,访问196.168.59.10就是对应访问192.168.1.10,会把网络包的目标IP换成192.168.1.10,然后通过对应的端口发出去。
  • 机器2收到网络包

NAT的全称是Network Address Translation,转化IP地址的意识,上诉的例子也看到了,网关转发的过程中修改了IP地址。但是何时该NAT,怎么准确NAT,它有自己非常复杂的逻辑。我作为程序员而非专业的网络工程师,暂时到此为止了。

家里的网络访问B站之类部署在公网的服务,运营商网关也将的私有IP地址NAT成公网IP地址了,服务器响应回来时,又NAT回我的私有IP地址,从而接收到对方的网络包。

到这里还留下了两个问题:

1.二层交换机每个端口都对应着MAC地址,有没有可能网络包从自己的一个端口出去,又回到自己的另一个端口了,这样交换机的世界观都崩塌了。其实也就是形成环路了,该怎么解决?

2.三层交换机的路由规则是怎么维护的?

交换机环路问题

交换机环路问题.png

  • 要是交换机出现了这种环路问题,这个数据包是不可能发出去。

有一个数据链路层的协议叫STP协议,它通过算法的,将带环的图,打破成最小生成树,就解决了环路的问题。

  • 打破不是去拔人家网线,是通过算法避免将一个包环路发送。
  • 算法的具体内容也不在这里描述,我觉得这不是网络的核心内容,然后我好像也写不太清楚。总之有了STP协议,妈妈再也不用担心二层交换机的环路问题了。

配置路由规则

以上例子中,三层网关怎么准发,都靠路由规则,规则是一个路由表:

目标地址(Destination)子网掩码(Netmask)网关(Gateway)接口(Interface)跃点数(Metric)
10.10.1.0255.255.255.0-e21
10.10.1.101255.255.255.255-e21
192.168.1.0255.255.255.0-e31
192.168.1.10255.255.255.255-e31
0.0.0.00.0.0.0192.0.2.1e11
  • 当三层交换机接收到网络包时,解出目标IP地址后,通过子网掩码可以计算出目标地址,从表中找到对应的接口(端口)或者下一跳的网关地址,然后做转发。到找不到的时候就会走目标地址为0.0.0.0这一条规则
  • 跃点数表示距离目标IP地址的远近

但是它是怎么维护的呢?

最简单的就是手动配置,也就是静态路由

静态路由

这没啥说的,根据命令去配置就行了

动态路由

所有的路由规则都去手动配置也是不现实的,IP层有相关的路由协议可以生成动态路由表

首先需要提到两类算法

动态路由算法

首先是距离动态矢量路由(distance vector routing),基于Bellman-Ford算法

1.距离矢量路由算法

  • 路由表有很多行,每一行的信息可以分为两部分:目标地址、自己距离它多远(跃点数)

路由器都要知道全局信息的话,它得不断更新,过程是:

  • 每个路由器肯定知道自己和邻居之间的距离,比如新路由器A加入了,它的邻居路由器B知道了,于是路由器B的路由表中多了一行记录:路由器A以及距离
  • 每过几秒,路由器会告诉邻居自己所掌握的全部路由表信息,于是路由器B告诉了C。注意C和B是邻居,C和A不是。
  • C收到B的发来的路由表后,发现A距离B是X,自己和B距离是Y,所以C会增加一条:路由器A的IP地址以及距离X+Y
  • 一会后消息传遍了整个网络,所有的路由器都知道A来了,且知道A离自己多远

它有两个问题:

1.A突然下线了,此时B不知道A下线了,B找A时,发现自己找不到,但B以为C知道,因为C的路由表原本是存了A的信息的,然后B会以为自己到A的距离是自己到C的距离加上C到A的距离, 然后更新自己的路由表。而这条信息是无用的,可怕的是这条无用的消息还会继续传播。

2.每次同步信息时,都是发送全局路由表,这个开销有点大

2.链路状态路由算法

另一类算法是链路状态路由(link state routing),基于Dijkstra算法

重在一个状态,路由器是否还存活的状态

当新路由器A加入时,会给自己的邻居们发一个echo命令

  • echo是一个计算机命令,它可以基于TCP协议,服务器就在TCP端口7检测有无消息,如果使用UDP协议,基本过程和TCP一样,检测的端口也是7。 是路由也是网络中最常用的数据包,可以通过发送echo包知道当前的连接节点有那些路径,并且通过往返时间能得出路径长度。
  • echo一去一回,除以2就是它们之间的距离

然后路由器会将自己和邻居之间的链路状态广播出去,然后每个路由器都会收到,所以每个路由器都能在自己本地构建一个完整的图,通过Dijkstra算法算出两点之间的最短路径。

每个路由器对外广播的都是自己对邻居echo的结果,首先不再是广播全量的路由表,开销比较小。另外能echo的邻居,一定还"活着"。

基于这两类算法,就有两种动态路由协议

动态路由协议

首先是OSPF(Open Shortest Path First),开放式最短路由优先

1.OSPF

  • 它基于链路状态路由算法,目的就是寻找去对方的最短路径
  • 由于主要运用于一些内部网络,这个协议也称为内部网关协议(Interior Gateway Protocal) ,IGP

另一个协议是BGP(Border Gateway Protocal),外网路由协议

2.BGP

  • 这个一听就是要跨网的
  • 它基于路径矢量路由算法
  • 把每一个网络称为自治系统AS(Autonomous System),AS与AS之间需要通信,这自然也需要路由器
  • AS之间通信用的路由器,叫边界路由器。
  • 边界路由器之间的路由信息的广播是用的BGP中的eBGP协议
  • 而不是每一个AS内部的机器都是直接连上的边界路由器的,这些内部路由器也需要导入边界路由器的路由信息,这是用的就是BGP中的iBGP协议

到这里,本篇的分享结束