【文章内容】
bonding简介
将多个Linux网络端口绑定为一个,可以提升网络的性能,比如对于备份服务器,需要在一个晚上备份几个T的数据,如果使用单个的千兆网口将会是很严重的瓶颈。其它的应用,比如ftp服务器,高负载的下载网站, 都有类似的问题。因此使用Linux teaming或bond来绑定多个网卡作为一个逻辑网口,配置单个的IP地址,会大幅提升服务器的网络吞吐(I/O)。
Linux的多网卡绑定功能使用的是内核中的”bonding”模块,关于此模块可以参考Linux Ethernet Bonding Driver文档, 但是目前发布各个Linux版本内核均已包含了此模块,大多数情况下不需要重新编译内核。 Linux的bonding模块提供了绑定/集成(bond)多个网卡为一个虚拟逻辑网口的功能。
驱动以及Changes介绍
linux的bonding驱动的最初版本仅仅提供了基本的机制,而且需要在加载模块的时候指定配置参数,如果想更改配置参数,那么必须重新加载bonding模块;然后modprobe支持一种rename的机制,也就是在modprobe的时候支持使用-o重新为此模块命名 ,这样就可以实现一个模块以不同的配置参数加载多次了,起初比如我有4个网口,想把两个配置成负载均衡,两个配置成热备,这只能手工重新将bonding编译成不同的名称来解决,modprobe有了-o选项之后,就可以两次加载相同的驱动了,比如可以使用:
modprobe bonding -o bond0 mode=0
modprobe bonding -o bond1 mode=1
加载两次bonding驱动,用lsmod看一下,结果是bond0和bond1,并没有bonding,这是由于modprobe加载时命名了,然而最终,这个命名机制不再被支持了,因为正如modprobe的man手册所叙述的一样,-o重命名机制主要适用于test。最后,bonding支持了sysfs的配置机制,对/sys/class/net/目录下的文件进行读或者写就可以完成对驱动的配置。
不管怎样,在sysfs完全支持bonding配置之前,如果想往某一个bonding网卡添加设备或者删除设备的时候,还是要使用经典且传统的ioctl调用,因此必然需要一个用户态程序与之对应,该程序就是ifenslave。
我想,如果linux的所有关于设备的配置都能统一于sysfs,所有的关于内核和进程配置统一于procfs(内核是所有进程共享的地址空间,也有自己的内核线程以及进程0,因此对内核的配置应该在procfs中),对所有的消息,使用netlink通信,这就太好了,摆脱了命令式的ioctl配置,文件式(netlink使用的sendto之类的系统调用也可以归为文件系统调用相关的)的配置将更加高效,简单以及好玩!
bonding配置参数
在内核文档中,列举了许多bonding驱动的参数,然后本文不是文档的翻译,因此不再翻译文档和介绍和主题无关的参数,仅对比较重要的参数进行介绍,并且这些介绍也不是翻译,而是一些建议或者心得。
ad_select: 802.3ad相关。如果不明白这个,那不要紧,抛开Linux的bonding驱动,直接去看802.3ad的规范就可以了。列举这个选项说明linux bonding驱动完全支持了动态端口聚合协议。
arp_interval和arp_ip_target: 以一个固定的间隔向某些固定的地址发送arp,以监控链路。有些配置下,需要使用arp来监控链路,因为这是一种三层的链路监控 ,使用网卡状态或者链路层pdu监控只能监控到双绞线两端的接口 的健康情况,而监控不到到下一条路由器或者目的主机之间的全部链路的健康状况。
primary: 表示优先权,顺序排列,当出现某种选择事件时,按照从前到后的顺序选择网口,比如802.3ad协议中的选择行为。
fail_over_mac: 对于热备模式是否使用同一个mac地址,如果不使用一个mac的话,就要完全依赖免费arp机制更新其它机器的arp缓存了。比如,两个有网卡,网卡1和网卡2处于热备模式,网卡1的mac是mac1,网卡2的mac是mac2,网卡1一直是master,但是网卡1突然down掉了,此时需要网卡2接替,然而网卡2的mac地址与之前的网卡1不同,别的主机回复数据包的时候还是使用网卡1的mac地址来回复的,由于mac1已经不在网络上了,这就会导致数据包将不会被任何网卡接收。因此网卡2接替了master的角色之后,最好有一个回调事件,处理这个事件的时候,进行一次免费的arp广播,广播自己更换了mac地址。
lacp_rate: 发送802.3ad的LACPDU,以便对端设备自动获取链路聚合的信息。
max_bonds: 初始时创建bond设备接口的数量,默认值是1。但是这个参数并不影响可以创建的最大的bond设备数量。
use_carrier: 使用MII的ioctl还是使用驱动获取保持的状态,如果是前者的话需要自己调用mii的接口进行硬件检测,而后者则是驱动自动进行硬件检测(使用watchdog或者定时器),bonding驱动只是获取结果,然而这依赖网卡驱动必须支持状态检测,如果不支持的话,网卡的状态将一直是on。
mode: 这个参数最重要,配置以什么模式运行,这个参数在bond设备up状态下是不能更改的,必须先down设备(使用ifconfig bondX down)才可以配置,主要的有以下几个:
- balance-rr or 0: 轮转方式的负载均衡模式,流量轮流在各个bondX的真实设备之间分发。注意,一定要用状态检测机制,否则如果一个设备down掉以后,由于没有状态检测,该设备将一直是up状态,仍然接受发送任务,这将会出现丢包。
- active-backup or 1: 热备模式。在比较高的版本中,免费arp会在切换时自动发送,避免一些故障,比如fail_over_mac参数描述的故障。
- balance-xor or 2: 我不知道既然bonding有了xmit_hash_policy这个参数,为何还要将之单独设置成一种模式,在这个模式中,流量也是分发的,和轮转负载不同的是,它使用源/目的mac地址为自变量通过xor|mod函数计算出到底将数据包分发到哪一个口。
- broadcast or 3: 向所有的口广播数据,这个模式很XX,但是容错性很强大。
- 802.3ad or 4: 这个就不多说了,就是以802.3ad的方式运行。
xmit_hash_policy: 这个参数的重要性我认为仅次于mode参数,mode参数定义了分发模式 ,而这个参数定义了分发策略 ,文档上说这个参数用于mode2和mode4,我觉得还可以定义更为复杂的策略呢。
- layer2: 使用二层帧头作为计算分发出口的参数,这导致通过同一个网关的数据流将完全从一个端口发送,为了更加细化分发策略,必须使用一些三层信息,然而却增加了计算开销,天啊,一切都要权衡!
- layer2+3: 在1的基础上增加了三层的ip报头信息,计算量增加了,然而负载却更加均衡了,一个个主机到主机的数据流形成并且同一个流被分发到同一个端口,根据这个思想,如果要使负载更加均衡,我们在继续增加代价的前提下可以拿到4层的信息。
- layer3+4: 这个还用多说吗?可以形成一个个端口到端口的流,负载更加均衡。然而且慢! 事情还没有结束,虽然策略上我们不想将同一个tcp流的传输处理并行化以避免re-order或者re-transmit,因为tcp本身就是一个串行协议,比如Intel的8257X系列网卡芯片都在尽量减少将一个tcp流的包分发到不同的cpu,同样,端口聚合的环境下,同一个tcp流也应该使用本policy使用同一个端口发送,但是不要忘记,tcp要经过ip,而ip是可能要分段的,分了段的ip数据报中直到其被重组(到达对端或者到达一个使用nat的设备)都再也不能将之划为某个tcp流了。ip是一个完全无连接的协议,它只关心按照本地的mtu进行分段而不管别的,这就导致很多时候我们使用layer3+4策略不会得到完全满意的结果。可是事情又不是那么严重,因为ip只是依照本地的mtu进行分段,而tcp是端到端的,它可以使用诸如mss以及mtu发现之类的机制配合滑动窗口机制最大限度减少ip分段,因此layer3+4策略,很OK!
miimon和arp: 使用miimon仅能检测链路层的状态,也就是链路层的端到端连接(即交换机某个口和与之直连的本地网卡口),然而交换机的上行口如果down掉了还是无法检测到,因此必然需要网络层的状态检测,最简单也是最直接的方式就是arp了,可以直接arp网关,如果定时器到期网关还没有回复arp reply,则认为链路不通了。
绑定的网口(bonded)有多种工作模式:
目前网卡绑定mode共有七种(0~6)bond0、bond1、bond2、bond3、bond4、bond5、bond6
常用的有三种:
mode=0:负载均衡模式,有自动备援,两条线路同时提供数据传输,但需要”Switch”支援及设定。
mode=1:自动备援模式,只有一条线在使用,若主线路断线,备线路将会自动备援。
mode=6:负载均衡模式,有自动备援,两条线路同时提供数据传输,不必”Switch”支援及设定。
七种bond模式说明:
第一种模式:mod=0 ,即:(balance-rr)Round-robin policy(平衡抡循环策略)
特点:传输数据包顺序是依次传输(即:第1个包走eth0,下一个包就走eth1….一直循环下去,直到最后一个传输完毕),此模式提供负载平衡和容错能力;但是我们知道如果一个连接或者会话的数据包从不同的接口发出的话,中途再经过不同的链路,在客户端很有可能会出现数据包无序到达的问题,而无序到达的数据包需要重新要求被发送,这样网络的吞吐量就会下降
需要说明的是如果想做成mode 0的负载均衡,仅仅设置这里optionsbond0 miimon=100 mode=0是不够的,与网卡相连的交换机必须做特殊配置(这两个端口应该采取聚合方式),因为做bonding的这两块网卡是使用同一个MAC地址.从原理分析一下(bond运行在mode0下):
mode 0下bond所绑定的网卡的IP都被修改成相同的mac地址,如果这些网卡都被接在同一个交换机,那么交换机的arp表里这个mac地址对应的端口就有多个,那么交换机接受到发往这个mac地址的包应该往哪个端口转发呢?正常情况下mac地址是全球唯一的,一个mac地址对应多个端口肯定使交换机迷惑了。
所以 mode0下的bond如果连接到交换机,交换机这几个端口应该采取聚合方式(cisco称为 ethernet channel,foundry称为portgroup),因为交换机做了聚合后,聚合下的几个端口也被捆绑成一个mac地址.我们的解决办法是,两个网卡接入不同的交换机即可。
第二种模式:mod=1,即: (active-backup)Active-backup policy(主-备份策略)
特点:只有一个设备处于活动状态,当一个宕掉另一个马上由备份转换为主设备。mac地址是外部可见得,从外面看来,bond的MAC地址是唯一的,且切换后,MAC地址会更改为备网卡的MAC地址,以避免switch(交换机)发生混乱。此模式只提供了容错能力;由此可见此算法的优点是可以提供高网络连接的可用性,但是它的资源利用率较低,只有一个接口处于工作状态,在有 N 个网络接口的情况下,资源利用率为1/N
第三种模式:mod=2,即:(balance-xor)XOR policy(平衡策略)
特点:基于指定的传输HASH策略传输数据包。缺省的策略是:(源MAC地址 XOR 目标MAC地址)% slave数量。其他的传输策略可以通过xmit_hash_policy选项指定,此模式提供负载平衡和容错能力
第四种模式:mod=3,即:broadcast(广播策略)
特点:在每个slave接口上传输每个数据包,此模式提供了容错能力
第五种模式:mod=4,即:(802.3ad)IEEE 802.3ad Dynamic link aggregation(IEEE802.3ad 动态链接聚合)
特点:创建一个聚合组,它们共享同样的速率和双工设定。根据802.3ad规范将多个slave工作在同一个激活的聚合体下。外出流量的slave选举是基于传输hash策略,该策略可以通过xmit_hash_policy选项从缺省的XOR策略改变到其他策略。需要注意的是,并不是所有的传输策略都是802.3ad适应的,尤其考虑到在802.3ad标准43.2.4章节提及的包乱序问题。不同的实现可能会有不同的适应性。
必要条件:
条件1:ethtool支持获取每个slave的速率和双工设定
条件2:switch(交换机)支持IEEE802.3ad Dynamic link aggregation
条件3:大多数switch(交换机)需要经过特定配置才能支持802.3ad模式
第六种模式:mod=5,即:(balance-tlb)Adaptive transmit load balancing(适配器传输负载均衡)
特点:不需要任何特别的switch(交换机)支持的通道bonding。在每个slave上根据当前的负载(根据速度计算)分配外出流量。如果正在接受数据的slave出故障了,另一个slave接管失败的slave的MAC地址。
必要条件:
ethtool支持获取每个slave的速率
第七种模式:mod=6,即:(balance-alb)Adaptive load balancing(适配器适应性负载均衡)
特点:该模式包含了balance-tlb模式,同时加上针对IPV4流量的接收负载均衡(receiveload balance, rlb),而且不需要任何switch(交换机)的支持。接收负载均衡是通过ARP协商实现的。bonding驱动截获本机发送的ARP应答,并把源硬件地址改写为bond中某个slave的唯一硬件地址,从而使得不同的对端使用不同的硬件地址进行通信。
来自服务器端的接收流量也会被均衡。当本机发送ARP请求时,bonding驱动把对端的IP信息从ARP包中复制并保存下来。当ARP应答从对端到达时,bonding驱动把它的硬件地址提取出来,并发起一个ARP应答给bond中的某个slave。
使用ARP协商进行负载均衡的一个问题是:每次广播 ARP请求时都会使用bond的硬件地址,因此对端学习到这个硬件地址后,接收流量将会全部流向当前的slave。这个问题可以通过给所有的对端发送更新(ARP应答)来解决,应答中包含他们独一无二的硬件地址,从而导致流量重新分布。当新的slave加入到bond中时,或者某个未激活的slave重新 激活时,接收流量也要重新分布。
接收的负载被顺序地分布(roundrobin)在bond中最高速的slave上当某个链路被重新接上,或者一个新的slave加入到bond中,接收流量在所有当前激活的slave中全部重新分配,通过使用指定的MAC地址给每个 client发起ARP应答。下面介绍的updelay参数必须被设置为某个大于等于switch(交换机)转发延时的值,从而保证发往对端的ARP应答 不会被switch(交换机)阻截。
必要条件:
条件1:ethtool支持获取每个slave的速率;
条件2:底层驱动支持设置某个设备的硬件地址,从而使得总是有个slave(curr_active_slave)使用bond的硬件地址,同时保证每个 bond 中的slave都有一个唯一的硬件地址。如果curr_active_slave出故障,它的硬件地址将会被新选出来的 curr_active_slave接管其实mod=6与mod=0的区别:mod=6,先把eth0流量占满,再占eth1,….ethX;而mod=0的话,会发现2个口的流量都很稳定,基本一样的带宽。而mod=6,会发现第一个口流量很高,第2个口只占了小部分流量
mode6模式下无需配置交换机,因为做bonding的这两块网卡是使用不同的MAC地址。
安装配置bond:
1.创建bond网卡文件
在/etc/sysconfig/network-scripts/ 目录下创建ifcfg-bond0
vi /etc/sysconfig/network-scripts/ifcfg-bond0
或者复制物理网卡也行:
cp /etc/sysconfig/network-scripts/ifcfg-eth0 /etc/sysconfig/network-scripts/ifcfg-bond0
2.配置要绑定的网卡
编写bond0 eth1 eth2
使用命令:vi /etc/sysconfig/network-scripts/ifcfg-bond0(ifcfg-bond0这是网卡的名字,想要编写其它网卡修改名字即可)
最后编写后的结果如下:
#cat ifcfg-bond0
DEVICE=bond0
ONBOOT=yes
IPADDR=10.128.1.11
NETMASK=255.255.255.0
GATEWAY=10.128.1.11
USERCTL=no #是否允许非root用户控制该设备
这里要绑定的两块网卡配置是一样的
#cat ifcfg-eth0
DEVICE=eth0
ONBOOT=yes
MASTER=bond0
bootproto=none
#cat ifcfg-eth1
DEVICE=eth1
ONBOOT=yes
MASTER=bond0
bootproto=none
3.修改modprobe.conf(可能不存在,创建即可)
vi /etc/modprobe.d/modprobe.conf
添加:
alias bond0 bonding
options hond miimon=100 mode=1
1).miimon是用来进行链路监测的。 比如:miimon=100,那么系统每100ms监测一次路连接状态,如果有一条线路不通就转入另一条线路;如果交换机出去的链路出问题而本身没有问题,那么bonding认为链路没有问题而继续使用。
2).mode=1 表示使用主备模式,0表示负载均衡
4.设置方便开机启动时,自动载入配置
为了让网卡绑定在每次启动后都能立即生效,我们通常会设置 rc.local.所以我们还应检查一下这个文件。
# vim /etc/rc.d/rc.local
ifenslave bond0 eth0 eth1
5.检测、验证配置
首先执行命令装载bonding模块:modprobe bonding
重启网络服务,并确认bond0正确启动:service network restart
确认设备已经正确加载:less /proc/net/bonding/bond0
列出所有网口:ifconfig
自动生成bond0的脚本:
(如果是centos6.5,需要将eth0和eth1换成em1和em2,默认是负载均衡模式):
cat /var/www/html/bond0.sh
#!/bin/bash
#******************************************************
#this is for creating bond0 with eth0 and eth1.
#every time you need configure the ip and gateway
#******************************************************
NIC_ROOT=”/etc/sysconfig/network-scripts/”
IP=`ifconfig -a|awk ‘/(cast)/ {print $2}’|cut -d’:’ -f2`
#configure eth0
cat >$NIC_ROOT/ifcfg-eth0 <<EOF
DEVICE=eth0
ONBOOT=yes
SLAVE=yes
MASTER=bond0
BOOTPROTO=none
USERCTL=no
EOF
#configure eth1
cat >$NIC_ROOT/ifcfg-eth1 <<EOF
DEVICE=eth1
ONBOOT=yes
SLAVE=yes
MASTER=bond0
BOOTPROTO=none
USERCTL=no
EOF
#configure bond0
cat >$NIC_ROOT/ifcfg-bond0 <<EOF
DEVICE=bond0
ONBOOT=yes
BOOTPROTO=none
IPADDR=$IP
NETMASK=255.255.255.0
BONDING_OPTS=”mode=0 miimon=50 fail_over_mac=0″
USERCTL=no
EOF
#modprobe bonding module
echo “alias bond0 bonding” >> /etc/modprobe.d/bonding.conf
#network restart
service network restart >/dev/null 2>&1
#testing
UP_COUNT=`grep -c “MII Status: up” /proc/net/bonding/bond0`
BOND_MODE=`awk ‘/Bonding Mode/{print $3,$4}’ /proc/net/bonding/bond0`
DUPLEX=`grep -c “Duplex: full” /proc/net/bonding/bond0`
if [[ $UP_COUNT -eq 3 ]] && [[ $BOND_MODE = “load balancing” ]] && [[ $DUPLEX = 2 ]];then
echo -e “\033[32m create bond0 sunccessful\033[0m”
ip addr show bond0 | awk ‘/inet /{print “ipaddr:”,$2}’
else
echo -e “\033[31m create bond0 failure…\033[0m”
cat /proc/net/bonding/bond0
exit 1
fi
————————————————————————–