故障现象
在监控上发现部分虚拟机每隔大概20分钟就会出现一次入口流量高峰,大小在1MB/s左右:
故障原因
交换机上配置了广播抑制,导致整个环境中没有广播包。在计算节点上Linux Bridge的MAC learning table中网关对应的MAC地址过期后(默认值300秒),没有及时更新,Linux Bridge会把本来应该发到网关对应端口的数据包发送到所有端口。部分业务Client虚拟机会持续向业务Server发送数据,当网关MAC 失效后,本来发送给业务Server的数据包被发送给了同宿主机上的所有虚拟机,因此出现入口流量峰值。
处理方法
方法一:解除交换机上的广播抑制。
方法二:配置Linux Bridge的MAC Ageing Time为1500秒,此时间大于交换机ARP的过期时间,保证在Linux Bridge上的网关MAC地址记录过期之前收到来自网关的ARP请求包,因而可以及时更新网关MAC地址。
排查过程
在虚拟机出现流量峰值时,登陆到虚拟机使用iftop查看流量详情:
# iftop -nNBP
发现峰值流量的源目的地址都不是本机,于是分别查看源目的地址机器,经过粗略分析判断目的地址是业务Server,源地址是某台业务Client服务器,业务Client发送给业务Server的流量窜到其他虚拟机上了。
下意识感觉受害虚拟机跟这两个机器应该存在某些关联,由于目的机器是一台物理机,关系应该不大,于是重点查看源地址,这是一台虚拟机。果然,发现这两台虚拟机位于同一台宿主机上。查看宿主机上的其他虚拟机,存在同样的问题:
继续去受害虚拟机上抓包,分析错误发来的数据包存在什么特征,因为Linux Bridge执行二层转发的功能,于是打印出数据包的链路头信息:
# tcpdump -e -nnn host 10.212.26.241 and host 10.212.13.14
发现目的MAC都是10:0a:10:0b:10:0c,这明显不是一个正常的MAC地址,查看arp表:
显示这个MAC地址对应的是网关。到宿主机上查看arp表,结果一样:
猜测这是在交换机上的封装过的MAC地址,这不重要,对于整个虚拟化环境来说,它就是网关的MAC地址。在宿主机上抓包:
可以看到源目的IP正常通信的往来数据包。而且在正常情况下,受害虚拟机没有收到误转发流量包时,物理机上也能抓到形式一样的数据包。那么在什么情况下,本应发送给网关的数据包会被网桥错误地转发给虚拟机呢?
经过一番搜索,查到了Linux Bridge的MAC learning table这个东西,交换机上也有一样的概念。它记录着网桥的每个端口连接着同个二层网络的哪些MAC地址,即便跨越了多个交换机。使用brctl showmacs BR-NAME查看Linux Bridge的MAC learning table:
而在出现异常流量时,MAC learning table是这样的:
明显看到网关的MAC消失了。这是因为默认MAC learning table记录的过期时间是300秒,超过300秒后记录就被删除。而每当收到某个端口数据包时,Linux Bridge会更新这个数据包的源MAC地址到MAC learning table。
经过观察发现MAC learning table中网关的记录会不定期地在ageing time到达几十秒、一百多秒时更新一次,但是周期性地会有一次不更新,在ageing time达到300秒后消失几分钟,也正是在网关MAC消失的这个时间段内虚拟机上会出现异常流量。
在物理交换机上,如果数据包的目的MAC地址在MAC learning table里找不到,那么这个数据包会被丢弃,但是由于我们的Linux Bridge没有开启STP,它会将数据包发送到所有端口,类似一个集线器。
因为有多个集群,为什么其他集群是正常的而只有这个集群出现问题。在不同集群的计算节点上抓包:
看到在正常环境中会频繁收到来自网关的ARP广播,所已Linux Bridge能够及时更新MAC learning table,而在问题集群中,完全没有广播包,只有在网关需要查询这个主机上存在的机器时,才会发送一个ARP单播包。这超出了正常的认知,怀疑是交换机做了特殊配置,跟网络组沟通,又向厂商询问后,得到回复确实是为了避免泛洪,交换机上配置了广播抑制,才出现这样的情况。
那么如何解决呢,一个办法是关闭交换机的广播抑制,但是这样会引入广播泛洪的风险。另一个办法是将计算节点Linux Bridge的MAC Ageing Time调高,使它超过交换机上ARP的过期时间,这样就能保证在网关MAC地址记录过期之前收到来自网关的ARP请求包,因而可以及时更新网关MAC地址。目前设置Ageing Time为1500秒:
# brctl setageing brqa96cd777-01 1500
为了保证配置不失效,将命令写入/sbin/ifup-local脚本,这个脚本会在每个网络设备启动后,被/etc/sysconfig/network-scripts/ifup-post调用。/sbin/ifup-local内容:
if [[ "$1" == "brq"* ]]; then /sbin/brctl setageing $1 1500 fi
参考文档
How to disable MAC learning in a Linux bridge
ARP Timeout Value for Cisco 3750, Linux and Windows
How to configure a Linux Bridge to act as a Hub instead of a Switch
CentOS: Start custom script automatically after network startup