环境介绍:
CentOS6.5_x86_64
linux内核2.6.32。
ipvsadm v1.26
所必须的:内核支持,在内核2.6以后,ip_vs code已经被整合进了内核中,自定义编译内核时候选择上ipvs功能即可。如果是更老的内核,需要手动将ip_vs code源码整合进内核源码并编译。
在CentOS6.5默认的内核中ipvs是以模块存在的,如下图:
ipvs内核和各种调度算法模块还有一些特殊功能的模块。这是工作于内核中的功能模块,与ipvsadm是不一样的。可以说ipvs是框架,需要ipvsadm所定义的规则来使它工作起来。
一、命令介绍。
ipvsadm是工作于用户空间的软件,用于给工作于内核空间的ipvs传递规则的。
SYNOPSIS ipvsadm -A|E -t|u|f service-address [-s scheduler] [-p [timeout]] [-M netmask] ipvsadm -D -t|u|f service-address ipvsadm -C ipvsadm -R ipvsadm -S [-n] ipvsadm -a|e -t|u|f service-address -r server-address [-g|i|m] [-w weight] [-x upper] [-y lower] ipvsadm -d -t|u|f service-address -r server-address ipvsadm -L|l [options] ipvsadm -Z [-t|u|f service-address] ipvsadm --set tcp tcpfin udp ipvsadm --start-daemon state [--mcast-interface interface] [--syncid syncid] ipvsadm --stop-daemon state ipvsadm -h #帮助
添加LVS集群服务
ipvsadm -A|E -t|u|f service-address [-s scheduler] [-p [timeout]] [-M netmask]
-A、-E:分别是添加和修改lvs集群服务。集群服务可以添加多条,客户端访问请求区配到了哪条,哪条的集群服务工作。
-t、-u、-f:分别表示三种添加方式, -t:根据TCP协议的,-u:UDP协议的,-f:访火墙标记的。
-s:表示LVS的调度算法。默认wlc的算法。
-p:表示会话持久连接。默认不会持久连接。
-M:用于区配客户端地址的子网掩码,用于持久性连接的粒度。如:255.255.255.0,来访IP分别是123.123.0.1、123.123.0.10,lvs为以为它们是同一个地址,如果开启了持久连接,就会被一同保持在同一台Real Server上。默认是255.255.255.255,这样也是最好的负载方式,一般不用改。
添加Real Server相关的规则。
ipvsadm -a|e -t|u|f service-address -r server-address [-g|i|m] [-w weight] [-x upper] [-y lower]
-a、-e:分别是用来添加和修改各个集群服务所管理的Real Serve规则。
-t、-u、-f:是用来指定各种不同的集群服务的。
-r:指定Real Server的地址。在支持端口映射的工作类型中,可以加上端口。
-g、-i、-m:就是工作类型,-g:DR类型,默认;-i:ipip_tun类型;-m:NAT类型。
-w:权重,默认为1,如果指定为0,lvs将不会把访问请求发给它。lvs不会将访问请求发给权重为0的Real Server.
-x、-y:分别是表示给于此Real Server的连接数上限和下限。默认都是0,表示不设置。
上面这两个分别是用于设置lvs集群服务的规则和各个集群服务所管理的Real Server的规则。可能有点乱,来张图看下。
每个红线下面第一行都是所定义的集群服务,上面定义了三个集群服务。而各个集群的下面都是所管理的Real Server的规则。访问请求区配到了哪个集群服务,哪个集群服务就按调度算法在下面找一个Real Server。
删除指定的集群服务。
ipvsadm -D -t|u|f service-address
删除指定的Real Server。
ipvsadm -d -t|u|f service-address -r server-address
查看规则。
ipvsadm -L|l [options]
-L、-l:是一样的,用来查看状态的。常用的options有:-n,不反解服务名称和主机名称;-c,显示各个连接;--stats,显示统计数据;--rate,显示速率;--exact,显示统计数据的精确值。--timeout连接超时时间。
查看连接也可以这样:cat /proc/net/ip_vs_conn
计数器清零。
ipvsadm -Z [-t|u|f service-address]
清空所有规则。
ipvsadm -C
载入规则。如:ipvsadm -R < /var/ipvs.conf。也可以保用ipvsadm-restore < /var/ipvs.conf
ipvsadm -R
保存规则。如:ipvsadm -S > /var/ipvs.conf。也可以使用ipvsadm-save > /var/ipvs.conf
ipvsadm -S [-n]
设置连接超时时间。
ipvsadm --set tcp tcpfin udp
tcp,指的是TCP连接超时时间(空闭时间);tcpfin,表示在客户端发送fin以后,连接还在hash-table中所存在的时间;udp,记录udp连接,超出时间还未收到下一个udp包(udp超时,udp没有连接状态,只能这样写了),则从hash-tabl中删除连接条目。这些值一般也不用改变。不过为什么有这个还是介绍下吧:
因为lvs是处在客户端和Real Server之间的,它本身可没有连接状态,数据只是在内核中转出去了而已,根本不会建立连接。那么它怎么知道现在客户端发过来的数据是不是与Real Server已经建立连接了呢,就是靠的这个hash table了。就是通过这张表来查看客户端与Real Server的连接状态的。不然的话,tcp三次握手,第一次给转到Real Server A上去了,A返回确认,第三次握手信息结果给转到B上去了,是不是很糟糕。数据传输那就更糟糕了。所以大概意思就是这么来的。
hash表条目:source ip + source port --> dest ip + dest port还有协议和状态。
ipvsadm --start-daemon state [--mcast-interface interface] [--syncid syncid] ipvsadm --stop-daemon state
开启关闭同步守护进程
ipvsadm -h
帮助,参数之类的信息。
概念补充:session
session会话:客户端访问服务器,服务器端会保留客户端的session信息,如你的购物车,或查看商口的记录等等。并且会发给客户端Cookie,用以标识客户端。下次客户端再来访问只要有这个Cookie,服务器就会按上次的session信息来继续提供服务。那么现在客户端在服务器A上查看的商口,还有加入的购物车,付款的时候,LVS给转到服务器B上去了,会是什么情况,你的购物车里的东西没有了。
session绑定:通过会话保持(sh调度算法或是-p会话保持)来实现,但是lvs的会话保持都是网络层的,也就是根据IP地址来计算的,而且万一服务器A挂了,session信息还是会丢失。这样对负载均衡或是用户体验都是有影响的。有工作于应用层的硬件,按不同的cookie信息来绑定不同的Real Server。
session复制:通过把session复制给所有Real Server并时刻保持同步,只能用于小型的集群中,不能用于大型的集群中,要不然同步session信息也是个大工程啦。
session服务器:用单独的服务器,如memcache来统一管理所有Real Server的session信息,优点很明显,缺点也很明显,性能,安全。为了性能和安全session服务器还要再做集群才行。
没有什么是绝对好的,适用才是最好的。
二、实验-NAT模型。
NAT模式不能与netfilter兼容,最好不要同时使用。
实验以上面的图为准:
开启Director的转发功能。
定义Real Server的网关为DIP.
在Director上添加规则。
详细过程如下:
1.开启转发功能。
永久生效:可以在/etc/sysctl.conf文件中修改net.ipv4.ip_forward = 1,并且可以执行sysctl -p来重新加载文件,即时生效。
# Controls IP packet forwarding net.ipv4.ip_forward = 1
本次生效:直接修改/proc/sys/net/ipv4/ip_forward。
[root@director ~]# echo 1 > /proc/sys/net/ipv4/ip_forward [root@director ~]#
2.定义网关为DIP。
永久生效:在/etc/sysconfig/network-scripts/ifcfg-eth*中定义网关。
本次生效:在没有默认路由的情况下,直接添加默认路由。
3.在Director上添加规则。
我们先定义一个看看:
第一行就是定义的集群服务,-s指定调度算法。第二、三行就是添加Real Server了。红框中的表示的是一个集群服务。
第二、三行中的-a添加Real Server,再后面表示某个集群服务中的Real Server,-r表示RS的地址了,-m表示用nat工作方式。很显然多个RS可以指定于不同的工作方式。然后这就完成了。
查看一下:
[root@director ~]# ipvsadm -L -n IP Virtual Server version 1.2.1 (size=4096) #这里的4096是hash表的大小,但是这个表中的表项都会有一个链表,所以实际的大小是不受这个限制的,一般不用修改。 Prot LocalAddress:Port Scheduler Flags -> RemoteAddress:Port Forward Weight ActiveConn InActConn TCP 172.16.5.10:80 rr #集群服务+rr调度算法 -> 192.168.5.11:80 Masq 1 0 0 -> 192.168.5.12:80 Masq 1 0 0
查看下各个连接:
有来源地址,VIP地址,还有目标Real Server地址。还有当前的连接状态。还有各种连接状态的超时时间。不过ESTABLISHED一会儿就没了,http协议是无连接,默认也是不会开启keepAlive,所以在客户端接收完数据以后就会发送fin,状态就变成TIME_WAIT了。
[root@director ~]# ipvsadm -L --timeout Timeout (tcp tcpfin udp): 900 120 300
超时时间分别是:900秒,120秒,300秒。
三、会话持久。
那么上面我们也看到session了,在lvs这里可以用-p来实现会话绑定,这个是工作于算法之上的,如果被会话匹配,直接跳过调度算法,发给会话绑定超时时间内的服务器。
工作方式:会把所有会话连接记录在一张模板中,会话都有超时间,超时以后就会从模板中删除。访问请求如果匹配了其中的会话记录,lvs会把请求发给模板中所记录的相应的Real Server。这里其实我也不清楚这个到底是保存在一个单独的模板中,还是保存在hash表中的。求科普。
来试一下-p选项。
[root@director ~]# ipvsadm -E -t 172.16.5.10:80 -s rr -p 600 #-E修改集群服务。 [root@director ~]# ipvsadm -L -n IP Virtual Server version 1.2.1 (size=4096) Prot LocalAddress:Port Scheduler Flags -> RemoteAddress:Port Forward Weight ActiveConn InActConn TCP 172.16.5.10:80 rr persistent 600 #定义会话持久超时时间600秒。600秒所记录的会话没有再次访问,则从模板中删除。 -> 192.168.5.11:80 Masq 1 0 0 -> 192.168.5.12:80 Masq 1 0 0
红线上面的就是所保持的会话,从10分钟开始倒数。
这里所定义的就是以集群服务端口来做的会话绑定,但是有的服务可是有多个端口的,比如:http和https这两个都是一起存在的,还有ftp服务端口就更多了。
概念补充:持久连接
PCC:将来自于同一个客户端的访问统统定位至同一个Real Server.
PPC:将来自于同一个客户端发往VIP的某个端口的访问统统定位至同一个Real Server.
PFMC:基于防火墙标记的,将多个端口绑定至同一个集群服务,同一个客户端请求的统一定位至同一个Real Server.
上面我们所做的都是基于PPC的。另外两个举例子来说明吧。
PCC:这个很简单,只是在定义集群服务的时候,把端口号写成0。只有指定-p才可以使用。
[root@director ~]# ipvsadm -C #清除所有规则,这里可不能用-E修改了,都已经不是同一个集群了。 [root@director ~]# ipvsadm -A -t 172.16.5.10:0 -s rr -p 600 #端口位置为0,这就是一个集群服务。 [root@director ~]# ipvsadm -a -t 172.16.5.10:0 -r 192.168.5.11 -m #这里没有什么变化,还是指定集群服务并添加Real Server。 [root@director ~]# ipvsadm -a -t 172.16.5.10:0 -r 192.168.5.12 -m [root@director ~]# ipvsadm -L -n IP Virtual Server version 1.2.1 (size=4096) Prot LocalAddress:Port Scheduler Flags -> RemoteAddress:Port Forward Weight ActiveConn InActConn TCP 172.16.5.10:0 rr persistent 600 -> 192.168.5.11:0 Masq 1 0 0 -> 192.168.5.12:0 Masq 1 0 0
这就完成了,就是一个端口号。这样无论来访的是什么请求,都会给分配到上次会话的Real Server上,DNS啦,ftp啦,http啦,各种各样啦。可是我们有Real Server是FTP,结果客户端访问ftp的请求给分配到http上了。好吧。
PCC作用范围太广,PPC作用范围太窄,那就可以用PFMC来自定义了。
注意:以上不是说持久连接什么的作用范围,而是集群服务的作用范围,持久连接是集群服务的功能。
PFMC: 主要是其于防火墙标记来创建集群服务的,与-p没有主要关系。
1.首先为某些来访请求打上防火墙标记
防火墙标记从0-99之间,我们可以为某些数据打上相同的标记。
如可以把访问VIP:80端口的数据打上标记为1(随便),然后再把访问VIP:443端口的数据也打上标记为1。
然后再以防火墙标记来创建集群,而不是按上面的那种以IP+端口来定义集群了。
[root@director ~]# iptables -t mangle -A PREROUTING -d 172.16.5.10 -p tcp -m multiport --dport 80,443 -j MARK --set-mark 1
这样就创建完防火墙规则了,防火墙会把所匹配到的数据以打标处理。
我们上面说过NAT模式不能与netfilter兼容(netfilter就是linux系统防火墙的核心),主要说的是防火墙中的fifter过滤还有NAT地址转换。而且上面打标的应用是在PREROUTING上,而IPVS是工作在INPUT上的,也没有什么冲突。
下面就可以开始创建集群服务了,其于防火墙标记来创建,用-f。
[root@director ~]# ipvsadm -C [root@director ~]# ipvsadm -A -f 1 -s rr -p 600 [root@director ~]# ipvsadm -a -f 1 -r 192.168.5.11 -m [root@director ~]# ipvsadm -a -f 1 -r 192.168.5.12 -m [root@director ~]# ipvsadm -L -n IP Virtual Server version 1.2.1 (size=4096) Prot LocalAddress:Port Scheduler Flags -> RemoteAddress:Port Forward Weight ActiveConn InActConn FWM 1 rr persistent 600 -> 192.168.5.11:0 Masq 1 0 0 -> 192.168.5.12:0 Masq 1 0 0
使用-f指定防火墙标记。来看下现在的连接:
[root@director CA]# ipvsadm -L -n -c IPVS connection entries pro expire state source virtual destination TCP 01:58 TIME_WAIT 172.16.3.108:53922 172.16.5.10:443 192.168.5.12:443 TCP 00:07 CLOSE 172.16.3.108:53919 172.16.5.10:443 192.168.5.12:443 TCP 00:08 CLOSE 172.16.3.108:53921 172.16.5.10:443 192.168.5.12:443 IP 09:58 NONE 172.16.3.108:0 0.0.0.1:0 192.168.5.12:0 TCP 00:06 CLOSE 172.16.3.108:53918 172.16.5.10:443 192.168.5.12:443 TCP 00:08 CLOSE 172.16.3.108:53924 172.16.5.10:443 192.168.5.12:443 TCP 00:07 CLOSE 172.16.3.108:53920 172.16.5.10:443 192.168.5.12:443 TCP 01:27 TIME_WAIT 172.16.3.108:53892 172.16.5.10:443 192.168.5.12:443 TCP 01:31 TIME_WAIT 172.16.3.108:53895 172.16.5.10:80 192.168.5.12:80 TCP 01:51 TIME_WAIT 172.16.3.108:53904 172.16.5.10:80 192.168.5.12:80 TCP 01:51 TIME_WAIT 172.16.3.108:53906 172.16.5.10:80 192.168.5.12:80 TCP 00:06 CLOSE 172.16.3.108:53917 172.16.5.10:443 192.168.5.12:443 TCP 01:51 TIME_WAIT 172.16.3.108:53905 172.16.5.10:80 192.168.5.12:80 TCP 00:08 CLOSE 172.16.3.108:53923 172.16.5.10:443 192.168.5.12:443 TCP 01:51 TIME_WAIT 172.16.3.108:53907 172.16.5.10:80 192.168.5.12:80 TCP 01:51 TIME_WAIT 172.16.3.108:53903 172.16.5.10:80 192.168.5.12:80 TCP 01:41 TIME_WAIT 172.16.3.108:53900 172.16.5.10:80 192.168.5.12:80 TCP 01:41 TIME_WAIT 172.16.3.108:53899 172.16.5.10:80 192.168.5.12:80 [root@director CA]#
可以看到无论是80端口还是443端口都被定向到了192.168.5.12。而保持会话的那的0.0.0.1:0因为那是防火墙标记的集群服务啊。如果是5号标记:
pro expire state source virtual destination IP 09:55 NONE 172.16.3.108:0 0.0.0.5:0 192.168.5.12:0
大家做实验有时候为了让这些连接清空,service ipvsadm stop 会卸载ipvs的模块,连接也就清空了,在定义规则的时候,模块又会自动挂载了。要注意保存规则啊。可以用service ipvsadm save来保存,用service ipvsadm start的时候会自动加载规则。这里的ipvsadm指的可不是服务,而是一个ipvsadm的管理脚本。
四、实验-DR模型。
大概步骤:
lvs定义vip
lvs开启转发(最好是打开)
定义Real Server不会广播或响应不属于当前网卡IP地址的ARP信息。
各Real Server定义隐藏VIP。
定义ipvs规则。
1、lvs定义VIP。这个如果是一张网卡直接在网卡别名上设置就好,不要设置在主网卡地址上。
[root@director ~]# ifconfig eth0:0 172.16.5.10
看网上有的教程在Director上的VIP地址掩码给设置成了四个255,这样用起来是没有问题,可是Director的VIP地址却不能与网关主动通信(因为它认为不在同一个网段),不过优点是可以保证与RIP通信的地址是DIP(因为VIP与RIP不在同一个网段)。
补充:如何让前端的路由器只知道Director上VIP的MAC地址,而不知道RS上VIP的MAC地址。
通过在前端路由器上做ARP绑定。缺点:1、要有路由器的权限;2、LVS在高可用环境中切换主机以后MAC地址变了。
arptables,设置RS上的arp防火墙不发送某些arp信息。缺点:配置复杂,容易出现问题。
修改linux内核参数,不响应不广播不属于当前网卡IP地址的ARP信息。
那么我们就用第3个。
2、在各RS上设置Real Server不会广播和响应不属于当前网卡ip地址的ARP信息。
echo 1 > /proc/sys/net/ipv4/conf/all/arp_ignore echo 1 > /proc/sys/net/ipv4/conf/eth0/arp_ignore echo 2 > /proc/sys/net/ipv4/conf/all/arp_announce echo 2 > /proc/sys/net/ipv4/conf/eth0/arp_announce
上面的all表示的所有接口,eth0表示在eth0接口。两个都修改只是为了安全。
看到有的在lo接口上设置,我觉得没有必要,lo又不是连接外面的出口。把好出口就好了。
如果想永久生效,在/etc/sysctl.conf中添加:
net.ipv4.conf.eth0.arp_ignore = 1 net.ipv4.conf.eth0.arp_announce = 2 net.ipv4.conf.all.arp_ignore = 1 net.ipv4.conf.all.arp_announce = 2
至于各参数的意义大家还是上网查吧。
3、定义各RS的VIP地址。
一定要在上面的arp参数配置完以后再添加VIP,不然还要在前端路由上清理arp表。我们这里是客户端直接访问的,就要清理访问主机的arp表。
ifconfig lo:0 172.16.5.10/32 broadcast 172.16.5.10 route add -host 172.16.5.10 dev lo:0 #手动指定路由条目,不指也可以,指了更保险。
要定义在回环地址上,这样经过上面的arp设置,网卡接口不会发送在lo接口上arp信息。
要想永久生效,直接定义一个ifcfg-lo:0的配置文件即可。
注意上面的子网掩码必须是全部的而且广播地址也要是自己。完全禁止它主动向外发送信息。
而且如果不是32位的子网掩码,网络还会断掉,不明白具体的原因,求科普。
4、定义ipvs规则。
[root@director ~]# ipvsadm -A -t 172.16.5.10:80 -s rr [root@director ~]# ipvsadm -a -t 172.16.5.10:80 -r 172.16.5.11 -g [root@director ~]# ipvsadm -a -t 172.16.5.10:80 -r 172.16.5.12 -g
定义规则还是一样的简单,变化只有一个-g。难就难在了概念上。
看下连接情况:
[root@director ~]# ipvsadm -L -n -c IPVS connection entries pro expire state source virtual destination TCP 00:07 CLOSE 172.16.3.108:51387 172.16.5.10:80 172.16.5.11:80 TCP 00:07 CLOSE 172.16.3.108:51385 172.16.5.10:80 172.16.5.11:80 TCP 00:06 CLOSE 172.16.3.108:51382 172.16.5.10:80 172.16.5.12:80 TCP 00:07 CLOSE 172.16.3.108:51384 172.16.5.10:80 172.16.5.12:80 TCP 00:07 CLOSE 172.16.3.108:51389 172.16.5.10:80 172.16.5.11:80 TCP 00:06 CLOSE 172.16.3.108:51383 172.16.5.10:80 172.16.5.11:80 TCP 00:07 CLOSE 172.16.3.108:51388 172.16.5.10:80 172.16.5.12:80 TCP 00:08 CLOSE 172.16.3.108:51390 172.16.5.10:80 172.16.5.12:80 TCP 00:07 CLOSE 172.16.3.108:51386 172.16.5.10:80 172.16.5.12:80 TCP 00:10 SYN_RECV 172.16.3.108:51364 172.16.5.10:80 172.16.5.12:80
上面的这样的使用,所有的IP都要是公网地址才行,如果没有这么多公网地址就可以将RS放到内网中,而RS数据出来的位置放一台路由器就可以了。RS的网关就要指定这台路由器,与LVS不是同一台路由器。情况就变成了这样。
Director的网关是RouteA,而各Real Server的网关就是RouteB了。而且RouteB的下一跳也是可以指向RouterA的,上面的图只是一种表现方式。Director可以是双网卡也可以是单网卡,RouteB也是一样。
在RouteB是双网卡的情况下(用linux系统所模拟的路由器,硬件路由不知道会不会这样),我们的实验环境可能会遇到路由不转发的情况,主要是因为我们的实验环境不严谨,路由器在收到一些异常的数据会直接丢弃,把上面那张图改一下成下面这个了:
这样从RS出来的数据源地址为172.16.5.10,目标地址为172.16.0.1,到达RouteB的192.168.5.1的接口。基中一种异常情况就是:在本网卡收到不该在本网卡收到的信息时,丢弃。如上面应该在172.16接口收到的信息却在192.168接口收到了。
这就是为什么单网卡用两个地址却没事,而用双网卡却出问题的原因。
在linux上面的这种安全过滤机制是可以关闭的,在:
/proc/net/ipv4/conf/*/rp_fifter开启或关闭(1为开启,0为关闭)
上面*号表示不同的接口。
还有一点,如果有默认路由,那么非网卡所在地址的网段只能从默认路由那边过来。
下面做实验的那个图也要改这个,不知道是属于什么异常数据了。
最后我们做次实验来结束吧,上图:
6台虚拟机,LVS也是双网卡(画双线不好看,就单线吧)。
做实验不要把网卡弄乱了,在虚拟机的设置-网络适配器-高级里面查看MAC地址,并与虚拟机里的MAC地址对比。有时候不知道网卡是eth?。
Director:添加IP,删除原来的默认路由,添加默认路由。
RealServer_A:
RealServer_B:
RouteA:
RouteB:
client:
好奇怿,为什么在client上会不通:可以ping得通。
最后在RouteB上面改了下面的参数就好了。
难道说这也是属于异常的报文?。不过linux到底还是跟真实的路由器不同。
实验结束。
lvs主要就是概念的问题,概念懂了,也自然就会配置了。
菜鸟一坨,难免会出现错误,还望朋友们指出。
很多由于做实验的时候所出的问题,可能大家的会有所不同。如发现错误,还望指出。
谢谢大家