深入浅出的网络拓扑介绍

写在前面

最近一段时间的工作偏运维开发,相对于纯粹的后端开发,关注的点由 CPU 和内存转到了更为宏观的系统、性能及稳定性。对我来说,做业务开发时技术上考虑更多的是计算效率与存储效率的问题,对IO(缓存、磁盘、网络等)的指标考虑的比较少,因此IO相关的知识储备就显得像是一块短板。俗话说“趁未老,补短板”,因此花了一点时间复习了一下网络相关的知识,现在总结一下,以备后用。

适用人群

入门——初级√——中级——高级;本文适应初级及以上。

网络基础

按照OSI模型的定义,可以把网络分成七层,分别是1)物理层、2)数据链路层、3)网络层、4)传输层、5)会话层、6)表示层、7)应用层。这个模型不太具有实践的意义(相对来说 TCP/IP 协议族实践性更强),但是为概念表达提供了很好的参考,比如:当我们说一个设备工作在二层网络的时候,说明其主要工作在数据链路层;当我们说做四层负载均衡时,说明是在传输层做手脚,很大程度是讲UDP或TCP连接的事情;当我们说七层负载均衡时,说明是在应用层做手脚,大概率是在讲一次或多次 HTTP 连接的事情。每一层有每一层的特点,具体的大家可以再去翻翻《计算机网络》这本书,我这里只就几个点做一些简单的阐述。

从网线直连到交换机连通(二层网络)

假如世界上只有两台电脑,为了能够让这两台电脑能够互相通信,可以使用一根网线把它们连接起来,如上图 A 所示,由 1 发出的所有信息通过网线直接到达 2,反之亦然,真是干脆利落。

按照 A 的拓扑特点,当有三台电脑时,为了达成两两之间能够互相通信,需要在两两之间架设网线,如上图 B 所示。当 1 想要给 2 发送信息时,通过网路 1 可以实现;如果 1 想要给 3 发送信息,通过网路 3 可以实现;以此类推。如果把网路想象成道路,可以意识到,为了让三个地方互相连通两两之间修路的方式实在太浪费了。尤其当扩展新节点的时候,要另外添加 (N-1)条线路,这根本无法支撑大数量的节点群啊。

这个时候,就出现了上图 C 的拓扑结构,图示有 5 个节点通过交换机互连(交换机不是唯一选择,比如集线器、网桥等也可以做到)。当 1 感觉到孤独时,会首先向交换机询问连通到交换机的其他节点列表,获取到了 2、3、4、5 后, 于是它对交换机说“帮我对 5 说一句‘你好’”,于是有了 (PC with eth0-1) -> (线路1) -> (交换机) -> (线路5) -> (PC with eth0-5)这个链路。当 5 收到了讯息后,觉得有必要寒暄一下,于是对交换机说“帮我回 1 说一句‘你也好’”,于是有了(PC with eth0-5) -> (线路5) -> (交换机) -> (线路5) -> (PC with eth0-1)这个链路。虽然通信的过程变复杂了,但是建设网路的消耗变少了,再扩展新的节点时,也只需要添加一条到交换机的网路就可以了。

通过上面的描述可以知道,如果同一台交换机上挂载的节点变得非常多的时候,交换机必然会成为通信的瓶颈。同时受到地理位置的限制,也不可能把所有的电脑都连接到一个交换机上面,因此可能会出现多个拓扑类似的节点群。那么这样的多个节点群之间该如何连通呢?

IP与网关(三层网络)

上图的上半部分描述了两个节点群 M 与 N 之间的拓扑图,如果 M 中的 PC with eth0-1 想给 N 中的 PC with eth0-9 发送讯息,该以一种什么样的方式实现呢?如果不对拓扑结构进行扩展,其实 eth0-1 甚至不知道有 eth0-9 的存在。在上一节已经描述过,为了与外界沟通,eth0-1节点要首先向交换器询问连通到交换机的其他节点列表,由于 eth0-9 在另一个交换机上面,因此 eth0-1 所获取得到的节点列表里是不包含eth0-9的。其实即使 eth0-1知道了eth0-9的存在,它对交换机说“帮我对 eth0-9 说一句‘你好’”,交换机也不知道该怎么办,只能傻掉。

为了实现 M 中的 PC with eth0-1 给 N 中的 PC with eth0-9 发送讯息,上图的下半部分给出了一种拓扑方案。1)首先对所有的机器进行统一编码(设定 IP),比如 M 节点群 IP 为 10.0.1.1-5/24,N 节点群 IP 为 10.0.2.1-5/24。2)同时为各个节点群配置了网关(eth0-4eth0-7)并设置二者之间的网路使之连通

基于上面的方案,当 M 中的 eth0-1 给 N 中的 eth0-9 发送讯息时,它首先会向交换机询问同一个网段其他节点的列表(每个节点的 IP 及 eth0 对应的 Mac 地址)。在eth0-1获取得到列表后,发现并没有eth0-9的身影,于是它把请求直接发给了网关eth0-4。一个请求被发送到了eth0-4eth0-4会首先检查请求中的目的 IP,当发现目的 IP 在网段 10.0.2.0/24 时,于是把请求发送到 eth0-7。这时候 eth0-7接收到了请求,检查从交换机获取到的节点列表里有请求里设定的目的 IP,对应的就是eth0-9这台机器,于是把请求发送到eth0-9

路由(Router,依然是三层网络)

当子网越来越多,相应的网关也会越来越多,这个时候如果在每个网关上配置路由信息(根据请求中的目的 IP 或者响应中的 IP 决策发送到哪个子网或网关),也会显得比较累赘。比如上图中网关-1、网关-6与网关-7之间的路由关系,因为拓扑简单因此路由信息直接维护在网关服务器上;而网关1-5则通过一个集中的 Router(类比家里用的路由器,不过企业里用的要高级很多)来转发网络请求。

最后简单聊一下正向与反向代理(四层与七层网络)

当前世界上存在的智能终端数目(PC、手机、车载系统等)已经远远超过了2^32(大概是40亿)个,这也是 IPV4 的极限数量。同时为了让每一个智能终端都能够“联网”,必须为每个智能终端编号,这怎么编号呢?一个方案是 IPV6,不过目前有更普世的 NAT 方案。比如一个企业内部有一个私有集群,集群中包含了成千上百台机器,但是没有必要给每台机器申请一个公网 IP,一方面节省开支(每个公网 IP 都是要收使用费的),另一方面可以有效避免被外界黑客攻击的风险。这种架构下集群里的机器如何上网呢?答案是基于 NAT 原理的正向代理(四层代理)。

上一小节里的图示中包含一个出入口,这就是正向代理工作的地方。当任意子网中的主机有访问互联网服务的需求时,比如 10.0.5.30/24 这台服务器想要访问www.baidu.com(14.215.177.38)的服务,请求经过网关-5和路由最终会汇聚到10.0.253.3/24,然后经过 NAT 把请求源 IP 映射成为公网 IP,形成10.0.5.30:34567 => 185.199.111.153:45234 => 14.215.177.38:80 这样的调用链路。于是,14.215.177.38:80所在的服务知道把对应的响应返回给185.199.111.153:45234,而185.199.111.153:45234知道自己对应了内网里的10.0.5.30:34567,最终完成响应。

考虑另一个问题,当我们访问www.baidu.com(假如只绑定了一个IP,14.215.177.38)的时候,虽然会解析到14.215.177.38:80所在的服务,但是从百度的体量考虑可以知道它的后端肯定有非常多的机器,甚至这些机器监听的并不是80端口(比如监听了8081端口)。那么外部的请求是如何传到后端的服务器的呢?答案是反向代理(七层代理)。

最终的调用链路为 10.0.5.30:34567 <=> 185.199.111.153:45234 <=> 14.215.177.38:80 <=> x.x.x.x:8081,实现了请求从客户端到服务端再到客户端的完整响应。

小结

本文复习了大学课堂上学习的基础网络拓扑原理,主要涉及到了二层网络中的交换机(Switch)、三层网络中的路由(Router)及四层与七层网络中的正向和反向代理。这些知识应该是 IT 从业人员的常识,不过不排除一些细节上的理解与真实情况存在出路。计算机网络是一门高复杂度的工程,每一层上延伸出的技术实践远不止本文讲述的这些;不过本文虽简单,但是也只有熟练掌握了上面所讲的内容,才能进一步深入了解更多高阶的架构设计。

接下来如果有时间就可以分析一下 Docker 及 K8s 网络相关的架构设计了😆。

参考