假设想要两张卡都使用,对于出方向的流量,前文提到过 MAC flapping 问题:如果同一个 MAC 一会从端口 1 发出去流量,一会从端口 2 发出流量,交换机通过收到的包学习 MAC 地址会感到困惑。所以,如果两个 interface 都往外发送数据的话,不能使用相同的 MAC 地址。
这样,问题就解决了:对于发出去的流量,我们可以用两个 interface 来发,两个 interface 使用不同的 MAC 地址,对于交换机来说,就像是两个不同的主机。
对于接收流量,我们还是只能用一个 interface 来接收。这一点怎么做到呢?还记得别人是怎么发送流量给我们的吗?需要先发送 ARP 通过 IP 获得 IP 对应的 MAC 地址,然后才能将这个 MAC 封装为二层帧的目标来发送。所以,在回应 ARP 请求的时候,我们总是使用其中一个 interface 的 MAC 地址来回复。
接收端的流量如何切换呢?我们现在有两个 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 缓存,快速切换,那么就要:
交换主和备的 MAC 地址,这样主 MAC 地址迁移到了备上,继续存活;
通过备 interface (现在的主)发送一个 GARP,让交换机来更新 Mac address table,对于目标 MAC 原先发送给端口1,现在发送给端口2.
2:bond0:<BROADCAST,MULTICAST,MASTER,UP,LOWER_UP>mtu1500qdisc noqueue state UP mode DEFAULTgroup defaultqlen1000
link/ether1a:50:9c:11:58:a3 brd ff:ff:ff:ff:ff:ff
35:eth0:<BROADCAST,MULTICAST,SLAVE>mtu1500qdisc fq_codel master bond0 state DOWN mode DEFAULTgroup defaultqlen1000
link/ether9e:fa:f1:b5:0c:28brd ff:ff:ff:ff:ff:ff
36:eth1:<BROADCAST,MULTICAST,SLAVE,UP,LOWER_UP>mtu1500qdisc fq_codel master bond0 state UNKNOWN mode DEFAULTgroup defaultqlen1000
link/ether1a:50:9c:11:58:a3 brd ff:ff:ff:ff:ff:ff
与此同时,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 问题的时候,对于相同的 Client,要给出相同的答案。不能让人家一会发送到 MAC AA,一会又发送到 MAC BB,这样可能造成 TCP 乱序影响性能,对于负载均衡也不好,无法保证两个 interface 收到的流量是均衡的。这个问题的解决方法就是追踪我们回复给不同的客户端什么 MAC 地址,后续对于此客户端都回复一样的 MAC 地址。
第二个问题更难。主机得到 IP 和 MAC 之间的对应关系,不光是靠发出去 ARP 问题来询问,还会从收到的 ARP 问题中学习。当一个主机 Z 收到 ARP 问题:「谁有 xx 的地址,如果有的话,请告诉 192.168.1.10,192.168.1.10 的 MAC 地址是 YY。」不管这个主机 Z 有没有 xx 的地址,它都会从这个问题中学习到:192.168.1.10 对应的 MAC 地址是 YY,并且缓存在自己的 ARP 缓存中。