目录
随着应用系统业务量的增长和用户的增加,服务器的的压力越来越大、性能逐渐下降,利用负载均衡等技术可以解决这一问题。但如果选择商业硬件如F5等价格太高,从节约成本的角度考虑,选用基于开源的软件架构LVS+keepalive可以为我们实现高性能、高可用的负载均衡服务器集群,本文就来大概讲述一下搭建的过程。

LVS是Linux Virtual Server的简写,意即Linux虚拟服务器,是一个虚拟的服务器集群系统。本项目在1998年5月由章文嵩博士成立,是中国国内最早出现的自由软件项目之一。
LVS集群采用IP网络地址转化负载均衡技术和基于内容请求分发技术,调度器具有很好的吞吐率,将请求均衡地转移到不同的服务器上执行,且调度器自动屏蔽掉服务器的故障,从而将一组服务器构成一个高性能的、高可用的虚拟服务器。目前有三种IP网络地址转化负载均衡实现技术(VS/NAT、VS/TUN和VS/DR):
1)Virtual Server via Network Address Translation(VS/NAT):通过网络地址转换,调度器重写请求报文的目标地址,根据预设的调度算法,将请求分派给后端的真实服务器;真实服务器的响应报文通过调度器时,报文的源地址被重写,再返回给客户,完成整个负载调度过程。
2)Virtual Server via IP Tunneling(VS/TUN):采用NAT技术时,由于请求和响应报文都必须经过调度器地址重写,当客户请求越来越多时,调度器的处理能力将成为瓶颈。为了解决这个问题,调度器把请求报文通过IP隧道转发至真实服务器,而真实服务器将响应直接返回给客户,所以调度器只处理请求报文。由于一般网络服务应答比请求报文大许多,采用VS/TUN技术后,集群系统的最大吞吐量可以提高10倍。
3)Virtual Server via Direct Routing(VS/DR):VS/DR通过改写请求报文的MAC地址,将请求发送到真实服务器,而真实服务器将响应直接返回给客户。同VS/TUN技术一样,VS/DR技术可极大地提高集群系统的伸缩性。这种方法没有IP隧道的开销,对集群中的真实服务器也没有必须支持IP隧道协议的要求,但是要求调度器与真实服务器都有一块网卡连在同一物理网段上。
针对不同的网络服务需求和服务器配置,IPVS调度器实现了八种(rr、wrr、lc、wlc、lblc、lblcr、dh、sh)负载调度算法:
1)轮叫(Round Robin):调度器通过"轮叫"调度算法将外部请求按顺序轮流分配到集群中的真实服务器上,它均等地对待每一台服务器,而不管服务器上实际的连接数和系统负载。
2)加权轮叫(Weighted Round Robin):调度器通过"加权轮叫"调度算法根据真实服务器的不同处理能力来调度访问请求。这样可以保证处理能力强的服务器处理更多的访问流量。调度器可以自动问询真实服务器的负载情况,并动态地调整其权值。
3)最少链接(Least Connections):调度器通过"最少连接"调度算法动态地将网络请求调度到已建立的链接数最少的服务器上。如果集群系统的真实服务器具有相近的系统性能,采用"最小连接"调度算法可以较好地均衡负载。
4)加权最少链接(Weighted Least Connections):在集群系统中的服务器性能差异较大的情况下,调度器采用"加权最少链接"调度算法优化负载均衡性能,具有较高权值的服务器将承受较大比例的活动连接负载。调度器可以自动问询真实服务器的负载情况,并动态地调整其权值。
5)基于局部性的最少链接(Locality-Based Least Connections):调度算法是针对目标IP地址的负载均衡,目前主要用于Cache集群系统。该算法根据请求的目标IP地址找出该目标IP地址最近使用的服务器,若该服务器是可用的且没有超载,将请求发送到该服务器;若服务器不存在,或者该服务器超载且有服务器处于一半的工作负载,则用"最少链接"的原则选出一个可用的服务器,将请求发送到该服务器。
6)带复制的基于局部性最少链接(Locality-Based Least Connections with Replication):调度算法也是针对目标IP地址的负载均衡,目前主要用于Cache集群系统。它与LBLC算法的不同之处是它要维护从一个目标IP地址到一组服务器的映射,而LBLC算法维护从一个目标IP地址到一台服务器的映射。该算法根据请求的目标IP地址找出该目标IP地址对应的服务器组,按"最小连接"原则从服务器组中选出一台服务器,若服务器没有超载,将请求发送到该服务器,若服务器超载;则按"最小连接"原则从这个集群中选出一台服务器,将该服务器加入到服务器组中,将请求发送到该服务器。同时,当该服务器组有一段时间没有被修改,将最忙的服务器从服务器组中删除,以降低复制的程度。
7)目标地址散列(Destination Hashing):调度算法根据请求的目标IP地址,作为散列键(Hash Key)从静态分配的散列表找出对应的服务器,若该服务器是可用的且未超载,将请求发送到该服务器,否则返回空。
8)源地址散列(Source Hashing):调度算法根据请求的源IP地址,作为散列键(Hash Key)从静态分配的散列表找出对应的服务器,若该服务器是可用的且未超载,将请求发送到该服务器,否则返回空。
Keepalived主要用作RealServer的健康状态检查以及LoadBalance主机和BackUP主机之间failover的实现。Keepalived的作用是检测服务器的状态,如果有一台web服务器宕机,或工作出现故障,Keepalived将检测到,并将有故障的服务器从系统中剔除,同时使用其他服务器代替该服务器的工作,当服务器工作正常后Keepalived自动将服务器加入到服务器群中,这些工作全部自动完成,不需要人工干涉,需要人工做的只是修复故障的服务器。
环境中的服务器设备的参数如下:

使用LVS和Keepalived搭建的负载均衡服务器集群示例环境的网络拓扑图如下:

要使用Linux内核提供的LVS能力,需安装一个LVS的管理工具ipvsadm。首先安装该软件,这里使用的版本是ipvsadm-1.24.tar.gz,可以到LVS官方网站下载。
- $ tar zxvf ipvsadm-1.24.tar.gz
- $ cd ipvsadm-1.24
- $ ln -s /usr/src/kernels/2.6.18-194.el5-x86_64 /usr/src/linux
- $ make
- $ make install
注意一定要与当前的运行的内核相一致。如果不创建这个连接文件,在编译时会出错,从而不能继续进行安装。
检验ipvsadm是否被正确安装,看是否有如下输出:
- $ ipvsadm
- IP Virtual Server version 1.2.1 (size=4096)
- Port LocalAddress:Port Scheduler Flags ->RomoteAddress:Port
- Forward Weight ActiveConn InActConn
检查当前加载的内核模块,看是否存在ip_vs模块:
- $ lsmod | grep ip_vs
- ip_vs 77569 0
注意,只有执行ipvsadm以后,才会在内核加载ip_vs模块;不能以查进程的方式判断ipvs是否运行。
这里使用版本keepalived-1.1.19,下载地址http://www.keepalived.org/software/keepalived-1.1.19.tar.gz
- $ tar -zxvf keepalived-1.1.19.tar.gz
- $ cd keepalived-1.1.19
- $ ./configure --prefix=/usr/local/keepalived
- $ make
- $ make install
- $ cp /usr/local/keepalived/etc/rc.d/init.d/keepalived /etc/rc.d/init.d/
- $ chmod +x /etc/rc.d/init.d/keepalived
- $ cp /usr/local/keepalived/etc/sysconfig/keepalived /etc/sysconfig/
- $ mkdir /etc/keepalived
- $ cp /usr/local/keepalived/etc/keepalived/keepalived.conf /etc/keepalived/
- $ cp /usr/local/keepalived/sbin/keepalived /usr/sbin/
- $ service keepalived start
如果编译时出现如下错误:
configure: error:
!!! OpenSSL is not properly installed on your system. !!!
!!! Can not include OpenSSL headers files. !!!
解决办法:
$ yum -y install openssl-devel
开启负载服务器路由机制:
- $ vi /etc/sysctl.conf
- net.ipv4.ip_forward = 1
- #sysctl -p
建立负载服务器启动脚本:
-
- $ vi /sbin/lvsdr.sh
- #!/bin/bash
- VIP=172.16.3.100
- RIP1=172.16.3.53
- RIP2=172.16.3.63
- /etc/rc.d/init.d/functions
- case "$1" in
- start)
- echo "start LVS of DirectorServer"
- #Set the Virtual IP Address
- /sbin/ifconfig eth0:1 $VIP broadcast $VIP netmask 255.255.255.255 up
- /sbin/route add -host $VIP dev eth0:1
- #Clear IPVS Table
- /sbin/ipvsadm -C
- #Set Lvs
- /sbin/ipvsadm -A -t $VIP:80 -s wrr
- /sbin/ipvsadm -a -t $VIP:80 -r $RIP1:80 -g
- /sbin/ipvsadm -a -t $VIP:80 -r $RIP2:80 -g
- #Run Lvs
- /sbin/ipvsadm
- ;;
- stop)
- echo "Close LVS Directorserver"
- /sbin/ifconfig eth0:1 down
- /sbin/ipvsadm -C
- ;;
- *)
- echo "Usage0{start|stop}"
- exit 1
- esac
- $ chmod 755 /sbin/lvsdr.sh
执行测试:
- $ /sbin/lvsdr.sh start
- $ ifconfig **查看是否有ifcfg-eth0:1
- $ route -n **查看路由表是否多了eth0:1的路由
配置后端WEB服务器:在WEB1和WEB2上分别建立如下脚本并执行,以下脚本使Realserver不响应ARP请求:
- $ vi /sbin/realdr.sh
- #!/bin/bash
- # Written by NetSeek
- # description: Config realserver lo and apply noarp
- VIP=172.16.3.100
- /etc/rc.d/init.d/functions
- case "$1" in
- start)
- ifconfig lo:0 $VIP netmask 255.255.255.255 broadcast $VIP
- /sbin/route add -host $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 Start OK"
- ;;
- stop)
- ifconfig lo:0 down
- route del $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 Stoped"
- ;;
- status)
- # Status of LVS-DR real server.
- islothere=`/sbin/ifconfig lo:0 | grep $VIP`
- isrothere=`netstat -rn | grep "lo:0" | grep $VIP`
- if [ ! "$islothere" -o ! "isrothere" ];then
- # Either the route or the lo:0 device
- # not found.
- echo "LVS-DR real server Stopped."
- else
- echo "LVS-DR Running."
- fi
- ;;
- *)
- # Invalid entry.
- echo "$0: Usage: $0 {start|status|stop}"
- exit 1
- ;;
- esac
- exit 0
- $ chmod 755 /sbin/realdr.sh
- $ realdr.sh start
- $ sysctl -p
-
-
后端WEB服务器也可采用secondary ip address方式配置,在/etc/sysctl.conf添加以下内容:
- $ vi /etc/sysctl.conf
- net.ipv4.conf.lo.arp_ignore = 1
- net.ipv4.conf.lo.arp_announce = 2
- net.ipv4.conf.all.arp_ignore = 1
- net.ipv4.conf.all.arp_announce = 2
- $ sysctl –p
- $ ip addr add 172.16.3.100/32 dev lo
- $ ip add list **查看是否绑定
首先配置Master调度器keepalived:
- $ vi /etc/keepalived/keepalived.conf
- global_defs {
- router_id LVS_master_2
- }
- vrrp_sync_group VGM {
- group {
- VI_CACHE
- }
- }
- vrrp_instance VI_CACHE {
- state MASTER
- interface eth0
- lvs_sync_daemon_inteface eth0
- virtual_router_id 51
- priority 180
- advert_int 5
- authentication {
- auth_type PASS
- auth_pass 1111
- }
- virtual_ipaddress {
- 172.16.3.100
- }
- }
- virtual_server 172.16.3.100 80 {
- delay_loop 6
- lb_algo wlc
- lb_kind DR
- protocol TCP
- real_server 172.16.3.53 80 {
- weight 10
- TCP_CHECK {
- connect_timeout 3
- nb_get_retry 3
- delay_before_retry 3
- connect_port 80
- }
- }
- real_server 172.16.3.63 80 {
- weight 100
- TCP_CHECK {
- connect_timeout 3
- nb_get_retry 3
- delay_before_retry 3
- connect_port 80
- }
- }
- }
再配置Backup调度器keepalived:
- #vi /etc/keepalived/keepalived.conf
- global_defs {
- router_id LVS_backup_2
- }
- vrrp_sync_group VGM {
- group {
- VI_CACHE
- }
- }
- vrrp_instance VI_CACHE {
- state BACKUP
- interface eth0
- lvs_sync_daemon_inteface eth0
- virtual_router_id 51
- priority 150
- advert_int 5
- authentication {
- auth_type PASS
- auth_pass 1111
- }
- virtual_ipaddress {
- 172.16.3.100
- }
- }
- virtual_server 172.16.3.100 80 {
- delay_loop 6
- lb_algo wlc
- lb_kind DR
- protocol TCP
- real_server 172.16.3.53 80 {
- weight 100
- TCP_CHECK {
- connect_timeout 3
- nb_get_retry 3
- delay_before_retry 3
- connect_port 80
- }
- }
- real_server 172.16.3.63 80 {
- weight 10
- TCP_CHECK {
- connect_timeout 3
- nb_get_retry 3
- delay_before_retry 3
- connect_port 80
- }
- }
- }
然后启动keepalived:
- $ /etc/rc.d/init.d/keepalived start **把这条语句写到/etc/rc.local中,开机启动
- 用ps 去查看一下相关的进程是否存在,#tail -f /var/log/messages看一下日志。由以下结果知已绑定VIP
- $ ip add
- 1: lo:
mtu 16436 qdisc noqueue - link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
- inet 127.0.0.1/8 scope host lo
- inet6 ::1/128 scope host
- valid_lft forever preferred_lft forever
- 2: eth0:
mtu 1500 qdisc pfifo_fast qlen 1000 - link/ether 00:0c:29:81:ce:0e brd ff:ff:ff:ff:ff:ff
- inet 172.16.3.65/19 brd 172.16.31.255 scope global eth0
- inet 172.16.3.100/32 brd 172.16.3.100 scope global eth0:1
- inet6 fe80::20c:29ff:fe81:ce0e/64 scope link
- valid_lft forever preferred_lft forever
- 3: sit0:
mtu 1480 qdisc noop - link/sit 0.0.0.0 brd 0.0.0.0
为测试方便,在两台真实服务器上分别安装apache,并在web目录下放置两个不同内容的文件a.html,访问地址分别为http://172.16.3.53/a.html http://172.16.3.63/a.html 返回结果如下:


然后再通过LVS配置的虚地址http://172.16.3.100/a.html访问服务器,可以看到两个页面交替出现。由此可知,LVS把请求转发到了后端真实服务器、实现了负载均衡。
关闭其中一台WEB服务器,然后在LVS 上用ipvsadm 命令查看
- $ ipvsadm -ln
- IP Virtual Server version 1.2.1 (size=4096)
- Prot LocalAddress:Port Scheduler Flags
- -> RemoteAddress:Port Forward Weight ActiveConn InActConn
- TCP 172.16.3.100:http wrr persistent 60
- -> 172.16.3.63:http Route 3 0 0
通过上面测试可以知道,当WEB服务器故障或者无法提供服务时,负载均衡器通过健康检查自动把失效的机器从转发队列删除掉。
重启被关闭的WEB服务器,当WEB服务器故障恢复后,负载均衡器通过健康检查自动把恢复后的机器添加到转发队列中。
- $ ipvsadm -ln
- IP Virtual Server version 1.2.1 (size=4096)
- Prot LocalAddress:Port Scheduler Flags
- -> RemoteAddress:Port Forward Weight ActiveConn InActConn
- TCP 172.16.3.100:http wrr persistent 60
- -> 172.16.3.53:http Route 3 0 0
- -> 172.16.3.63:http Route 3 0 0
停掉master的LVS,backup会自动接管master工作。停掉主LVS:
- $ lvsdr.sh stop
- $ service keepalived stop
查看备用LVS的运行状态:备用LVS已经接管了工作,状态为MASTER STATE。
$ tail -f /var/log/messages

当master 恢复时,backup会自动回到backup状态,master会自动接管工作。重新启动主LVS,查看主LVS的运行状态:主LVS又主动接管了工作,状态为MASTER STATE:
- $ lvsdr.sh stop
- $ service keepalived stop
- $ tail -f /var/log/messages

这个时候,备用LVS的状态一定是BACKUP STATE:
![]()
本文使用LVS通过转发请求到后端真实服务器来实现负载均衡,把keepalived用作后端真实服务器的健康状态检查以及负载均衡主机和备份机之间失效备援。我们可还以结合分布式文件系统、memcached等技术来进一步优化提高服务器的性能。