zoukankan      html  css  js  c++  java
  • Bonding 配置全套

    注意

    本教程针对于 Centos 8  系统, ARM 机器架构, HuaWei KunPeng 920, 
    其他系统 以及 X86  机器可以参考!! 原理都是通的....
    

    配置 Bonding

    Bonding 技术

        bonding(绑定)是一种linux系统下的网卡绑定技术,可以把服务器上n个物理网卡在系统内部抽象(绑定)成一个逻辑上的网卡,能够提升网络吞吐量、实现网络冗余、负载等功能,有很多优势。
    
        bonding技术是linux系统内核层面实现的,它是一个内核模块(驱动)。使用它需要系统有这个模块, 我们可以modinfo命令查看下这个模块的信息, 一般来说都支持。
    

    Bonding 的 7 中模式

        bonding技术提供了七种工作模式,在使用的时候需要指定一种,每种有各自的优缺点.
    Bonding的模式一共有7种:
    defineBOND_MODE_ROUNDROBIN       0   (balance-rr)   模式网卡的负载均衡模式, 需要配置交换机做端口聚合
    defineBOND_MODE_ACTIVEBACKUP     1   (active-backup)模式网卡的容错模式
    defineBOND_MODE_XOR              2   (balance-xor)  模式需要交换机支持
    defineBOND_MODE_BROADCAST        3   (broadcast)    模式
    defineBOND_MODE_8023AD           4   (802.3ad)      动态链路聚合模式需要配置交换机
    defineBOND_MODE_TLB              5   (balance-tlb)自适应传输负载均衡模式
    defineBOND_MODE_ALB              6   (balance-alb)网卡虚拟化方式
        bonding模块的所有工作模式可以分为两类:多主型工作模式和主备型工作模式,(balance-rr) 和 (broadcast) 属于多主型工作模式, 而 (active-backup) 属于主备型工作模式。(balance-xor)自适应传输负载均衡模式(balance-tlb)和自适应负载均衡模式(balance-alb)也属于多主型工作模式,IEEE (802.3ad)动态链路聚合模式。
    

    详细介绍这7种模式

    balance-rr (mode=0)
    轮转(Round-robin)策略:从头到尾顺序的在每一个slave接口上面发送数据包。本模式提供负载均衡和容错的能力。


    active-backup(mode=1)
    活动-备份(主备)策略:在绑定中,只有一个slave被激活。当且仅当活动的slave接口失败时才会激活其他slave。为了避免交换机发生混乱此时绑定的MAC地址只有一个外部端口上可见。在bongding的2.6.2及其以后的版本中,主备模式下发生一次故障迁移时,bonding将在新激活的slave上会送一个或者多个gratuitous ARP。bonding的主salve接口上以及配置在接口上的所有VLAN接口都会发送gratuitous ARP,只要这些接口上配置了至少一个IP地址。VLAN接口上发送的的gratuitous ARP将会附上适当的VLAN id。本模式提供容错能力,primary option,documented below会影响本模式的行为。


    balance-xor(mode=2)
    XOR策略:基于所选择的传送hash策略。
    本模式提供负载均衡和容错的能力。


    broadcast(mode=3)
    广播策略:在所有的slave接口上传送所有的报文。本模式提供容错能力。


    802.3ad(mode=4)
    IEEE 802.3ad 动态链路聚合。创建共享相同的速率和双工模式的聚合组。能根据802.3ad规范利用所有的slave来建立聚合链路。Salve的出站选择取决于传输的hash策略,默认策略是简单的XOR策略,而hash策略则可以通xmit_hash_policy选项加以改变。需要注意的是:不是所有的传输策略都与802.3ad兼容,尤其是802.3ad标准的43.2.4章节中关于 packet mis-ordering要求的地方。不同个体的实现往往出现很大的不兼容。
    先决条件:
    1. 每个slave的基本驱动支持Ethtool获取速率和双工状态。
    2. 交换机支持IEEE 802.3ad动态链路聚合。大多数的交换机都需要使用某种配置方式来启用802.3ad模式。


    balance-tlb(mode=5)
    自适应传输负载均衡:信道绑定不需要特殊的交换机支持。出口流量的分布取决于当前每个slave的负载(计算相对速度)。进口流量从当前的slave的接收。如果接收salve出错,其他的slave接管失败的slave的MAC地址继续接收。
    先决条件:
    每个slave的基本驱动支持Ethtool获取速率状态。


    balance-alb(mode=6)
    自适应负载均衡:包括balance-tlb(模式5)以及用于IPV4流量的接收负载均衡,并且不需要特殊的交换机支持。接收负载均衡通过ARP协商实现。bonding的驱动拦截本机发出的ARP Replies(ARP回应报文),并且用bond的某一个slave的硬件地址改写ARP报文的源地址,使得本服务器对不同的设备使用不同的硬件地址。本服务器建立的连接的接收流量也是负载均衡的。当本机发送ARP Request时,bonding驱动通过ARP报文复制并保存节点的IP信息。当从其他节点接收到ARP Reply,bonding驱动获取节点的硬件地址并且会回应一个包含绑定好的slave的硬件地址的ARP Reply给发送的节点。用ARP协商的负载均衡的有一个问题是每次用bond的硬件地址广播ARP报文,那么其他节点发送的数据全部集中在一个slave上,处理ARP更新给其他所有节点的时候,每个节点会重新学习硬件地址,导致流量重新分配。当新加入一个slave或者一个非激活的slave重新激活的时候也会导致接收流量重新分配。接收流量负载是串行(轮转)的分配在bond的一组速率最高的slave上。
    当一个链路重连或者一个新的slave加入的时候,bond会重新初始化ARP Replies给所有的客户端。updelay参数的值必须等于或者大于交换机的forwarding delay,以免ARP Replies被交换机阻塞。
    先决条件:

      	1. 每个slave的基本驱动支持Ethtool获取速率状态。
        	2. 基本驱动支持当设备打开时重新设置硬件地址。也要求每一个slave具有唯一的硬件地址。如果curr_active_slave失败,它的硬件地址被新选上的curr_active_slave硬件地址来替换。
    

    配置步骤

    准备 工作

    # 查看 系统内核 是否支持bonding
    cat /boot/config-`uname -r` | grep -i bonding  
    	# 若 CONFIG_BONDING=m , 则表示支持 
    # 加载bonding 内核模块
    modprobe bonding 
    # 查看系统 是否 加载 bonding 模块 
    lsmod | grep bonding 
    

    以 创建 bondind 模式 1 为例, 其他 模式同理, bonding 名随意,

    操作步骤

    # 1. 创建 mode = 1, 名称为 bond1 的绑定
    nmcli con add type bond con-name bond1 ifname bond1 mode active-backup  # 模式以 具体的模式为准
    # 2. 将 enp131s0f0 增加到bond1
    nmcli connection add type bond-slave ifname enp131s0f0 master bond1
    # 3. 将 enp131s0f1 增加到bond1
    nmcli connection add type bond-slave ifname enp131s0f1 master bond1
    # 4. 启动从属接口 enp131s0f0
    nmcli connection up bond-slave-enp131s0f0       # 具体接口名 以第 2 步骤命令执行返回结果中的具体接口名为准
    # 5. 启动从属接口 enp131s0f1
    nmcli connection up bond-slave-enp131s0f1       # 具体接口名 以第 3 步骤命令执行返回结果中的具体接口名为准
    # 6. 启动绑定
    nmcli connection up  bond1                      # bonding 名 以 第 1 步骤命令 所创建的 bonding 名 为准
    

    其他

    # 查看系统 bonding  状态文件, 在 /proc/net/bonding/ 目录下每个 bonding 存在一个状态文件。 
    # 且 该 状态文件 是会 根据 bonding 状态 自动 变化的 
    cat  /proc/net/bonding/bond1
    # 查看系统 bonding  配置文件: 文件名规则与 网卡设备连接名 相同。
    cat  /etc/sysconfig/network-scripts/ifcfg-bond1
    # 系统启动时, 自动加载的 bond 配置文件
    /etc/modprobe.d/bonding.conf
    # 添加 自配置 命令
     	# 在 /etc/rc.d/rc.local  文件中添加如下:
    ifenslave bond0 eth0 eth1     # bonding 名 和 接口名 以 实际的名称为准  
    
    # bonding mode=4 可选添加的 配置参数
    BONDING_OPTS="mode=802.3ad miimon=100 lacp_rate=fast arp_validate=0"
    
    BONDING_OPTS="mode=4 miimon=100 xmit_hash_policy=layer3+4"  
    

    自动化 Bonding 创建 Python 脚本

    注意

    1. 系统中 需存在 nmcli 命令
    2. 系统中 需安装 python, 且为 版本 3 
    

    auto_bonding_v1.py

    #!/usr/bin/python 
    #coding=utf-8
    
    import subprocess
    import shlex
    import os
    import time
    
    __author__ = "shiwei"
    __time__ = "2020/12/31"
    __version__ = "v1"
    
    
    
    mode_li = ["balance-rr", "active-backup", "balance-xor", "broadcast", "802.3ad", "balance-tlb", "balance-alb"]
    mode_name = None        # 将要创建的 bonding 名字
    mode_num = None         # 将要创建的 bonding 级别
    mode_int_li = []        # 该 bonding 所要绑定的 接口列表
    exists_son_int_li = []  # ifconfig 命令下 已存在的 非 bongding  接口列表
    exists_ifcfg_li = []    # /etc/sysconfig/network-scripts/ 目录下已存在的 bond 子接口 列表 
    bonding_son_int_li = [] # 该 bonding  从属子接口名字列表
    
    
    def execute_cmd(cmd_str):
    	""" 执行 bash 命令, 通过 subprocess.Popen 方法
    	"""
    	sh_cmd = shlex.split(cmd_str)
    	print("")
    	# 不支持管道符
    	Popen_obj = subprocess.Popen(sh_cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE, shell=True)
    	# s.stdin.write(b"import os
    ")
    	# s.stdin.write(b"print(os.environ)")
    	# s.stdin.close()
    	res = Popen_obj.stdout.read().decode("UTF-8")
    	Popen_obj.stdout.close()
    	# print(res)
    	time.sleep(0.46)  # 休息 0.36 秒,等待系统缓冲
    	return res
    
    
    def execute_cmd_02(cmd_str):
    	""" 执行 bash 命令, 通过 subprocess.run 方法
    	"""
    	ret = subprocess.run(cmd_str, stdout=subprocess.PIPE,shell=True)
    	res = ret.stdout
    	res = str(res, encoding = "UTF-8")
    	#res = res[:-1].split("
    ")
    	# print("结果为:", res)
    	time.sleep(0.46)  # 休息 0.36 秒,等待系统缓冲
    	return res
    	
    def create_mode_name():
    	""" 创建 Bonding 模式名
    	"""
    	while 1:
    		try:
    			user_mode_str = input("请输入所要配置 Bonding 模式【0-6】>").strip()
    			user_mode_num = int(user_mode_str)
    			if not user_mode_num in range(0, 7):
    				raise IndexError("没有这个模式啦....")
    			# assert isinstance(user_mode_num, int), "类型错误!"
    			break
    		except Exception as e:
    			print(e, "
     请重新输入【0-6】>")
    	cur_name = "bond" + user_mode_str
    	# 获取当前系统所有已创建的 Bond 模式名
    	cmd_str = r"""ls /proc/net/bonding/ | xargs -n  1"""
    	bonding_name = execute_cmd_02(cmd_str)
    	regis_li = bonding_name[:-1].split("
    ")  # 已创建 bonding 名列表
    	while 1:
    		if cur_name in regis_li:
    			cur_name += "v1"
    		else:
    			break
    	global mode_num, mode_name
    	mode_num = user_mode_num
    	mode_name = cur_name
    
    def print_interface(cur_int_li):
    	""" 打印接口列表信息
    	"""
    	print(f"	 0 > 退出")
    	for index, val in enumerate(cur_int_li, 1):
    		print(f"	 {index} > {val}")
    
    
    def sel_interface():
    	""" 选择该 Bonding 索要绑定的接口
    	"""
    	new_cmd_str=r"""cat /proc/net/dev | grep -v lo | grep -v virbr | sed '3,$p' -n | cut -d: -f1 | xargs  -n 1"""
    	int_li_str = execute_cmd_02(new_cmd_str)
    	# if int_li_str:
    	cur_int_li = int_li_str[:-1].split("
    ")
    	exists_son_int_li = cur_int_li  
    	index_li = []  # 所选择的接口列表
    	#
    	# print("当前系统接口列表如下
    :", cur_int_li)
    	# print_interface(cur_int_li)
    
    	while 1:
    		print("当前系统接口列表如下:")
    		print_interface(cur_int_li)
    		index = input(f"请选择当前 bonding 所要绑定的接口,输入数字【0-{len(cur_int_li)}】>")
    		try:
    			index = int(index)
    			if not index in range(0, len(cur_int_li) + 1):
    				raise IndexError("没有这个接口啦....") 
    			if not index:
    				break
    			else:
    				if index not in index_li:
    					index_li.append(index)
    					mode_int_li.append(exists_son_int_li[index - 1])
    		except Exception as e:
    			print(e, "
     请重新输入【0-{len(cur_int_li)}】>")
    
    
    def get_bond_sub_li(cmd_str):
    	""" 执行添加 从属接口命令, 根据返回返回值获取 bonding 子接口名字
    	"""
    	res = execute_cmd_02(cmd_str)
    	if res:
    		sub_int_name = res[:-1].split('"')[1]
    		bonding_son_int_li.append(sub_int_name)
    	
    	
    def struct_cmd():
    	""" 创建 bonding , 执行命令
    	""" 
    	exists_ifcfg__cmd = r"""find /etc/sysconfig/network-scripts/ -maxdepth 1 -type f  -perm 644 -name 'ifcfg-bond-*' | xargs -i basename {} | awk 'BEGIN{FS="ifcfg-"}{print $2}'"""
    	ifcfg_li = execute_cmd_02(exists_ifcfg__cmd)
    	exists_ifcfg_li = ifcfg_li[:-1].split("
    ")
    	global mode_li, mode_name, mode_num
    	print("已存在的 子接口 为:", exists_ifcfg_li)
    	cmd_bonding_li = []  # 命令列表
    	
    	# 第一步, 创建 bonding 接口
    	first_cmd = "nmcli con add type bond con-name " + mode_name + " ifname " + mode_name + " mode " + mode_li[mode_num]
    	cmd_bonding_li.append(first_cmd)
    	execute_cmd_02(first_cmd)
    	time.sleep(0.5)
    	# 第二步, 添加 子接口
    	# 返回子接口信息示例: "Connection 'bond-slave-enp189s0f2' (325727bb-a6be-451e-83a2-2221916c4eb9) successfully added."
    	for interface in mode_int_li:
    		cmd = r"nmcli connection add type bond-slave ifname " + interface + " master " + mode_name
    		get_bond_sub_li(cmd)
    		cmd_bonding_li.append(cmd)
    	# 第三步, 依次启动从属接口
    	for bond_sub in bonding_son_int_li:
    		cmd = r"nmcli connection up " + bond_sub
    		execute_cmd_02(cmd)
    		cmd_bonding_li.append(cmd)
    	# 第四步, 启动 bonding 接口
    	fourth_cmd = r"nmcli connection up " + mode_name
    	execute_cmd_02(fourth_cmd)
    	cmd_bonding_li.append(fourth_cmd)
    	# 打印 执行命令
    	for index, item in enumerate(cmd_bonding_li, 1):
    		print(f"{index} > , {item}")
    	
    		
    if __name__ == "__main__":
    	create_mode_name()
    	print("bonding 名字为: ",  mode_name)
    	sel_interface()
    	if len(mode_int_li) >= 2:
    		struct_cmd()
    
    

    python 自创 switch 语句

    #!/bin/env python
    #coding=utf-8
    
    
    class switch(object):
        def __init__(self, value):
            self.value = value
            self.fall = False
    
        def __iter__(self):
           
            yield self.match
            raise StopIteration
    
        def match(self, *args):
            
            if self.fall or not args:
                return True
            elif self.value in args: # changed for v1.5, see below
                self.fall = True
                return True
            else:
                return False
    
    
    
    v = 'ten'
    for case in switch(v):
        if case('one'):
            print 1
            break
        if case('two'):
            print 2
            break
        if case('ten'):
            print 10
            break
        if case('eleven'):
            print 11
            break
        if case(): # default, could also just omit condition or 'if True'
            print "something else!"
            # No need to break here, it'll stop anyway
    
    
    c = 'z'
    for case in switch(c):
        if case('a'): pass # only necessary if the rest of the suite is empty
        if case('b'): pass
        # ...
        if case('y'): pass
        if case('z'):
            print "c is lowercase!"
            break
        if case('A'): pass
        # ...
        if case('Z'):
            print "c is uppercase!"
            break
        if case(): # default
            print "I dunno what c was!"
    
    
    import string
    c = 'A'
    for case in switch(c):
        if case(*string.lowercase): # note the * for unpacking as arguments
            print "c is lowercase!"
            break
        if case(*string.uppercase):
            print "c is uppercase!"
            break
        if case('!', '?', '.'): # normal argument passing style also applies
            print "c is a sentence terminator!"
            break
        if case(): # default
            print "I dunno what c was!"
    

    参考文档

    Centos7配置bonding

    centos 链路捆绑(聚合)bonding配置举例

  • 相关阅读:
    进入到已有的docker容器中
    Ubuntu 18.04下指定Sublime Text 3 默认python编译版本
    设计模式之单例模式(c++版)
    clang10在ubuntu18.04下编译ZeroTier,故障解决
    搜狗输入法安装实践
    ubuntu 安装 dingtalk,飞书,google,zoom,时钟等
    js为某个元素添加某个类,并为其他兄弟元素删除此类
    jquery 中attr和css的区别
    unlimited tablespace 权限是否对所有表空间拥有权限测试
    Oracle DG 日常管理操作
  • 原文地址:https://www.cnblogs.com/shiwei1930/p/14255437.html
Copyright © 2011-2022 走看看