数据中心网络高可用技术之从服务器到交换机:802.3 ad

我们距离双线双活的完美方案越来越近了。在上文的链路聚合方案中,服务器和交换机之间的多条线路可以虚拟成一条,唯一的不足是故障检测比较复杂,MII Monitoring 和 ARP Monitoring 都不够完美。有什么办法,可以在出现问题的时候,让无论是交换机还是服务器都能快速发现问题并进行切换呢?

目前的健康检查手段,MII Monitoring 太短,不足以检查到线路的问题;ARP Monitoring 太长,连对端服务器的问题也会触发。最好的检测距离就是服务器到交换机之间,这样不多也不少。

按照这个思路,可以让交换机和服务器之间实现类似 keepalive 的机制,当任意一方的任意一条线路发现对面不再存活,就不使用这条线继续发送数据,就可以做到更加准确的健康检查机制。

LACP (Link Aggregation Control Protocol) 就是这样一种协议。

IEEE 802.3ad 定义了链路聚合,但是链路聚合可以认为是一种实现而不是协议,它的兼容性很高,不同的厂商可以自己实现链路聚合功能。在上一篇文章中,我们没有使用 LACP 协议,也看到了链路聚合正常工作。802.3ad 一个是定义了链路聚合,另一个就是定义了 LACP 协议。LACP 协议做了两件事情:

  1. 健康检查,可以自动发现问题执行切换;
  2. 可以自己协商链路聚合,减少手动配置的内容;

健康检查是通过 LACP 协议参与的两端(交换机和服务器),互相发送 LACPDU,这是一个二层的数据帧,只会存在于网线的两端,不会被转发。如果能收到对方发送的 LACPDU,说明线路健康,如果连续3个 LACPDU 都没收到,就不从这条线路发送数据了。LACP 发送 LACPDU 的 rate 有两种,一种是 fast, 每 1s 发送一个,这样在线路挂的时候,需要 3 个包的时间,就是 3s 恢复。另一种是 slow,每 30s 发送一个,出现问题的时候需要 90s 时间恢复。

第二个功能更加实用。读者可能觉得,配置多一点没有什么问题呀,只要我们使用自动化来代替手动配置就可以。但是事实上,这个功能远不止节省了配置。

LACP 协议有两种模式,mode active 和 mode passive:

  • active 模式下,设备会通过线路发送 LACPDU(LACP 协议的包),不管对方有没有开启 LACP 协议;
  • passive 模式下,设备不会发送 LACPDU,除非收到了对方发过来的 LACPDU;

Active 不代表建立了链路聚合,要完成链路聚合,双方至少有一方得是 active 模式才行,如果两端都收到了对方的 LACPDU 就可以协商建立起来链路聚合。

建立链路聚合的过程,来源

这种自动协商的链路聚合第一个优点就是配置很少,要多加一根线的时候,插上线,LACP 协议就可以开始自动协商。

第二个优点就是可以阻止错误,这点非常重要。机房部署的时候,经常遇到线路接错的情况(不要惊讶,这太常见了)。

考虑下面这种情况,交换机 1 和 2 做了链路聚合,服务器网口 A 和 B 做了链路聚合,配置正确,但是机房人员在接线的时候接错了,服务器 B 口应该连接交换机端口 2,却连接了端口 5.

接错线的例子

如果是静态配置的链路聚合,交换机和服务器都不会知道线路接错的情况,服务器会通过 A 和 B 发送数据,交换机这边就会出现 MAC flapping 问题。交换机也可能通过 2 端口把应该发给这台服务器的数据发送到错误的地方去。

这是一个灾难性的问题,因为程序会表现异常而不是直接报网络错误,很难排查。可以类似我们在写程序的时候,我们喜欢程序直接出错挂掉,而不是没有错误但是逻辑有 BUG。又如,我们宁可数据库出问题,也不想数据库没问题但是数据全错了。

而如果使用 LACP 协议的话,交换机从 1 号端口和 5 号端口发送过来的 LACPDU 会有不一样的 system id,在服务器侧,就会发现对方的两个端口不属于同一个 Link Aggration Group (LAG), 于是协商失败,就无法完成链路聚合,在服务器侧就会只选择使用一条线进行发送。同理,交换机也不会认为自己的 1 号和 5 号能完成链路聚合,这时候会选择断开一条线。LACP 协商会让两端断开同一条线,所以最终这种情况是依然可以通信,但是只有一条线能工作。问题非常明确,我们直接去排查为什么带宽不正确,进而排查 LACP 链路聚合状态即可。

802.3ad 模式实验 (mode 4)

我们使用的拓扑结构如下,还是和之前的一样:

使用默认的配置很简单,还是和之前的配置一样,只不过 mode 使用 802.3ad 这个名字。

因为 LACP 协议是在 802.3ad 中定义的,所以 Linux 中的配置直接用了 802.3ad 作为 mode,意思就是完全使用 802.3ad 中定义的链路聚合,也意味着开启了 LACP 协议。

查看 ip link,和之前的静态链路聚合是一样的。

查看 bonding 信息:

可以看到默认的模式是 active. 即 Linux 总是尝试与对面进行 LACP 协商。这样的话,我们在交换机侧配置成 active 或者 passive 都是可以的。

交换机配置很简单,我们直接对这两个端口配置成一个 channel-group,模式是 active 或者 passive。

现在线路已经完成链路聚合了,我们抓包可以看到,两端都在定期发送 LACPDU,结构长这样子:

LACP 抓包

除了 LACP,还有一个协议支持自动协商链路聚合:PAgP(Port Aggregation Protocol)。这个是思科的专有协议。思科设计很多优秀的协议,很多开放网络协议就是参考了思科的协议而设计的。PAgP 在 1990s 就出现了,LACP 在 2000 才标准化。但是,像链路聚合这种事情,很多场景是运行在多个厂商的设备之间,私有协议很难普及。如今大部分几乎见不到 PAgP 了,思科设备之间运行的一般也是 LACP。

802.3ad 模式近乎完美,数据中心使用的 bonding 模式基本上都是 802.3ad 模式了。我们花了这么篇幅介绍了没有在使用的方案,好像是研究了一些没有用的东西,其实不是。后面我们在介绍 VRRP,HSRP 等更高级的内容的时候,读者会发现,原理还是 ARP,MAC 地址表这些东西,所以这个系列的内容是由简入难,对后面的内容理解是有帮助的。另外,像 MikroTik 这种基于 Linux 的路由器,其内置的链路聚合就是 Linux 的 bonding,所以配置这个路由器就是配置我们熟悉的 bonding,有时候可以灵活运用这些 bonding 模式。

到本文我们有能够自动协商的链路聚合,但是距离「完美」还差一步。我们发现,现在在服务器这儿是高可用了,但无论是链路聚合,还是 LACP 自动协商的链路聚合,都有一个限制——就是两条线必须连接到相同的交换机,这样一来交换机就成了一个单点。在没有链路聚合之前,我们的 bonding 方案 (active-backup, balance-tlb, balance-tlb) 还支持插到多个交换机上呢!需要交换机使用链路聚合的 bonding 模式 (balance-xor, balance-rr, 802.3ad) 只能接到一台交换机上。下篇文章我们来讨论如何解决交换机的单点问题。

Until next time!

参考资料:

数据中心网络高可用技术系列

  1. 数据中心网络高可用技术:序
  2. 数据中心网络高可用技术之从服务器到交换机:active-backup
  3. 数据中心网络高可用技术之从服务器到交换机:balance-tlb 和 balance-alb
  4. 数据中心网络高可用技术之从服务器到交换机:链路聚合 (balance-xor, balance-rr, broadcast)
  5. 数据中心网络高可用技术之从服务器到交换机:802.3 ad
  6. 数据中心网络高可用技术之从交换机到交换机:MLAG, 堆叠技术
  7. 数据中心网络高可用技术之从服务器到网关:VRRP
 

数据中心网络高可用技术之从服务器到交换机:链路聚合 (balance-xor, balance-rr, broadcast)

到现在我们讨论了 3 种 Linux bonding 模式:active-backup, balance-tlb, balance-alb. 这些方案都不够完美,各有利弊。那么有没有完美的方案呢?前面讨论的方案都没有需要交换机支持特殊功能,假设我们可以在交换机上做一些事情,交换机可以如何配合服务器来做到完美的双线双活?

我们重新思考一下我们的需求:

  • 我们有两条线,我们想充分利用两条线的带宽;
  • 当有一条线挂的时候,就只用另一条线,自动切换。

将这个需求转换到对交换机的要求,那具体就是:

  • 交换机将两条线路视为一条线路,即对于物理端口 1 和 2,在 MAC 地址表中,不再记录 MAC 地址 AA 对应的端口是 1 还是 2,而是记录为 虚拟1号端口,虚拟1号就是物理 1 和 2 的结合体,这样就没有 MAC flapping 的问题了。对于:
    • 发送数据,交换机对于发往 MAC 地址 AA 的 Frame,可以自由选择从 1 还是 2 来发送,但是要保证一个数据流总是发送到一条线路,来尽量保证顺序。对于广播数据,也只需要广播给两个端口中的一个即可;
    • 接收数据,无论从物理端口 1 还是 2 收到的数据,都视为从虚拟端口 1 收到的数据,如果修改 MAC 地址表,就将学习到的 Src MAC 地址记录为虚拟端口 1。如果从 1 或 2 收到广播数据,不需要再发给物理端口 1 或 2。
  • 当其中一条线路 down 的时候,只从另一条好的线路发送数据

实际上,交换机完全能做到这种事情,这个功能叫做链路聚合。简单,就是将两条线虚拟成一条线。

这里说个题外话,链路聚合技术,英文名字叫 Link Aggregation. 但是它还有很多其他的很多名字:

  • Ethernet bonding
  • Ethernet teaming
  • Link bonding
  • Link bundling
  • Link teaming
  • Network interface controller (NIC) bonding
  • NIC teaming
  • Port aggregation
  • Port channeling
  • Port trunking
  • Eth-Trunk
  • EtherChannel

不要被这些吓人的名字唬住了,其实说的都是上文链路聚合这点简单的东西……

其中,Trunking 一般是说交换机之间连接模式,用来让不同的交换机上的相同 Vlan 能够互通。不同厂商的设备都有自己的一套命名逻辑,这些名字要结合语境来理解,知道它们说的是什么。

为什么要起这么多有迷惑性的名字呢?简单来说就是为了卖设备。像笔者写的这么直白,怎么忽悠客户购买上万元的设备呢?EtherChannel,听着多牛逼。但是你 Cisco 起名叫 EtherChannel,我华为也叫这个名字未免就显得我抄了你的,我就叫个 Eth-Trunk,还用上个缩写,显得更牛逼。实际都是差不多的东西,咱可不能被忽悠瘸了。

公开的网络协议方面,命名是很统一的,但是涉及技术实现,就有很多高大上的名词和缩写了。

回到我们高可用的话题上,链路聚合具体做的事情就是将多个物理线路组合成一个逻辑线路,对于交换机系统,就如同只有一条带宽更高的线一样——虚拟线路的带宽是所有物理线路的总带宽。当某条线路挂掉,发送的流量可以自动切换到其他线路上。

链路聚合应用很广。我们的公司附近最近新盖了一个办公大楼,要部署网线,像这种工程,挖路布线,成本都在人工上,埋一根线和十根线成本差别不大。假设 5 年之后网络大发展,带宽不够用了,再挖开路面重新施工,成本就得再来一次。那就不如一开始埋上十根线,之后可以通过链路聚合来获得更多的带宽。

布线施工现场

有了这个技术,交换机能替我们办点事,服务器这边的事就好办多了。利用这个功能,我们再来看服务器这边如何做到高可用。

Balance-xor (mode 2)

链路聚合可以把多条线路「捆绑」在一起,对于同一个 flow,需要保持使用同一条线路来发送,如何选择线路呢?

链路聚合并没有规定线路选择算法(或者叫路由算法,负载均衡算法),原因是:

  • 没有必要,即使运行链路聚合的服务器和交换机使用不同的算法,在数据的两个方向上都不会有问题;
  • 如果要标准化,会花费很多精力去对这些算法标准化,来统一不同的厂商;
  • 具体使用什么算法最好,通常取决于拓扑结构和流量特征;
  • 不标准化算法可以留给厂商优化的空间(比如一些高端交换机支持动态负载均衡,根据线路使用率来调整);

所以:

  • 链路聚合中的负载均衡算法并不作标准化,只对算法提需求;
  • 需求就是对于同一个 flow 要始终选择同一个路线;
  • 对于流量的接收,需要兼容所有算法。即作为链路聚合的接收端无论发送端使用什么样的算法来发送,都能正确处理收到的包,无论从哪一条物理线路收到流量,都如同在虚拟线路上收到一样
不同的链路聚合算法可以一起工作

所以,发送端可以自己选择负载均衡算法。聚在均衡算法本质上就是根据包的 header 计算 hash,然后根据 hash 来决定走哪一条线。常用的 header 有:

  • Source MAC Address (SA)
  • Destination MAC Address (DA)
  • Layer 3 (IP)
  • Layer4 (Port)

balance-xor 模式就是在链路聚合的模式下,使用一种负载均衡算法来选路。默认的算法是:(src mac address XOR dest mac address XOR packet type ID) modulo slave account.

也支持使用 xmit_hash_policy 来选择其他算法。xmit_hash_policy 支持的算法有:

  • layer2
  • layer2+3
  • layer3+4
  • encap2+3
  • encap3+4

配置实验

我们还是使用前面一直在用的拓扑图做实验。

实验拓扑图

在 ubuntu-5 上,用如下的命令配置好 bonding:

查看 ip link ,发现这下 bond0 和两个 slave eth0, eth1 都是一样的 MAC 地址了:

在交换机上面将 Eth0/0 和 Eth0/1 配置成 Etherchannel 之后,再查看 MAC 地址表:

会发现 0a:56:27:5a:c9:13 这个 MAC 地址对应的既不是 Eth0/0 也不是 Eth0/1,而是 Port Channel 的虚拟接口 Po22

执行一个 ping 命令,我们甚至可以看到 ping request 从 eth1 发出去,reply 从 eth0 收到的奇观。这是因为 Linux 和交换机使用了不同的负载均衡算法。这也是没问题的,只要 request 始终走一张卡,reply 始终走另一张卡,就可以看作是 flow 没有乱序。

ping 的 request 和 response 分别使用了一张网卡

由于发送出去的选路是 Linux 和交换机双方自由决定的,所以故障切换就有一些难度。难点是双发各自不知道对方的状态。之前我们在 Linux 这边就可以完成切换,因为我们什么都不需要交换机来做。现在不行了,假设我们这边网卡挂了,交换机不知道,交换机还是会往这张卡发送,这些包就被丢弃了。

为了解决这个问题,在 Linux 侧,我们应该使用 ARP monitoring 而不是 MII monitoring,这样就可以检测整个链路的状态。在交换机侧也需要配置类似的检测切换机制。

还真是麻烦呢,先不说这些配置有多复杂,光是「是否应该切换」这个问题也无法检测准确,ARP monitoring 可能由于目标 IP 的问题导致误切换。

看来,我们距离完美方案还有一步之遥,下一期我们讨论更加智能的链路聚合。在开启下一期之前,我们再来讨论两个「神奇」的 bonding 模式。

Balance-rr (mode 0)

balance-rr 中 rr 的意思是 round robin,意思是轮询使用所有的 interface 来发送包。我把这个模式配置好,ping 一下,读者就了然了。

ping 发现,request 轮流被两张卡发送

右边上下两个面板分别是两张网卡的 tcpdump. ping 的 reply 可以忽略,因为这是交换机决定的走哪条线。我们专注看 request。这个 request 可就有意思了,它一会从 eth0 发出去,一会从 eth1 发出去,而且是准确的一个包换一次。

这就是 balance-rrbalance-rr 是唯一一个对于同一个 flow 可以使用所有网卡的 bonding 模式。什么意思呢?假设服务器有两张 10G 网卡,做好 bonding,非 balance-rr 的情况下,由于同一个 flow (同一个 TCP 连接)会走同一张卡,一个 TCP 连接最大速率是 10G,假设建立很多 TCP 连接,也许可以用上 20G 的速率。而 balance-rr 可以让同一个 TCP 连接能够用上 20G 的速率。实际上这样会造成乱序,所以 TCP 的例子不是很恰当,派上用场的场景很有限,对于某些基于 UDP 的不关心 flow 顺序的协议可能会有用。

Broadcast (mode 3)

这个就更有意思了,顾名思义,这个模式就是把要发送的包复制到所有的 interface 发送。

broadcast 模式通过两个网卡传送一样的包

这个模式有什么用处呢?也许可以用于流量复制。

在这个模式下光有交换机的链路聚合还不行,因为包从 Linux 这里就复制 2 次了,所以如上图,每一个 ping request 都发出去 2 次,收到 2 个 reply。特殊的拓扑结构才会用到这种模式。

这篇就写到这里,写了这么久,我们的一个包还没找到从服务器传到交换机的「万无一失」的方案呢。别急,希望读者还觉得有趣,我们距离完美方案已经很近了。Until next time!

参考资料:

数据中心网络高可用技术系列

  1. 数据中心网络高可用技术:序
  2. 数据中心网络高可用技术之从服务器到交换机:active-backup
  3. 数据中心网络高可用技术之从服务器到交换机:balance-tlb 和 balance-alb
  4. 数据中心网络高可用技术之从服务器到交换机:链路聚合 (balance-xor, balance-rr, broadcast)
  5. 数据中心网络高可用技术之从服务器到交换机:802.3 ad
  6. 数据中心网络高可用技术之从交换机到交换机:MLAG, 堆叠技术
  7. 数据中心网络高可用技术之从服务器到网关:VRRP
 

数据中心网络高可用技术之从服务器到交换机:balance-tlb 和 balance-alb

在上一篇文章中我们讨论了 active-backup 的模式,能够在一张线路出现故障的时候快速切换,配置也比较简单。但是这种方式有一个很大的缺点——就是明明我有两张卡,但是一次只能使用一张,只有在这张卡挂了的时候才使用另一张。

这样很浪费,我们花了两张卡的钱,希望能用两张卡。我们想要的是两张卡都在工作,当其中一张卡挂了的时候,退回到使用一张卡。

在高可用的设计中,双活优于主备,主备意味着浪费

这篇文章我们来讨论如何能让两张卡都工作。

Balance-tlb (Adaptive transmit load balancing, mode 5)

我们还是通过流量的入和出两个方向分开讨论。

假设想要两张卡都使用,对于出方向的流量,前文提到过 MAC flapping 问题:如果同一个 MAC 一会从端口 1 发出去流量,一会从端口 2 发出流量,交换机通过收到的包学习 MAC 地址会感到困惑。所以,如果两个 interface 都往外发送数据的话,不能使用相同的 MAC 地址

这样,问题就解决了:对于发出去的流量,我们可以用两个 interface 来发,两个 interface 使用不同的 MAC 地址,对于交换机来说,就像是两个不同的主机。

对于接收流量,我们还是只能用一个 interface 来接收。这一点怎么做到呢?还记得别人是怎么发送流量给我们的吗?需要先发送 ARP 通过 IP 获得 IP 对应的 MAC 地址,然后才能将这个 MAC 封装为二层帧的目标来发送。所以,在回应 ARP 请求的时候,我们总是使用其中一个 interface 的 MAC 地址来回复。

balance-tlb 模式:两张卡发送,一张卡接收

如此,我们就实现了 Transmit Load Balancing (balance-tlb):

  • 对于发出去的流量,我们使用两个 interface。但是我们需要某种 hash 的机制,保证同一个 TCP 流总是走同一个 interface,不然就可能带来 reorder 问题,影响性能;(实际上,balance-tlb 模式不是简单的 hash,而是会根据两张卡的负载动态调整使用哪张卡来发)
  • 对于接收流量,由于其他的客户端只知道 IP 对应一个网卡的 MAC 地址,所以入流量总是会走到其中一个 interface 上;
  • 在交换机看来,有一个主机的 MAC 地址只会发出去包,但是从来没有其他人发给这个 MAC,像是一个孤独的可怜人。

虽然这样只是发出去的流量可以充分用两张卡,还是没有完全利用上手里的两张卡,但是已经比较好了。因为对于面向客户的武服务器来说,进入服务器的流量很少(请求一般都比较小),从服务器出去的流量比较多(响应一般很大),像短视频服务器,流媒体,HTTP 服务器等,尤其如此。所以这种方案是可以解决一定的问题的。

Failover 流程

现在我们有两个 interface 在工作,接收流量的叫做主,不接受流量只发送的叫做备。

假设备挂了,那么很简单,接收端不受影响。发送端只要切换到只用主来发就可以了。

假设主卦了,那么发送端要切换到只使用备来发,并且接收端的流量也要切换到备上面。

接收端的流量如何切换呢?我们现在有两个 MAC 地址,切换接收端流量,就要让发送流量的地方来切换。一个很直观的解决思路是切换 ARP。即,让其他的发送者知道,现在应该发送给另一个 MAC 地址了。但是 ARP 太慢了,在 ARP 更新到发送者那里之前,流量都会因为发送到了挂掉的 MAC 地址而被丢弃掉。

那么有没有更快的切换方式呢?发送者的流量是发送给交换机,交换机再发送给我们的。所以一个更好的解决办法是让交换机来切换,交换机原来通过端口1发给我们,现在通过端口2发送我们。如果要实现快速切换,就要求不涉及去通知发送者,发送者还是使用原来的 MAC 地址进行发送。客户端的目标 MAC 地址不能变,但是交换机转发的端口改变,这不就和我们在 数据中心网络高可用技术之从服务器到交换机:active-backup 中讨论的 Gratuitous ARP 一样吗?不过这里需要额外做的事情是,我们的主 MAC 地址所在的 interface 已经挂了,这个 MAC 地址原来在 interface A 上,现在要转移到 interface B 上,需要交换两个 interface 的 MAC 地址。(所以,balance-tlb 模式需要硬件支持改写 MAC 地址才行。)

总结一下这个切换过程,我们要保持主 MAC 地址总是可用来做到不影响 ARP 缓存,快速切换,那么就要:

  1. 交换主和备的 MAC 地址,这样主 MAC 地址迁移到了备上,继续存活;
  2. 通过备 interface (现在的主)发送一个 GARP,让交换机来更新 Mac address table,对于目标 MAC 原先发送给端口1,现在发送给端口2.

演示

我们使用如下的拓扑图来演示,在 ubuntu-5 上面开启 balance-tlb bonding 模式,其他的 ubuntu 作为普通的客户端。

实验拓扑图

在 ubuntu5 上配置 bonding 的命令如下:

查看网卡的信息,可以看到 bond0 interface 的 MAC 地址是和其中的一个 slave eth0 一样,这个 MAC 地址是不能挂的。eth0 这个 interface 也是当前主要的 interface,它会接收 inbond 流量。

如果其他客户端查询 192.168.1.10 对应的 MAC 地址,也是拿到的这个主 MAC 地址 1a:50:9c:11:58:a3,不会知道另一个 MAC 地址。

我们在 ping 的同时,手动 down 掉 eth0. 会看到 1a:50:9c:11:58:a3 这个地址迁移到了 eth1 上来。

与此同时,ping 也没有失败。

这个方案可以在发送方向使用两张卡,也能做快速的自动切换。有没有办法能够在接收方向也能用上两张卡呢?

Balance-alb 模式 (adaptive load balancing, mode 6)

要想让收到的流量也负载均衡,就涉及到发送者了。因为我们作为流量的接收方,有两个 MAC 地址,对于让流量发送到哪一个 interface 来说无能为力。

发送者是怎么决定发给哪一个 MAC 的呢?又回到了 ARP。

那么我们现在有两个 interface,分别有两个 MAC 地址,我们希望这两张 interface 各收到 50% 的流量,可以该怎么做呢?对于两个 MAC 地址,可以让 50% 的发送者发给 MAC AA,另外的 50% 的发送者发送给 MAC BB。具体来说,就是在响应 ARP 的时候,我们有时对别人说,这个 IP 对应的 MAC 地址是 AA,有时说此 IP 对应的是 BB。这样就可以对流量做到一定程度的负载均衡。这种方法叫做 ARP negotiation。

ARP negotiation: 回复不同的 MAC 地址来让发送端进行负载均衡

是不是有点像使用 DNS 做负载均衡

这里面有几个技术难点。

首先,我们在回答 ARP 问题的时候,对于相同的 Client,要给出相同的答案。不能让人家一会发送到 MAC AA,一会又发送到 MAC BB,这样可能造成 TCP 乱序影响性能,对于负载均衡也不好,无法保证两个 interface 收到的流量是均衡的。这个问题的解决方法就是追踪我们回复给不同的客户端什么 MAC 地址,后续对于此客户端都回复一样的 MAC 地址。

第二个问题更难。主机得到 IP 和 MAC 之间的对应关系,不光是靠发出去 ARP 问题来询问,还会从收到的 ARP 问题中学习。当一个主机 Z 收到 ARP 问题:「谁有 xx 的地址,如果有的话,请告诉 192.168.1.10192.168.1.10 的 MAC 地址是 YY。」不管这个主机 Z 有没有 xx 的地址,它都会从这个问题中学习到:192.168.1.10 对应的 MAC 地址是 YY,并且缓存在自己的 ARP 缓存中。

这样做可以减少很多 ARP 查询,假设主机要发送给 192.168.1.10 内容,或者要发送 ARP reply 的时候,就不必再通过 ARP 协议来询问 192.168.1.10 的 MAC 地址了,可以直接根据自己的 ARP 缓存进行发送。

但是这对我们的 balance-alb 来说很糟糕,我们好不容易骗一半的客户端认为我们的 MAC 地址是 AA,一半认为是 BB,一旦我们要询问 ARP,好了,所有的人都知道我们的 MAC 地址是 AA(或者 BB)了,接收的流量又全部去了一条线路上。

ARP 问题刷新了所有的客户端 ARP 缓存

有什么方法能让我们在询问 ARP 的时候,不要让别人学习到同一个 MAC 地址呢?既然我们已经追踪了之前回复给所有客户端的 MAC 地址,能否在发送 ARP 问题的时候,对于一半的客户端使用 AA 来询问,另一半使用 BB 来询问?

这是不可行的,因为我们询问 ARP 的时候,不是发送 N 个请求出去询问 N 个客户端,而是发送一个广播包给交换机,交换机帮助我们广播给 N 个客户端。所以对于一个 ARP 问题,我们发出去的只有一个包而已,无法对于不同的客户端区别对待。

这样看来 ARP 问题刷新所有人的缓存是无法避免的了。我们能做的,只有是在刷新这些缓存之后,重新修正部分客户端的 ARP 缓存。即,我们在我们的 ARP 问题收到回复之后,再对所有人发送一个 Gratuitous ARP,使用自己不同的 MAC 地址告知这些客户端。

发送 GARP 重新对客户端分流

之前我们学到的 Gratuitous ARP 发送的是(不求答案的)问题,为的是更新交换机的 MAC – 端口对应关系。而在这里,我们需要更新的是客户端的 IP-MAC 地址对应关系,所以我们要发送的是(没有人问的) ARP reply。Gratuitous ARP 不仅可以是问题,也可以是 reply。当其他主机收到这个 ARP reply 的时候,会有些奇怪,但是他们也会更新自己的 ARP 缓存「我没有问你呀,为什么要告诉我你的 IP 对应的 MAC 是 xx,算了,我先记下吧。」

实验

还是上面的拓扑图,配置命令也几乎一样。唯有 mode 现在改成了 balance-alb

配置好之后,我们在 ubuntu-5 上面查看 link,结果和之前也是一样的。

但是我们去另外的两台机器分别查看 ARP 记录,有趣的就来了,不同的机器显示相同的 IP 有不同的 MAC 地址:

然后我们在 ubuntu-5 尝试发出去一个 ping 包,并且在这两台机器抓包,(只抓 in 方向的包,看看其他的客户端都会收到哪些 ARP 内容)。

可以看到,所有人都收到了一开始的 ARP 广播问题,随后又收到了一个自作多情的 ARP reply,但是 reply 中 IP 对应的 MAC 地址也是不同的。

但是,理论上发送一个包就够了,我在实验的时候,每次都会收到正好2个 GARP 的包,不知道为什么,在网络上提问也没人回答,看代码也没看懂。有知情的读者欢迎赐教。

Failover 过程

Failover 的过程和 balance-tlb 基本上一样,但是现在,无论是哪一个卡挂了,我们必须要更新所有人的 ARP 缓存,不能只让交换机换端口了。

Failover 流程如下:

  • 如果挂的是主,交换两张卡的 MAC 地址,如果是备,不需要;
  • 发送 GARP 给所有人(Unicast),告诉所有人自己的 IP 对应的 MAC(当然是没挂的那一个)。

将 link set down 并且在其他机器上抓包,就会看到有多个 GARP 包发过来。

总结和分析

到现在我们讨论了三种 bonding 模式:

  • active-backup:实现简单,快速切换,只能用单卡;
  • balance-tlb:实现简单,快速切换,发送能用双卡,需要硬件支持 MAC 地址修改;
  • balance-alb:实现简单,切换较慢,涉及 GARP 去刷新所有的客户端缓存,收发双卡,需要硬件支持 MAC 地址修改。

博客中讨论的这三种方案都是用了两张卡来讨论的,实际上这三种方案都可以加更多的卡,工作原理完全一样。(仔细想想看!)

实际上,这些都有缺点,都不是数据中心在用的方案,但是我们离「完美」的方案越来越近了,希望读者觉得这篇讨论的内容有趣,until next time!

参考资料:

数据中心网络高可用技术系列

  1. 数据中心网络高可用技术:序
  2. 数据中心网络高可用技术之从服务器到交换机:active-backup
  3. 数据中心网络高可用技术之从服务器到交换机:balance-tlb 和 balance-alb
  4. 数据中心网络高可用技术之从服务器到交换机:链路聚合 (balance-xor, balance-rr, broadcast)
  5. 数据中心网络高可用技术之从服务器到交换机:802.3 ad
  6. 数据中心网络高可用技术之从交换机到交换机:MLAG, 堆叠技术
  7. 数据中心网络高可用技术之从服务器到网关:VRRP
 

重新认识 TCP 的握手和挥手:答案和解析

本文是重新认识 TCP 的握手和挥手一文的答案和解析。

第一题,3个。

Wireshark 选择 Statistics > 选择 TCP Tab 就可以看到 3 个会话,以及 IP 端口,一共使用的数据量,发送的速率等等。

Wireshark 的会话统计功能

第二个问题,找到这 3 个会话的握手包和挥手的包。

这个问题比较简单,借这个问题介绍一个 Wireshark 的很好用的功能:Profile。

Profile 可以让你在分析不同的网络问题或者网络协议的时候使用不同的配置,比如,我们在分析 HTTP 问题的时候,就让 Wireshark 切换到 HTTP 模式;在分析 TCP 性能的时候,就切换到「TCP 性能模式」。

Profile 可以在 Edit > Configuration Profiles… 打开,然后可以添加或者复制已有的模式。

进入 Profile 管理

我们新添加一个 TCP Profile。(也可以复制已有的)

添加一个新的 Profile

我们点击 Wireshark 右下角的 Profile: 可以切换,选择我们刚刚创建的 TCP 模式。

刚切换过来,和之前没有什么不同。我们可以在这个 Profile 下做一些配置。

在 View > Coloring Rules… 可以打开颜色配置,在这里可以修改 Packet 在 Wireshark 中显示的颜色。

颜色配置入口

我们删除其他所有的颜色,只留下 TCP 和 TCP flags 的配色。

Wireshark 颜色配置

这时候回到 Wireshark,就没有其他的颜色干扰了,我们想要的 TCP SYN 和 FIN 都展现在眼前。

刚刚的修改只会影响我们创建的 TCP 这个 Profile,如果你在刚刚右下角的位置切换回 Default, 那么 Default 的颜色配置又回来了。Profile 就是我们对不同问题分析的时候用的不同配置。

如果还觉得不够清晰,可以试试这个 Display Filter Button 功能。

点击这个 +,可以输入过滤条件。
输入 Label,Filter 和 Comment

点击 OK,在 + 右边会出现一个 SYN||FIN 的按钮。点击之后,就会直接应用我们给这个按钮绑定的过滤条件。

使用 Display Filter Button 快速过滤

这个按钮也是跟随 Profile 的,切换不同的 Profile 就可以展示不同的快速过滤按钮。适合将常用的 filter 给保存下来。

在第二题中,前两个会话是特殊构造的。

第一个会话的三次握手其实只有两个包。在TCP 延迟分析中,我们知道三次握手的第三个包发送出去之后就可以直接发送数据,不占用延迟时间,那么是否可以将数据和第三个包(实际上是一个 ACK)一起发送呢?答案是可以的,就和当前题目中给出的抓包文件一样。

在之前的博客 TCP可以使用两次握手建立连接吗?再多来点 TCP 吧:Delay ACK 和 Nagle 算法中也有讨论。

第二个会话中,四次挥手其实是三次,FIN 和 ACK 也合并了。读者如果没有注意到,可以再仔细观察下第二个 TCP 连接。

在第三个问题,如何区分 ACK 的是数据还是 FIN flag 呢?答案是:FIN flag 也是占用一个 sequence number 的。

我们可以用第三个会话来分析这个现象。在第三个会话中右键选择 Follow > TCP Stream.

过滤某一个单独的会话

就可以只显示和这个 TCP 会话有关的包了,在有很多 TCP 连接,我们只想分析其中一个的时候,非常有用。

除了 Wireshark 的包列表页面,我们还会看到一个明文的页面,这就是这个 TCP 会话中发送的所有数据。

TCP Stream 分析

我们这里想要分析的 seq number 和 ack number,所以可以在列表中展示这两列。直接在列的 header 右键可以编辑。

也可以打开一个包,在想要的字段上右键,选择 Apply as Column,就可以直接把这个字段放到列里面。

Apply as Column

同理,也把 ack number 放到 Column 里面。

找到一个 FIN 的包,就可以清楚的看到这个 length 为 0 的 FIN 包页增加了一个 seq number。

在 TCP 协议里面是这么说的。

A control bit (finis) occupying one sequence number, which indicates that the sender will send no more data or control occupying sequence space.

RFC 793

总结一下,今天学习到的 Wireshark 技巧真多呢:

  • Wireshark 的会话统计功能
  • 配置 Profile 和颜色
  • 配置 Profile 的快速过滤按钮
  • 过滤单独的 TCP 会话
  • 将想看的字段展示在 Column 上面

==计算机网络实用技术 目录==

这篇文章是计算机网络实用技术系列文章中的一篇,这个系列正在连载中,我计划用这个系列的文章来分享一些网络抓包分析的实用技术。这些文章都是总结了我的工作经历中遇到的问题,经过精心构造和编写,每个文件附带抓包文件,通过实战来学习网路分析。

如果本文对您有帮助,欢迎扫博客右侧二维码打赏支持,正是订阅者的支持,让我公开写这个系列成为可能,感谢!

没有链接的目录还没有写完,敬请期待……

  1. 序章
  2. 抓包技术以及技巧
  3. 理解网络的分层模型
  4. 数据是如何路由的
  5. 网络问题排查的思路和技巧
  6. 不可以用路由器?
  7. 网工闯了什么祸?
  8. 网络中的环路和防环技术
  9. 延迟增加了多少?
  10. TCP 延迟分析
  11. 重新认识 TCP 的握手和挥手
  12. 重新认识 TCP 的握手和挥手:答案和解析
  13. TCP 下载速度为什么这么慢?
  14. TCP 长肥管道性能分析
  15. 后记:学习网络的一点经验分享
与本博客的其他页面不同,本页面使用 署名-非商业性使用-禁止演绎 4.0 国际 协议。
 

数据中心网络高可用技术之从服务器到交换机:active-backup

数据中心里面是一个个的机架(Rack),机架里面放着服务器,怎么把这些服务器连接起来呢?如果是 ToR (Top of Rack)的架构,就是在每一个机架上放一个机架交换机,这个机架的所有机器都连接顶部的交换机,然后再用聚合交换机把机架顶部的交换机连接起来。

ToR Switch, 来源

服务器和交换机是怎么连接的呢?最简单的方式是,服务器上有一个网卡,用网线把服务器和交换机连接起来。但这样做的话,我们就有了很多「单点」:网卡,网线,和交换机。高可用设计的目标就是排除掉单点,方法是添加冗余。

网卡通过 PCI 或者 PCIe 接口插在主板上,可以插多个网卡。有的网卡能够提供多个 Ethernet 接口或者多个光口

于是我们在服务器上再插上一根网卡,然后我们再用一根线连接服务器和交换机。

服务器上面有两个网卡,使用两条线连接到交换机的两个端口

现在在服务器上,我们就有了两个物理卡,对应地,我们在操作系统上可以看到两个 interface。

我们怎么配置这两个网卡呢?

首先,假设我们给两个 interface 分别配置一个 IP 地址,这样的话,在交换机和其他设备看来,这个服务器其实是两个机器,因为它是两个不同的 IP,已经失去了高可用的意义了。因为软件是需要基于 IP 来部署和交互的,拿 Etcd 来讲,假设我们部署 Etcd 在这个机器上,它就只能 listen 其中的一个 IP。如果部署两个实例分别 listen 一个 IP,那在其他实例看起来,好像是有两个不同的实例,但其实是部署在一个物理机上,这样,反而降低了可用性。因为物理机一挂就会导致两个 Etcd 实例一起失败。综上,我们要让服务器对外看起来还是一个 IP 才行。

我们在考虑:假设给这两个网卡配置成一样的 MAC 地址行不行?这样,对外看起来只有一个 IP 和一个 MAC 地址,发送数据的时候可以用两条线,接收数据的时候,无论哪一条线收到都可以。看起来完美,但是忽略了一个重要的角色——交换机。

还记得交换机是怎么工作的吗?它从每一个收到的包学习 MAC 地址。两条线接到交换机上,对于交换机来说,这就是两个客户端。假设这两个网卡(客户端)的 MAC 地址一样,都是 MAC AA,那么当网卡 A 从交换机端口 1 发送数据出去的时候,交换机学习到:「MAC AA 对应端口1,发往 MAC AA 的数据都转发给端口 1」;但是当网卡 B 从端口 2 发送出去的时候,来源 MAC 地址也是 AA,交换机就学习到:「OK,现在 MAC AA 是在端口 2 了,让我修改我的 MAC 地址表,之后如果发给 MAC AA 我就往端口 B转发就好了」。过了一会,交换机的端口 1 又收到了 MAC AA 发来的数据,交换机迷惑了——「怎么这个 MAC AA 一会插在端口 1 上,一会插在端口 2 上,切换如此频繁,到底是谁的手速这么快?」。

这就是 MAC flapping 问题,指的就是同一个 MAC 地址在不同的交换机端口之间来回切换。

它的坏处有几个:

  1. 显而易见它会给交换机带来困扰,交换机来回修改 MAC 地址表,性能会下降;
  2. 对目标地址为 MAC AA 的,交换机会时而发给端口 1,时而发给端口 2,可能会造成同一个 TCP 连接的乱序问题,从而造成性能下降。

综上,我们不能对两个网卡使用相同的 MAC 地址。

但是我们可以把两张卡配置成一样的 MAC 地址,却不同时使用呀。

最简单的方案是:我们总是使用一张物理卡,当这个网卡不可用的时候,我们转而无缝切换到另一张网卡。这就是 Linux bonding 的 active-backup 模式。

配置 bonding active-backup 模式(mode 1)

从命令行配置 bonding 模式非常直观,大体的步骤是,把要配置的网卡先 down 掉,然后创建一个 bond 模式的 interface,将物理网卡设置为 bond 的 slave,最后把 bond 设置为 up,完事。(不需要手动设置物理网卡为 up,会自动 up。)

命令如下:

其中,ip link add bond0 type bond mode active-backup 命令又可以写成 ip link add bond0 type bond mode 0。每一个 bond mode 都有一个编号。(我们在接下来的文章中会循序渐进地介绍这些 mode)。

实验用的拓扑图

在这个拓扑图中,我们对 ubuntu-5 机器配置好了 bonding。使用 prof fs 的接口可以查看当前 bonding 的配置:

可见当前的 slave 是 eth0

Failover 过程

我们已经配置好了 active-backup 模式,希望在主接口 down 之后,自动切换到 backup 接口。

但是现在的配置下,是不能自动切换的,因为 bond 不知道应该何时切换。高可用的部署中,我们加了冗余之后,还需要思考两个问题:

  1. 什么时候会触发切换;
  2. 以及如何切换。

Failover 触发

Failover 触发方案的本质是监控——要监控两条线路的状态,在一条线路 down 的时候,执行切换动作。主要的监控方式有两种:MII Monitoring 和 ARP Monitoring。

MII Monitoring

MII 的全称是 Media-independent interface,是 MAC 硬件层和传输媒介 PHY 硬件之间的接口。

MII 在 PHY 和 MAC 之间,来源

它是干什么的呢?还记得理解网络的分层模型中我们提到的「沙漏模型」吗?假设没有 MII,网卡中的 MAC 硬件直接连接物理媒介,那么每出现一种新的物理媒介,比如千兆以太网,万兆以太网,各种光纤,都要去适配所有的 MAC 硬件,是 M x N 的工作量。如果有 MII,MAC 硬件对接 MII,然后每出现一种新的媒介,只需要开发一次新的 MII 接口即可。

MII Monitoring 就是通过 MII 来检查物理物理网卡的状态。如果物理网卡挂了,通过 MII 就可以检测到。但是 MII 检查通过不能代表网络是通的

(之前我有一个误解,我觉得 MII 只能检测网卡自身问题,无法检测像是网线不良,对端是否插线,对端设备挂了,对端设备端口挂了等问题,但是后来发现 PHY 芯片是可以检测到这些问题的,这里稍微展开一下。)

use_carrier 如果打开的话(默认就是 1, 打开的),就使用 netif_carrier_ok 来获取链路状态,底层依赖的是网卡驱动程序。大部分的网卡驱动程序都支持 netif_carrier_on/off 功能,如果不支持的话,那么链路检测永远是 up 的,即使挂了也不会触发 bonding 的切换。所以网卡如果不支持,就得把 use_carrier 改成 0

use_carrier 能够检查出来更多的问题,原理是通过 PHY 芯片来检查以太网物理层上的电信号(载波检测、信号强度、波形和信噪比),在以太网线路上,即使线路是 idle 的,只要线路健康,也会有一些信号在线路上发送,这些信号就可以用来做健康检测。在一些高阶的以太网标准上,比如 IEEE 802.3 1000BASE-T,能够检测的故障更多。可以检测出对端交换机挂了,交换机的端口挂了等问题。

MII Monitoring 无法检测的问题是:交换机正常运行但是配置错误,或者通过了 Linux 网卡驱动的检测但是发送数据会有问题等等。

下面会演示 MII Monitoring 触发的切换。

MII Monitoring 下的 Failover 测试

我们在上面的配置中,并没有配置 miimon ,所以默认是关闭的。这里再配置下检测频率为 102ms.

再看一下 bonding 状态,确认 miimon 已经生效,并且当前 active 端口是 eth0.

我们现在 ping 交换机另一端的一个主机,并且在 ping 的过程中手动 down 掉现在的 active eth0 端口。

ping 程序也显示,在切换的过程中一个包都没有丢。我们来分析一下这个切换过程。

Failover 过程分析

对于对端的主机来说,什么都没发生改变,因为这个 IP 对应的 MAC 地址没变,对端主机依然按照这个目标 IP 和 MAC 地址发送包过来。

出流量对于本机来说,切换也很简单,原先成 eth0 发送出去,现在从 eth1 发送出去即可。

入流量就麻烦了,我们的端口 down 了,交换机可不知道,入流量是交换机来决定从哪条线路发送过来的,所以流量还是会从端口 1 源源不断地进来。

发出流量已经切换,可是怎么切换接收的流量呢?

我们想要的是:让交换机现在通过端口 2 来发给我们流量,而不是端口 1.

如何做到呢?还记得交换机的工作方式吗?交换机从每一个收到的包学习 MAC 地址和端口的对应关系。利用这个,我们让交换机学习到,此时 MAC AA 对应的是端口 2,而不是端口 1。

即,我们使用 MAC AA 作为 Src MAC 从端口 2 发送点数据出去,交换机就知道了。

在 Failover 的时候用 tcpdump 来抓包,我们可以观察到在 backup 的端口发送出去的内容。

哈,eth1 发送出去了一个 ARP 请求,它问:「谁有 192.168.1.10 的地址?请告诉 192.168.1.10。」可是这个 IP 明明是它自己呀。它这是明知故问,没有人会回复给他,它也不需要答案,发送这个 ARP 请求的目标是让交换机知道现在 MAC AA 对应端口 2。

从交换机的视角,就如同 MAC AA 原先插在端口 1 上,现在移动到了端口 2 上一样,交换机会立即把发往这个 MAC 地址的流量切换到端口 2.

这种 ARP 的用法叫做 Gratuitous ARP(不必要的ARP),有的时候是不要的 ARP 请求,有的时候是不必要的 ARP 响应(我们会在后面见到)。在 RFC 5227 中定义。

实验:交换机端口 down

我们继续用 MII Monitoring 的方式,来测试一下模拟交换机 down,看能否触发切换。

确认当前的 active 端口:

然后我们 ping 其中的一个主机,同时去交换机 down 掉 eth0 连接的端口。

可以看到现在无法完成切换,此时的 active interface 还是 eth0。因为 MII Monitoring 依然认为服务器的物理链路是好的(这个实验是在没有上文说的 use_carrier 功能下做的,所以 MII 无法检测对端的端口 down)。

ARP Monitoring

ARP Monitoring 的原理就是用 ARP 协议一直对某一个 IP 询问 MAC 地址,如果能够得到回复,说明网络没问题,如果得不到回复,就执行切换。

我们首先设置 miimon 为 0 来关闭 MII Monitoring,然后开启 ARP Monitoring,主要设置两个选项:ARP 检测的地址和检测的频率,这里使用 1s。

然后开始测试切换,查看现在 active 的端口是 eth1

然后开始 ping,在 ping 的时候在交换机把 eth1 端口 down 掉。

可以看到第 11-13 个包丢了,一共丢了三个包。因为我们设置的频率是 1s,所以切换有些慢的。ARP Monitoring 比 MII Monitoring 能检测的网络范围更广泛。

ARP 也有问题,就是如果我们使用的 192.168.1.12 有问题,有时候回复 ARP 有时候不回复,就会导致端口来回 flapping。一个解决方法是,ARP Monitoring 支持多个 IP 检查目标,就可以避免 false alarm。

另一个坏处是会给网络带来额外的 ARP 流量。但现在网络都是万兆起步,这点流量可以忽略。

分析和总结

本文讨论了 Linux bonding 模式中的一种:active-backup。这个模式的特点是:

  • 不需要交换机特殊配置,在交换机看来就是两个独立的端口;
  • 由于交换机视角是独立的,所以我们可以把两根线接到两个不同的交换机上,可以实现多交换机的 Failover,避免交换机的单点故障;
  • 一次只能利用一条线路,假设两条1G线路,总速率还是 1G,有一条线总是浪费的;

本质上这是个冷备方案,我们不喜欢冷备方案,因为它浪费资源。下一篇文章我们讨论如何将两条线路都利用起来。

数据中心网络高可用技术系列

  1. 数据中心网络高可用技术:序
  2. 数据中心网络高可用技术之从服务器到交换机:active-backup
  3. 数据中心网络高可用技术之从服务器到交换机:balance-tlb 和 balance-alb
  4. 数据中心网络高可用技术之从服务器到交换机:链路聚合 (balance-xor, balance-rr, broadcast)
  5. 数据中心网络高可用技术之从服务器到交换机:802.3 ad
  6. 数据中心网络高可用技术之从交换机到交换机:MLAG, 堆叠技术
  7. 数据中心网络高可用技术之从服务器到网关:VRRP