今年(2009年)1月,OpenSolaris的Clearview项目的一个网络特性--IPMP在Solaris Nevada build 107中发布了。Solaris以前就支持IPMP,然而这次发布的IPMP使大家可以在Solaris上有更便捷和更清晰的网络配置体验。现在,大家可以在OpenSolaris 0906这个版本上使用这种新的配置方法。这篇文章会对Solaris IPMP中的基本概念和配置IPMP的新方法进行介绍。
这篇文章参考了我的同事Meem 的Clearview/IPMP设计文档 ,如果大家对IPMP或者Clearview项目有什么疑问,请访问我们在opensolaris.org上的项目主页 。
IPMP(IP Multipathing)是一种在业界应用广泛的IP层多路传输技术。IPMP本身将基于IP层通信的应用程序和其底层网络接口的状态变化和硬件变化分隔开来,比如我们把两个网络接口分配给一个IPMP组,那么如果你弄坏或移除其中任意一个网络接口都不会对使用这个IPMP组的应用程序的通信产生影响,因为IPMP底层网络接口的状态对使用IPMP通信的上层应用来说的透明的。而且,如果IPMP组中有多个网络接口,通过这个IPMP组通信的应用可以将流入/流出网络流平衡(而不是平均)地分配给它底层的网络接口,从而使网络应用程序获得比一个网络接口大的多的实际网络流量,这从另一个方面提高了网络利用率。
IPMP作为一种网络技术得以广泛应用是有其理由的,我总结了下面三条:
现在,让我们看看如何配置IPMP接口。在本文中我用到了host_a和host_b两台机器,其中host_a是我用来建立IPMP接口的机器,而在host_b上我会配置IPMP探测目标(probe target),那么什么是探测目标?我们现在先留着这个问题,我在后面会讲到,且看下文。
通常企业服务器会采用active-active的方式来配置IPMP。Active-active的意思就是IPMP组里的所有网络接口都处在被激活而且是工作的状态,这样能大大增强IPMP接口的负载和互联能力。这里我要区分一下“IPMP组”和“IPMP接口”这两个概念,一个“IPMP组”是指我们通常所说的经过配置的一个IPMP单位,它在OpenSolaris中的概念包括IPMP地址和其底层接口等一个IPMP单位所包含的所有东西,而一个“IPMP接口”是网络应用使用IPMP组的一个网络层对象,网络应用可以通过“IPMP接口”像使用其他的网络层接口一样使用IPMP组,“IPMP接口”隐藏了IPMP组的细节。
现在我们来看怎样配置IPMP,下面的命令创建了一个IPMP接口:
host_a # ifconfig ipmp0 ipmp group a
这是一种通过ifconfig(1M)显式创建IPMP的方法。其中"ipmp0"是IPMP接口的名字,而“a"是IPMP组的名字。下一步,我会向这个IPMP组添加两个底层网络接口。在这之前,我们要看看host_a上哪些网络接口是可用的:
host_a # dladm show-link
LINK CLASS MTU STATE OVER
bge2 phys 1500 unknown --
bge0 phys 1500 up --
bge1 phys 1500 unknown --
bge3 phys 1500 unknown --
我们可用使用很多类型的网络接口(即Solaris网络层接口对象)。比如,普通的物理网络接口,vlan网络接口以及用别名命名的网络接口等等。然而我们在创建IPMP时需要注意的最重要的一点是,所有分配给一个IPMP组的网络接口必须在同一个LAN中或连在同一个交换机上。现在,所有host_a上的bge网络接口和host_b上的探测目标网络接口都联在同一个交换机上了,我把两个物理网络接口bge1和bge2放到名字为a的IPMP组中,这样bge1和bge2就成为IPMP组的两个底层接口(underlying interface):
host_a # ifconfig bge1 plumb group a
host_a # ifconfig bge2 plumb group a
现在可以用“ipmpstat -g”来验证ipmp0的状态了:
host_a # ipmpstat -g
GROUP GROUPNAME STATE FDT INTERFACES
ipmp0 a failed -- [bge2 bge1]
ipmpstat(1M)是Clearview项目新引入的管理工具,它是用来获得IPMP状态信息最丰富而且是最主要的工具。ipmpstat的"-g"选项显示了系统上存在的每一个IPMP组的信息。我们可以看到,现在ipmp0这个组被标志成"failed",这是因为ipmp0这个IPMP组没有处于工作(active并且up)状态的数据地址(data address),数据地址又是什么地址呢?且不管它,看下文。
现在,用ifconfig(1M)向新创建的IPMP组中加入两个数据地址:
host_a # ifconfig ipmp0 192.168.30.100/24 up
host_a # ifconfig ipmp0 addif 192.168.30.101/24 up
Created new logical interface ipmp0:1
然后激活ipmp0的两个底层网络接口bge1和bge2,这样,两个底层网络接口才会接管这两个数据地址。我们可以使用“ipmpstat -a”(或者使用“ipmpstat -an”来避免主机名解析)来验证这两个新添加的两个数据地址:
host_a # ifconfig bge1 up
host_a # ifconfig bge2 up
host_a # ipmpstat -a
ADDRESS STATE GROUP INBOUND OUTBOUND
192.168.30.101 up ipmp0 bge2 bge2 bge1
192.168.30.100 up ipmp0 bge1 bge2 bge1
“ipmpstat -a”显示了系统中数据地址的状态。我们可以注意到网络流出负载(见 OUTBOUND域 )被分担给了bge1和bge2。现在,我要详细地讲解数据地址的概念了。
数据地址是可以被网络应用使用的进行数据通信的IP地址,如上面例子中的 192.168.30.101和 192.168.30.100 。每个数据地址都是某个IPMP组的一部分,只要IPMP组中总有一个网络接口在工作,不管IPMP组中接口的状态如何变化,那么网络应用就可以不间断地使用这个IPMP组中“所有的”数据地址正常工作。比如,我们使用数据地址进行telnet远程访问,在数据地址所属IPMP组中,不管某些网络接口连接的网线是否被拔掉,网卡是否坏掉,或者坏了又好,好了又坏,只要至少有一个网络接口在工作,那么telnet连接就不会有影响。
在Solaris以前的IPMP实现架构中,数据地址是附着在IPMP组底层的网络接口上的,而IPMP接口则是新的IPMP实现引入的概念, 数据地址在新的IPMP实现中附着在IPMP接口上。
现在,通过以上的配置,我们可以使用数据地址进行网络通信了。但是为了拥有更完善的IPMP配置,比如状态探测和出错检查机制,我们需要配置测试地址(test address)。下面我要详细介绍测试地址的概念。
测试地址是探测包(probe)的源IP地址或目的IP地址,IPMP的探测包是in.mpathd这个系统后台进程发出的ICMP包,它用来探测IPMP远程端与IPMP底层接口的数据发送、接收路径和连接状态。为了探测IPMP的连接状态,每一个探测包将附着在底层接口上的测试地址作为ICMP源地址,将探测目标(probe target)的地址作为ICMP包目的地址,探测目标收到探测包后会对该探测包应答,每个测试包都有一个ID,而探测包应答中也包含这个ID,我们可以通过“ipmpstat -p”来查看当前系统发送、接收的探测包和探测应答。那么,为什么要有探测包和探测目标呢?其实在实际应用中,探测目标主机往往是一台路由器,IPMP接口通过向探测目标发送探测包来检查它是否可以通过该路由器访问外网。
还有一点需要注意的是,测试地址不能用于应用程序的数据通信,它只能用于IPMP的连通性探测。
现在知道本文前面所说的host_b的作用了吧。现在就要在host_b上配置探测目标了。这里还需要提到刚才讲到的一点:探测目标网络接口必须连接在与IPMP接口相同的子网上(比如,连在同一个交换机上)。
host_b # ifconfig e1000g1 plumb 192.168.30.199/24 up
host_b # ifconfig e1000g1
e1000g1: flags=201000843<UP,BROADCAST,RUNNING,MULTICAST,IPv4,CoS> mtu 1500 index 6
inet 192.168.30.199 netmask ffffff00 broadcast 192.168.30.255
ether 0:14:4f:82:59:61
让我们回到测试地址的讨论。测试地址必须和一个IPMP底层接口相关联,这是和数据地址的区别之一。而且,测试地址被标记为“NOFAILOVER”,这样的话它们即使在接口遇到错误或修复错误的时候也不会发生测试地址转移到其他网络接口上的情况。而且测试地址被自动标记为“DEPRECATED”,这样系统就不会把这样的IP地址选出来进行数据通信,因为这些地址本身不是用来传输数据的,而是用来探测IPMP的状态的。为了为每个底层接口分配测试地址,我们可以执行以下命令:
host_a # ifconfig bge1 -failover
host_a # ifconfig bge2 -failover
host_a # ifconfig bge1 192.168.30.200/24
host_a # ifconfig bge2 192.168.30.201/24
在上面的命令行中,我先用“-failover”选项配置bge1和bge2是为了阻止测试地址像数据地址那样自动地转移到IPMP接口上,而且测试地址必须被分配到IPMP底层接口而不是IPMP接口本身。现在我们已经配置好了测试地址,那么就可以用“ipmpstat -t”来查看系统中的测试地址了(192.168.30.201和 192.168.30.200是两个测试地址):
host_a # ipmpstat -t
INTERFACE MODE TESTADDR TARGETS
bge2 multicast 192.168.30.201 192.168.30.199
bge1 multicast 192.168.30.200 192.168.30.199
每当看到failover和failback这两个词,我就感叹英语单词对工程技术精准而简明的概括能力,同时我在想如何用中文来描述这两个词。在网络工程领域,failover和failback经常被用到。而在本文所讲述的IPMP技术中,failover和failback就是小标题中小括号里的意思,下面是我对这两个操作的详细解释:
failover:当IPMP的底层接口因出现问题而不能工作时,在(bound to)这些接口上的数据地址会迁移到同一个IPMP组中能正常工作的底层接口上的操作。
failback:当 IPMP的底层接口修复了出现的问题又恢复正常工作状态后,迁移到别的接口上的数据地址回迁到原来它所在网络接口上的操作。
在OpenSolaris中,无论是Clearview项目中的实现还是Solaris以前版本中的实现,failover和failback操作是由内核自动完成的。
回到前面我们配置的IPMP组,现在我们已经把一个active-active的IPMP组配置好了。这种IPMP配置是一种典型而可靠的网络通信手段。在至少一个网络接口能够工作的情况下,基于IPMP数据地址的通信都可以正常进行。当我们停用一个IPMP组中的底层接口时,IPMP会自动进行failover操作,一旦这个停用的接口重新被启用时,IPMP会自动进行failback操作。我在下面会用 “ifconfig <interface> down/up”来展示“failover”和“failback”。下面,我会用到本文前面配置的IPMP组,并将ipmp0的bge1停用,看看会有什么事情发生:
host_a # ifconfig bge1 down
host_a # ipmpstat -g
GROUP GROUPNAME STATE FDT INTERFACES
ipmp0 a degraded 10.00s bge2 [bge1]
现在,我们可以看到ipmp0被标记为“degraded”,因为其中之一的bge1接口被down掉了(在INTERFACES域中用中括号括起来)。现在,只有bge2正常工作,我们看看数据地址的情况,ipmp0所有的数据地址这时候应该已经failover到bge2上了:
host_a # ipmpstat -an
ADDRESS STATE GROUP INBOUND OUTBOUND
192.168.30.101 up ipmp0 bge2 bge2
192.168.30.100 up ipmp0 bge2 bge2
好,让我展示一下“failback”,“failback”发生在当IPMP的底层接口重新被启用时:
host_a # ifconfig bge1 up
host_a # ipmpstat -an
ADDRESS STATE GROUP INBOUND OUTBOUND
192.168.30.101 up ipmp0 bge2 bge2 bge1
192.168.30.100 up ipmp0 bge1 bge2 bge1
很明显,ipmp0数据地址的状态又恢复原样了。
现在看看如何配置一个active-standby方式的IPMP组。
Active-standby方式的IPMP让用户至少有一个备份用的底层接口作为网络连接的可靠性保障。当某些处于工作状态的底层接口出错或被停用时,备份的底层接口可以被自动激活(standby并且active),并接管原来down掉的底层网络接口上的数据地址,也就是failover。同样,一旦被停用的接口恢复使用时,IPMP也会启动failback操作,此时,备用的底层接口又会回到备用(standby并且inactive)的状态。如果你把数据地址作为网络应用的通信地址使用,failover和failback的过程同样是透明的。备份接口的状态切换不会影响到网络应用的效率。现在,我会基于本文前面配置的IPMP组配置一个active-standby方式的IPMP组。既然我们在host_a上已经将bge1和bge2加入到ipmp0中,我们现在将bge2设置为待命(standby)状态:
host_a # ifconfig bge2 standby
host_a # ipmpstat -i
INTERFACE ACTIVE GROUP FLAGS LINK PROBE STATE
bge2 no ipmp0 is----- up ok ok
bge1 yes ipmp0 --mb--- up ok ok
host_a # ipmpstat -an
ADDRESS STATE GROUP INBOUND OUTBOUND
192.168.30.101 up ipmp0 bge1 bge1
192.168.30.100 up ipmp0 bge1 bge1
在上面的演示中,ipmpstat的“-i”选项表示显示IPMP底层接口的信息。我们可以看到bge2已经被标记为i(inactive)和s(standby),并且所有的数据地址都被迁移到bge1。现在让我们将bge1标记为offline看会发生什么:
host_a # if_mpadm -d bge1
host_a # ipmpstat -i
INTERFACE ACTIVE GROUP FLAGS LINK PROBE STATE
bge2 yes ipmp0 -smb--- up ok ok
bge1 no ipmp0 -----d- up disabled offline
host_a # ipmpstat -an
ADDRESS STATE GROUP INBOUND OUTBOUND
192.168.30.101 up ipmp0 bge2 bge2
192.168.30.100 up ipmp0 bge2 bge2
在这里if_mpadm(1M)是用来管理IPMP底层接口的命令。我们可以看到bge2上的i(inactive)标志已经没有了,而且所有的数据地址都已迁移到bge2。而在这个过程中,使用两个数据地址( 192.168.30.101和 192.168.30.100 )通信的应用程序不会受到影响。
本文中所展示的IPMP配置方式到此为止了,最后要删除我们在本文中创建的IPMP接口。删除IPMP接口时,要先删除分配给IPMP的底层接口,再删除IPMP接口:
host_a # ifconfig bge1 unplumb
host_a # ifconfig bge2 unplumb
host_a # ifconfig ipmp0 unplumb
host_a # ipmpstat -g
请记住在IPMP的底层接口被删除之前是不能删掉IPMP接口的。
(完)
欢迎查看本文的英文版