原文地址:http://blog.sina.com.cn/s/blog_5f54f0be0101eyiu.html
LVS 是通过 IPVS 模块来实现的。IPVS是LVS集群的核心,主要用于完成用户的请求到达负载调度器后,如果将请求发送到每个真实服务器节点上的,服务器如何返回数据给用户。
我们服务器都是采用 CentOS 6 ,该版本默认就支持 LVS 功能。要验证是否支持,用如下命令:
[root@localhost keepalived]# modprobe -l | grep ipvs
kernel/net/netfilter/ipvs/ip_vs.ko
kernel/net/netfilter/ipvs/ip_vs_rr.ko
kernel/net/netfilter/ipvs/ip_vs_wrr.ko
kernel/net/netfilter/ipvs/ip_vs_lc.ko
kernel/net/netfilter/ipvs/ip_vs_wlc.ko
kernel/net/netfilter/ipvs/ip_vs_lblc.ko
kernel/net/netfilter/ipvs/ip_vs_lblcr.ko
kernel/net/netfilter/ipvs/ip_vs_dh.ko
kernel/net/netfilter/ipvs/ip_vs_sh.ko
kernel/net/netfilter/ipvs/ip_vs_sed.ko
kernel/net/netfilter/ipvs/ip_vs_nq.ko
kernel/net/netfilter/ipvs/ip_vs_ftp.ko
如果类似上面,表示支持。
如果不支持:
安装 ipvsadm
=============================
CentOS 安装:
yum install ipvsadm
源码安装:
不同 kernel 版本要下载的版本不一样。查看kernel 版本:
uname -a
我这边版本是 2.6.32 所以就下载 1.26 版的
wget http://www.linuxvirtualserver.org/software/kernel-2.6/ipvsadm-1.26.tar.gz
tar -zxf ipvsadm-1.26.tar.gz
cd ipvsadm-1.26
make
报错:
make[1]: *** [libipvs.o] Error 1
make[1]: Leaving directory `/usr/src/ipvsadm-1.26/libipvs'
make: *** [libs] Error 2
安装完以下这些软件
[root@host2 ipvsadm-1.26]# rpm -qa | grep popt
popt-1.13-7.el6.x86_64
popt-devel-1.13-7.el6.x86_64
[root@host2 ipvsadm-1.26]# rpm -qa | grep libnl
libnl-1.1-14.el6.x86_64
libnl-devel-1.1-14.el6.x86_64
分别用 yum 安装
yum install libnl-devel-1.1-14.el6.x86_64
再 make, 又报:
ipvsadm.o: In function `parse_options':
/usr/src/ipvsadm-1.26/ipvsadm.c:432: undefined reference to `poptGetContext'
/usr/src/ipvsadm-1.26/ipvsadm.c:435: undefined reference to `poptGetNextOpt'
/usr/src/ipvsadm-1.26/ipvsadm.c:660: undefined reference to `poptBadOption'
/usr/src/ipvsadm-1.26/ipvsadm.c:502: undefined reference to `poptGetNextOpt'
/usr/src/ipvsadm-1.26/ipvsadm.c:667: undefined reference to `poptStrerror'
/usr/src/ipvsadm-1.26/ipvsadm.c:667: undefined reference to `poptBadOption'
/usr/src/ipvsadm-1.26/ipvsadm.c:670: undefined reference to `poptFreeContext'
/usr/src/ipvsadm-1.26/ipvsadm.c:677: undefined reference to `poptGetArg'
/usr/src/ipvsadm-1.26/ipvsadm.c:678: undefined reference to `poptGetArg'
/usr/src/ipvsadm-1.26/ipvsadm.c:679: undefined reference to `poptGetArg'
/usr/src/ipvsadm-1.26/ipvsadm.c:690: undefined reference to `poptGetArg'
/usr/src/ipvsadm-1.26/ipvsadm.c:693: undefined reference to `poptFreeContext'
collect2: ld returned 1 exit status
make: *** [ipvsadm] Error 1
wget http://mirror.centos.org/centos/6/os/x86_64/Packages/popt-static-1.13-7.el6.x86_64.rpm
rpm -ivh popt-static-1.13-7.el6.x86_64.rpm
然后再:
make
make install
ipvsadm --help
如果有对应的帮助信息表示安装成功了
配置 LVS 集群
=======================================
配置 LVS 集群可以通过 ipvsadm 命令进行。
这里写一个 shell 脚本去配置。也有一些工具可以去辅助配置。但用脚本还是比较直观。
在负载均衡服务器 主服务器上运行脚本 lvs.sh:
#!/bin/bash
SNS_VIP=192.168.2.118
SNS_RIP1=192.168.2.119
SNS_RIP2=192.168.2.35
/etc/rc.d/init.d/functions
logger $0 called with $1
case "$1" in
start)
/sbin/ipvsadm -set 30 5 60
/sbin/ifconfig eth0:0 $SNS_VIP broadcast $SNS_VIP netmask 255.255.255.255 broadcast $SNS_VIP up
/sbin/route add -host $SNS_VIP dev eth0:0
/sbin/ipvsadm -A -t $SNS_VIP:80 -s wlc -p 120
/sbin/ipvsadm -a -t $SNS_VIP:80 -r $SNS_RIP1:80 -g -w 1
/sbin/ipvsadm -a -t $SNS_VIP:80 -r $SNS_RIP2:80 -g -w 1
touch /var/lock/subsys/ipvsadm > /dev/null 2>&1
;;
stop)
/sbin/ipvsadm -C
/sbin/ipvsadm -Z
ifconfig eth0:0 down
route del $SNS_VIP
rm -rf /var/lock/subsys/ipvsadm > /dev/null 2>&1
echo "ipvsadm stopped!"
;;
status)
if [ ! -e /var/lock/subsys/ipvsadm ]
then
echo "ipvsadm stopped!"
exit 1
else
echo "ipvsadm started!"
fi
;;
*)
echo "Usage: $0 {start | stop | status}"
exit 1
esac
exit 0
该脚本会去绑定 VIP到当前网卡 eth0 上,并把请求转发到其它两个IP上。
绑定后,给该脚本加上执行权限:
chmod +x lvs.sh
然后执行:
./lvs.sh start
运行完后,查看当前IP:
ifconfig
会发现多了一个 eth0:0
注意:当前脚本中是通过:/sbin/ifconfig eth0:0 $SNS_VIP broadcast $SNS_VIP netmask 255.255.255.0 broadcast $SNS_VIP up 去绑定 eth0:0 但根据网络环境不一样,绑定到的位置可能不同。比如我测试的时候发现 ifconfig 的值里面没有 eth0, 有一个 eth3, 这时就要绑定到 eth3:0 上。同时,netmask 的值也要根据自己网络里的实际值去设置。
在真实的服务器上写脚本:realserver.sh
#!/bin/bash
SNS_VIP=192.168.1.108
/etc/rc.d/init.d/functions
case "$1" in
start)
ifconfig lo:0 $SNS_VIP netmask 255.255.255.255 broadcast $SNS_VIP
/sbin/route add -host $SNS_VIP dev lo:0
echo "1" > /proc/sys/net/ipv4/conf/lo/arp_ignore
echo "2" > /proc/sys/net/ipv4/conf/lo/arp_announce
echo "1" > /proc/sys/net/ipv4/conf/all/arp_ignore
echo "2" > /proc/sys/net/ipv4/conf/all/arp_announce
sysctl -p > /dev/null 2>&1
echo "RealServer started!"
;;
stop)
ifconfig lo:0 down
/sbin/route del $LVS_VIP > /dev/null 2>&1
echo "0" > /proc/sys/net/ipv4/conf/lo/arp_ignore
echo "0" > /proc/sys/net/ipv4/conf/lo/arp_announce
echo "0" > /proc/sys/net/ipv4/conf/all/arp_ignore
echo "0" > /proc/sys/net/ipv4/conf/all/arp_announce
echo "RealServer stopped!"
;;
*)
echo "Usage: $0 {start | stop}"
exit 1
esac
exit 0
这个脚本的功能是绑定 VIP 到 lo 上。在每个真实服务器上都要有。
和上面一样,加执行权限然后执行:
chmod +x realserver.sh
./realserver.sh start
这时,访问 192.168.2.118 即可看到效果。请求会被转发到 119 或者 35 上。
------------------------------------------------------------------------------------------------
负载均衡三种实现方式的理论:
虚拟服务器: VS / NAT
==========================================
实体 IP: 在网络的世界里,为了要辨识每一部计算机的位置,因此有了计算机IP 位址的定义。一个IP 就好似一个门牌!例如,你要去微软的网站的话,就要去『207.46.197.101 』这个IP 位置!这些可以直接在网际网络上沟通的IP 就被称为『实体IP 』了。
虚拟 IP:不过,众所皆知的,IP位址仅为 xxx.xxx.xxx.xxx 的资料型态,其中, xxx为 1-255间的整数,由于近来计算机的成长速度太快,实体的IP 已经有点不足了,好在早在规划IP 时就已经预留了三个网段的IP 做为内部网域的虚拟IP 之用。这三个预留的IP 分别为:
A级:10.0.0.0 - 10.255.255.255
B级:172.16.0.0 - 172.31.255.255
C级:192.168.0.0 - 192.168.255.255
上述中最常用的是192.168.0.0这一组。
不过,由于是虚拟 IP,所以当您使用这些地址的时候,当然是有所限制的,限制如下:
私有位址的路由信息不能对外散播
使用私有位址作为来源或目的地址的封包,不能透过Internet来转送
当内部网络要访问外部的时候,就需要将内部地址转换成外网可用的地址,即:网络地址转换 Network Address Translation, NAT.
每次请求的报文头(目标地址,源地址,端口)都被正确改写。外部用户访问该网络时, 请求会被转到内部的某个 IP 上,然后报文的数据被改写。目标机器处理完后把报文传给进行网络地址转换的设备(通常是路由器),这时候请求目标地址是该设备,然后返回的报文的报文头被改写成当前发起请求的地址.这次交互完成.所以,每次请求都要在地址转换设备上中转一次。它的性能就会成为瓶颈。
我们的路由器就是用来做这个的。
我们的路由器的 IP 就是我们这个内部网络所有机器的外部 IP.我们可以做如下设置: 将该路由器上所有的 80 端口的请求都转到内网的 192.168.2.222 (虚拟 IP)上.也可以转到其他任何一台连接到路由器上的机器上.
我们可以进行如下设置:
1.路由器将请求轮流解析到内部机器 A, B的内部 IP 上。[四层轮询的 LVS]
2.路由器将请求解析到 A 上,A, B 互相监视, 如果 A 挂了, B 将自己的 IP 设置成 A 之前的 IP. 这样可继续服务.[主 / 备]
这种办法的好处是用IP协议的,所以只要是支持TCP/IP的操作系统,只要一个公网IP放在调度机器上就成了,服务器组用私有IP。不足的是,调度机器会承受很大的压力,因为每次请求和响应都会经过它。
虚拟服务器: VS / TUN
==========================================
IP 隧道
大多数请求都有这种规律:请求报文较短,而响应很短。如平日我们看网站:提交的数据很少,但服务器返回的数据很多。
这时候想到的就是:将请求和响应分开。负载均衡的设备只负责响应请求,转发。而响应则直接返回给客户,不经过它。
调度器根据各个服务器的负载情况,动态地选择一台服务器,将请求报文封装在另一个IP报文中,再将封装后的IP报文转发给选出的服务器;服务器收到报文后,先将报文解封获得原来目标地址为VIP的报文,服务器发现VIP地址被配置在本地的IP隧道设备上,所以就处理这个请求,然后根据路由表将响应报文直接返回给客户。
在这里,请求报文的目标地址为VIP,响应报文的源地址也为VIP,所以响应报文不需要作任何修改,可以直接返回给客户,客户认为得到正常的服务,而不会知道是哪一台服务器处理的。
这种方式解放了调度器,它只负责选择真实服务器,然后进行IP封装,转发。同样,它的问题就在于,使用它就必须支持 IP 隧道协议。
虚拟服务器: VS / DR
==========================================
调度器和服务器组都必须在物理上有一个网卡通过不分段的局域网相连,即通过交换机或者高速的HUB相连,中间没有隔有路由器。VIP地址为调度器和服务器组共享,调度器配置的VIP地址是对外可见的,用于接收虚拟服务的请求报文;所有的服务器把VIP地址配置在各自的Non-ARP网络设备上,它对外面是不可见的,只是用于处理目标地址为VIP的网络请求。
调度器根据各个服务器的负载情况,动态地选择一台服务器,不修改也不封装IP报文,而是将数据帧的MAC地址改为选出服务器的MAC地址,再将修改后的数据帧在与服务器组的局域网上发送。因为数据帧的MAC地址是选出的服务器,所以服务器肯定可以收到这个数据帧,从中可以获得该IP报文。当服务器发现报文的目标地址VIP是在本地的网络设备上,服务器处理这个报文,然后根据路由表将响应报文直接返回给客户。
「Non-ARP 说明」arp (address resolution protocol),主要是确认网卡的物理地址用的,在三层是 ip,到了二层要通过 arp 协议确认哪个ip和哪个物理地址的对应关系,如果一个网卡没有mac地址那么,这个网卡配置的ip就不会被外界知道,一般这样的ip只用于内部交流用我们称之为 Non-ARP,没有mac地址的网卡一般也只有本地的loopback 口,在 lvs 的 Non-ARP 就是这个含义---- 没有 MAC 地址的网卡与 IP 只能在本机内做回环地址,不被外界所见。
和上面 VS/TUN 相比它不用 IP 隧道,通用性更强.但是要求真实服务器和调度器都有一块网卡,且连在同一物理网段上。真实服务器的网卡不做 ARP 响应. 这种方式目前是最流行的。