简介
数据中心网络架构浅谈(三) 中提到:之所以写,是想提供一个非网工的,云计算从业人员的视角。本文也尝试从一个 程序猿的视角,来汇总网络方面的一些知识。
网络分块和分层
为什么要分层
2019.7.5补充:虽然全世界组成一张大的互联网,美国的网站你也能够访问的,但是这个网络不是一整个的。你们小区有一个网络,你们公司也有一个网络,联通、移动、电信运营商也各有各的网络,所以一个大网络是被分成个小的网络。network layer以下就是解决 “小网络”内的事儿。PS:就好像看地图是一片,但实际因为山川河流阻隔,都是一块一块的。去一个地方看似都能走,实际就几条路。
The Layers of the OSI Model Illustrated
为什么网络要分层?因为是个复杂点的程序都要分层。
It conceptually divides computer network architecture into 7 layers in a logical progression. The lower layers deal with electrical signals, chunks of binary data, and routing of these data across networks. Higher levels cover network requests and responses, representation of data, and network protocols as seen from a user’s point of view.
网络各层
层次 | 数据组织 | 概念 | 每一层除数据包不同之外,知道哪一层在哪些行为里也很重要 |
---|---|---|---|
Physical Layer | bit | ||
Data Link Layer | frame | mac | 1. checks for physical transmission errors 2. packages bits into data “frames” 3. manages physical addressing schemes such as MAC addresses |
Network Layer | package | ip | 承担了分组(Packet)转发和路由选择两大功能 1. 根据目的ip地址determine if the data has reached its final destination. 2. If the data has reached the final destination, this Layer 3 formats the data into packets delivered up to the Transport layer. Otherwise, the Network layer updates the destination address and pushes the frame back down to the lower layers. 3. adds the concept of routing above the Data Link layer 4. To support routing, the Network layer maintains logical addresses such as IP addresses for devices on the network. 5. manages the mapping between these logical addresses and physical addresses(ARP) |
Transport Layer | error recovery, flow control, re-transmission. etc |
二层到四层都是在 Linux 内核里面处理的,是一个软件实现的功能逻辑层
《网络是怎样连接的》:IP 和Ethernet的分工,其中Ethernet的部分也可以替换成其他的东西,例如无线局域网、ADSL、FTTH 等,它们都可以替代以太网的角色帮助 IP 协议来传输网络包 要使用各种通信技术。像互联网这样庞大复杂的网络,在架构上需要保证 灵活性,这就是设计这种分工方式的原因。
网路通信
本小节来自《Paas实现与运维管理》的笔记。
我们将网络世界的物理设备抽象为三种:计算节点,交换节点和路由节点
-
因为计算节点不能两两相连,所以我们需要一个交换节点,负责转发数据。在数据链路层范围内
- 计算节点在发送数据的时候,应用程序中不可能直接写目的主机的mac地址,所以我们需要一个虚拟地址,即ip地址。arp请求(广播)及arp缓存。
- 交换节点收到一个包,在转发这个包的时候,没有mac地址与端口的映射,会先广播,然后建立mac地址与串口的映射关系。
-
因为一个交换节点负责不了世界上的所有计算节点,(不然广播域也太大了),所以我们需要一个路由节点。
- 计算节点在发送数据时,通过ip+掩码来判断目的计算节点是否在一个子网内。当发现不在一个子网时,它会将数据包发送给子网内的路由节点(也就是网关)。
- 路由器根据路由表中的策略来接收和发送包。这就不能叫转发了,因为路由器会修改数据包。路由表中的rule可以静态设置,也可以动态学习。
修正自己以前的几个误区:
- 除了功能不同,交换节点和路由节点的另一个区别:交换节点并不修改package
- 实际上,计算节点通过交换节点向路由节点发送数据,交换节点转发包可以理解为透明。所以是:
计算节点 ==> 路由节点 ==> 计算节点
实现跨网络传输 - 不仅计算节点有数据通信,路由节点也有数据通信
- 在一个网络数据包传输的过程中(跨网络+路由器),都是源/目标mac在变,源/目标ip都没变。
《趣谈网络协议》MAC 地址是一个局域网内才有效的地址。因而,MAC 地址只要过网关,就必定会改变,因为已经换了局域网。两者主要的区别在于 IP 地址是否改变。不改变 IP 地址的网关,我们称为转发网关;改变 IP 地址的网关,我们称为NAT 网关(IP段冲突场景)。在 IP 头里面,不会保存任何网关的 IP 地址。所谓的下一跳是,某个 IP 要将这个 IP 地址转换为 MAC 放入 MAC 头。NAT 网关经常见,大家每家都有家用路由器,家里的网段都是 192.168.1.x,所以你肯定访问不了你邻居家的这个私网的 IP 地址的。所以,当我们家里的包发出去的时候,都被家用路由器 NAT 成为了运营商的地址了。
网络发现
Computer networkNetwork是一组可以相互通信的Endpoints,网络提供connectivity and discoverability
尤其是对于discoverability,在网络的各个层次都有体现
- dns,有专门的dns服务器,在host组装数据包之前 根据dns 将域名转换为ip
- arp,在host 发出frame之前,根据arp 获取目的主机的mac地址
- 路由器之间的路由同步协议
- 边界路由器之间的路由同步协议,比如bgp
- 在oveylay 网络中,经常将 虚拟机/容器/网段在哪个主机上 等信息保存在zk/etc中。
解决了discoverability,数据包发向哪里都明确了,交换设备通过简单的复制,将数据包转发给目的设备,提供connectivity
网络路由
天天讲路由,那 Linux 路由到底咋实现的网络包在发送的时候,需要从本机的多个网卡(eth0和lo)设备中选择一个合适的发送出去。网络包在接收的时候,也需要进行路由选择,如果是属于本设备的包就往上层送到网络层、传输层直到 socket 的接收缓存区中。如果不是本设备上的包,就选择合适的设备将其转发出去。
网络层发送的入口函数是 ip_queue_xmit, Linux 在 IP 层的接收入口 ip_rcv 执行后调用到 ip_rcv_finish。在这里展开路由选择。如果发现确实就是本设备的网络包,那么就通过 ip_local_deliver 送到更上层的 TCP 层 tcp_v4_rcv进行处理。如果路由后发现非本设备的网络包,那就进入到 ip_forward 进行转发,最后通过 ip_output 发送出去。
//file: net/ipv4/ip_output.c
int ip_queue_xmit(struct sk_buff *skb, struct flowi *fl){
// 路由选择过程
// 选择完后记录路由信息到 skb 上
rt = (struct rtable *)__sk_dst_check(sk, 0);
if (rt == NULL) {
// 没有缓存则查找路由项
rt = ip_route_output_ports(...);
sk_setup_caps(sk, &rt->dst);
}
skb_dst_set_noref(skb, &rt->dst);
...
//发送
ip_local_out(skb);
}
路由表(routing table)在内核源码中的另外一个叫法是转发信息库(Forwarding Information Base,FIB)。在源码中看到的 fib 开头的定义基本上就是和路由表相关的功能。所有的路由表都通过一个 hash - fib_table_hash 来组织和管理。它是放在网络命名空间 net 下的。这也就说明每个命名空间都有自己独立的路由表。
//file: include/net/ip_fib.h
struct fib_table {
struct hlist_node tb_hlist;
u32 tb_id;
int tb_default;
int tb_num_default;
unsigned long tb_data[0];
};
//file:include/net/net_namespace.h
struct net {
struct netns_ipv4 ipv4;
...
}
//file: include/net/netns/ipv4.h
struct netns_ipv4 {
// 所有路由表
struct hlist_head *fib_table_hash;
// netfilter
...
}
发送过程调用 ip_route_output_ports 来查找路由,接收过程调用 ip_route_input_slow 来查找。但其实这两个函数都又最终会调用到 fib_lookup 这个核心函数
//file: include/net/ip_fib.h
static inline int fib_lookup(struct net *net, const struct flowi4 *flp,
struct fib_result *res){
struct fib_table *table;
table = fib_get_table(net, RT_TABLE_LOCAL);
if (!fib_table_lookup(table, flp, res, FIB_LOOKUP_NOREF))
return 0;
table = fib_get_table(net, RT_TABLE_MAIN);
if (!fib_table_lookup(table, flp, res, FIB_LOOKUP_NOREF))
return 0;
return -ENETUNREACH;
}
这个函数就是依次到 local 和 main 表中进行匹配,匹配到后就返回,不会继续往下匹配。从上面可以看到 local 表的优先级要高于 main 表,如果 local 表中找到了规则,则路由过程就结束了。这也就是很多同学说为什么 ping 本机的时候在 eth0 上抓不到包的根本原因。所有命中 local 表的包都会被送往 loopback 设置,不会过 eth0。
网络通信中的IP 与MAC
路由表同时记录了目的计算机地址、下一跳地址和网络接口的关联信息。所谓下一跳地址就是:如果 IP 包从主机 A 发到主机 B,需要经过路由设备 X 的中转。那么 X 的 IP 地址就应该配置为主机 A 的下一跳地址。一旦A配置了下一跳地址,那么接下来,当 IP 包从网络层进入链路层封装成帧的时候,eth0 设备就会使用下一跳地址X_IP对应的 MAC 地址,作为该数据帧的目的 MAC 地址。网关/下一跳的 IP 地址不会出现在任何网络包头中
frame header | frame body | |||
A mac | X mac | A ip | B ip | body |
-
如果要访问的目标IP跟自己是一个网段的(根据CIDR就可以判断出目标端IP和自己是否在一个网段内了),就不用经过网关了,先通过ARP协议获取目标端的MAC地址,源IP直接发送数据给目标端IP即可。
frame header frame body A mac B mac A ip B ip body 如何是一个局域网的, you can just send a packet with any random IP address on it, and as long as the MAC address is right it’ll get there.
-
如果访问的不是跟自己一个网段的,就会先发给网关(哪个网关由 The route table 确定),然后再由网关发送出去,网关就是路由器的一个网口,网关一般跟自己是在一个网段内的,通过ARP获得网关的mac地址,就可以发送出去了
frame header frame body A mac gateway mac A ip B ip body -
主机/直接路由 强行指定下一跳地址
$ ip route ... 10.244.1.0/24 via 10.168.0.3 dev eth0
目的 IP 地址属于 10.244.1.0/24 网段的 IP 包,应该经过本机的 eth0 设备发出去(即:dev eth0);并且,它下一跳地址(next-hop)是 10.168.0.3(即:via 10.168.0.3)。
在基于二层交换机的场景下,src mac 是可以不设置的,但是 dst mac 是一定要设置的,对于三层的网络通信是一定要 src mac 和 dst mac 都要设置正确,才可以完成数据包的正确处理。
传统网络架构
在传统的网络认知里,网络就是由带有一个或多个 NIC(Network Interface Controller,网络接口控制器,俗称网卡) 的一组 NC(Network Computer) 使用硬件介质和 switch(交换机)、Router(路由器)所组成的一个通信集合。
网络间通信——网关和路由器
- 在没有路由器的情况下,两个网络之间是不能进行TCP/IP通信的,即使是两个网络连接在同一台交换机(或集线器)上,TCP/IP协议也会根据子网掩码(255.255.255.0)判定两个网络中的主机处在不同的网络里。而要实现两个网络之间的通信,则必须通过网关。如果网络A中的主机发现数据包的目的主机不在本地网络中(同一个网段),就把数据包转发给它自己的网关,再由网关转发给网络B的网关,网络B的网关再转发给网络B的某个主机。
- 路由器使用静态路由或动态路由来决定网络间的最短路径。
从网关和路由器的定义来看,如果只是简单地连接两个网络,那么只需要网关就足够了。因为只有两个网络,不需要决定网络间最短路径。如果需要连接多个网络,为了保证网络的可靠性,网络结构需要设计为全网状或部分网状,这样,为了网络间的通信,需要网关和路由器两种设备(比如网络A到网路D有两种路径,A-B-D/A-C-D,需要网关连通B和C,需要路由器决策选取哪种路径),因为当前路由器集成了网关的功能,所以只使用路由器一种设备就可以了。
抛开这些陈年往事,从现在情境看,网关实质上是一个网络通向其他网络的IP地址。路由器是一个设备,可以做网关使用。它是一种连接多个网络或网段的网络设备,从而构成一个更大的网络。
linux 的路由表
笔者的直观感受 一直是,路由是路由器做的事儿,既然如此,为了linux 中还有一个路由表?
普通的主机与路由器之间的根本区别在于:主机不会将一个报文从一个接口转发到另一个接口,而路由器可以转发报文。但是,一个普通路由算法可以被用在路由器上,同样也可以用在一台普通主机上。当一台主机可以用作路由器时,我们通常说这台主机嵌入了路由器的功能。这种具备嵌入路由器功能的主机平常不会转发报文,除非我们对它进行了配置,使它开启这种功能。
Linux路由分析提到: Linux默认情况下会丢掉不属于本机IP的数据包(类似的,网卡默认会丢弃mac地址不是本网卡的数据包,除非开启混杂模式)。将net.ipv4.ip_forward
设置为1后,会开启路由功能,Linux会像路由器一样对不属于本机的IP数据包进行路由转发。linux 有路由表,是因为开启了路由功能。
root@ubuntu-1:/home/ops# ip route
default via 10.0.2.2 dev enp0s3
10.0.2.0/24 dev enp0s3 proto kernel scope link src 10.0.2.15
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 linkdown
172.32.135.128/26 via 192.168.56.103 dev tunl0 proto bird onlink
blackhole 172.32.185.64/26 proto bird
172.32.185.70 dev calie34960bc671 scope link
172.32.185.71 dev cali6d5e7989019 scope link
172.32.243.0/26 via 192.168.56.102 dev tunl0 proto bird onlink
192.168.56.0/24 dev enp0s8 proto kernel scope link src 192.168.56.101
如何看待这个输出 route table explanation
proto,发现该路由的路由协议(即路由来源),一般是协议名,proto kernel 表示 The route was installed by the kernel during autoconfiguration.
scope,The scope of a route in Linux is an indicator of the distance to the destination network.
- Link-local address are supposed to be used for addressing nodes on a single link. Packets originating from or destined to a link-local address will not be forwarded by a router. 还有一种说法 valid only on this device
- Site,valid only within this site (IPv6)
- Host,A host address is something that will only exist within the host machine itself. For instance 127.0.0.1 is a host address commonly assigned to the loopback interface. The loopback interface has no external connectivity and so it’s scope is confined to within that of the host machine.
- A global address is what you might currently consider a “normal” address. Global which is visible on and routable across an external network.
数据中心网络架构
著名的通信设备厂商思科把这种架构叫做分级的互联网络模型(Hierarchical Inter-networking Model)。这种架构的优点是,可以把复杂的网络设计问题抽象为几个层面来解决,每个层面又聚焦于某些特定的功能。首先是核心层。交换层的核心交换机为进出数据中心的数据包提供高速转发的功能,为多个汇聚层提供连通性,同时也为整个网络提供灵活的 L3 路由网络。然后是汇聚层。汇聚交换机与接入交换机相连,提供防火墙、SSL 卸载、入侵检测、网络分析等其他服务。最后我们来看接入层。接入交换机通常位于机架的顶部,因此它们也被称为 ToR 交换机,并且它们与服务器物理连接。
基于这样的网络拓扑结构,The Google File System (二):如何应对网络瓶颈? 客户端写入文件时,先把所有数据传输给到网络里离自己最近的次副本 A,然后次副本 A 一边接收数据,一边把对应的数据传输给到离自己最近的另一个副本,也就是主副本。同样的,主副本可以如法炮制,把数据也同时传输给次副本 B。从而把所有的数据从客户端,传输到三个副本所在的 chunkserver 上。为什么客户端传输数据,是先给离自己最近的次副本 A,而不是先给主副本呢?两台服务器如果在同一个机架上,它们之间的网络传输只需要通过接入层的交换机即可。在这种情况下,除了两台服务器本身的网络带宽之外,它们只会占用所在的接入层交换机的带宽。但是,如果两台服务器不在一个机架,乃至不在一个 VLAN 的情况下,数据传输就要通过汇聚层交换机,甚至是核心交换机了。而如果大量的数据传输,都是在多个不同的 VLAN 之间进行的,那么汇聚层交换机乃至核心交换机的带宽,就会成为瓶颈。
整体结构
数据中心网络架构 也可以说是一种 网络硬件设备架构
- 数据中心网络架构、三层网络架构、大二层网络架构 是什么?
- 数据中心网络,本质上是一个局域网, 但机器很多,为了减少网络广播等考虑,通常会划分几个子网。
- 一个交换机最多也就几百个端口,再多的话,交换这么多数据太忙了,接那么多物理机 接口也挺麻烦的。所以,一个交换机是无法支撑一个数据中心网络架构的
- 交换机可以只是单纯的连接物理机,提供连通性,比如access switch(通常一个机架一个)。也可以是一个子网入口,或者一个词POD(Point Of Delivery)
- 互联网的发展,使得数据中心以南北流量(数据中心的主机与外网相互访问)为主转变为东西流量(数据中心内主机彼此访问)为主。比如hadoop 集群就只是内网彼此访问
- 虚拟化的流行 大大提高了单台服务器的利用率,单台服务器网络流量也随之提高
- 东西流量要求原来的 三层网络架构 的核心交换机(core switch)具备很高的性能,代价较高
- Fabric网络架构,fabric 一词的由来
- 虚拟网络 和 物理网络是紧密联系的。
- overlay网络,只要求物理网络提供连通性。只要hostA(192.168.0.0/16)和 hostB(172.16.0.0/16)连通,就可以提供一个10.10.0.0/16 网络来。物理网络上跑的 数据包 还都是 hostA和 hostB的。
二层网络与三层网络
二层网络结构和三层网络结构的对比在这里的二层、三层是按照逻辑拓扑结构进行的分类,并不是说ISO七层模型中的数据链路层和网络层,而是指数据中心网络架构,具体的说是核心层,汇聚层和接入层,这三层都部署的就是三层网络结构,二层网络结构没有汇聚层。数据中心网络架构浅谈(一)
- 二层交换机根据MAC地址表进行数据包的转发,有则转发,无则泛洪。即将数据包广播发送到所有端口,如果目的终端收到给出回应,那么交换机就可以将该MAC地址添加到地址表中。但频繁这样做,在大规模网络架构中会形成网络风暴,限制了二层网络的规模。
- 三层交换机工作原理文中提到了vlan场景下的三层交换过程。如果来一个非同一网段ip1,交换机可以通过查询过程建立ip1与port1 的映射关系,此后,去向ip1的包直接由port1转发。
其它:
为什么三层交换机无法替代路由器? - 萧骁的回答 - 知乎提高三层交换机与路由器的区别时提到:
- 三层交换机: 三层交换技术就是将路由技术与交换技术合二为一的技术。在对第一个数据流进行路由后,它将会产生一个MAC地址与IP地址的映射表,当同样的数据流再次通过时,将根据此表直接从二层通过而不是再次路由,从而消除了路由器进行路由选择而造成网络的延迟,提高了数据包转发的效率。三层交换技术就是二层交换技术+三层转发技术。它解决了局域网中网段划分之后,网段中子网必须依赖路由器进行管理的局面,解决了传统路由器低速、复杂所造成的网络瓶颈问题。三层交换机的路由功能通常比较简单,因为它所面对的主要是简单的局域网连接。
- 路由器,本质是维护ip与port的关系,其处理过程从不涉及mac。路由器的重点是向网络中广播和更新自己的路由信息。路由器一般由基于微处理器的软件路由引擎执行数据包交换,虽然也适用于局域网之间的连接,但更主要的是路由功能,更多的体现在不同类型网络之间的互联上。
- 三层交换机的最重要的目的是加快大型局域网内部的数据交换,所具有的路由功能也是为这目的服务的,能够做到一次路由,多次转发。对于数据包转发等规律性的过程由硬件高速实现,更适用于数据交换频繁的局域网中。
交换机,维基百科解释:是一个扩大网络的器材,能为子网络中提供更多的port,以便连接更多的电脑。
二层交换机、三层交换机和路由器的基本工作原理和三者之间的主要区别出于安全和管理方便的考虑,主要是为了减小广播风暴的危害,必须把大型局域网按功能或地域等因素化成一个个小的局域网,这就使得VLAN技术在网络中得到大量应用,而不同VLAN之间的通信都要经过路由器来完成转发,随着网间互访的不断增加。单纯使用路由器来实现网间访问,不但由于端口数量有限,而且路由速度较慢。从而限制了网络的规模和访问速度。基于这种情况三层交换机便应用而生。
所谓的二层设备、三层设备,都是这些设备上跑的程序不同而已。什么叫二层设备呀,就 是只把 MAC 头摘下来,看看到底是丢弃、转发,还是自己留着。那什么叫三层设备呢?就是把 MAC 头摘下来之后,再把 IP 头摘下来,看看到底是丢弃、转发,还是自己留着。
其它
NAT
为什么 IPv6 难以取代 IPv4网络地址转换(Network Address Translation、NAT)是一种在 IP 数据包通过路由器时修改网络地址的技术,它能够将当前地址空间中的 IP 地址映射到另一个地址空间。
当数据包从内部访问外部网络时,NAT 会为当前请求分配一个端口、覆写数据包中的源地址和端口并将地址和端口信息存储到本地的转换表中;当数据包从外部进入网络内部时,NAT 会根据数据包的 IP 地址和端口号查找到私有网络中对应的主机和端口号并覆写数据包中的目的地址和端口。
通过 NAT 这一中间层,我们不仅可保护私有的网络,还能缓解 IP 地址的短缺问题。不过 NAT 技术也并不是只有好处,它也带来了很多的问题,在 NAT 网络下的主机并不能与对端建立起真正的端到端连接,也不能参与部分因特网协议。
另一种表述:NAT在网络连接的过程中是常见的操作。举例,在路由器上就会对地址进行转换,具体是 snat (源地址转换) /dnat (目的地址转换) 就看处理连接的阶段,如果是数据包从外部进来,就会进行 dnat 操作,作用是将数据包的目的地址,转换成真正要访问的服务的地址,如通过 NodePort 访问应用,那肯定会将目的地址转换成要访问的 Pod 的 ip 地址;如果是数据包要从主机出去的时候,一般会进行 snat 的操作,因为要让数据包的源地址是路由可达的,而一般路由可达的地址应该是主机的物理网卡的地址,所以一般会 snat 成主机的物理网络地址。有 NAT,就会有反向 NAT,主要是完成 reply 包的处理。
隧道技术
为什么需要IP隧道?为了在TCP/IP网络中传输其他协议的数据包
Linux Networking/IPIP Encapsulation
隧道都是静态建立的,隧道一端有一个IP地址,另一端也有唯一的IP地址
PPP、PPTP和L2TP等协议或软件不是基于内核模块的,Linux系统内核实现的IP隧道技术主要有三种,都是不加密的。对于ip 连通的hostA 和 hostB来说(可以直接连通,或者hostA ==> routeA ==> routeB ==> hostB):
- ipip,点对点tunnel,hostA和hostB 均包含tunnel设备(负责解封包)
- gre,解封包在 routeA 和 route B 上完成,hostA 和host B 只需要配置路由即可。因而支持广播。
- sit
- 对于厂商来说,docker网络可能跨多个环境,统一acl等比较复杂
- 容器相较于虚拟机在一台主机上的密度大大增加