原理图
1. LVS
1.1. LVS介绍
LVS是LINUX VIRTUL
SERVER的简称,是由章文嵩博士主持的著名开放源码项目,一个实现“三高”系统的解决方案。LVS旨在解决高速发展的Web商务中日益凸现的问题:如
何在有限资金投入的情况下,最大幅度的提高Web站点的潜在服务性能。核心就是通过一组服务器来进行负载均衡,通过前端的负载调度器(Load
Balancer),无缝地将网络请求调度到真实服务器上,从而使得服务器集群的结构对客户是透明的,客户访问集群系统提供的网络服务就像访问一台高性
能、高可用的服务器一样。客户程序不受服务器集群的影响不需作任何修改。
系统的伸缩性通过在服务机群中透明地加入和删除一个节点来达到,通过检测节点或服务进程故障和正确地重置系统达到高可用性。由于我们的负载调度技术 是在Linux内核中实现的,我们称之为Linux虚拟服务器(Linux Virtual Server)。以下为其大体的结构图
LVS的设计根据透明性、性能、高可用性、可管理性和可编程性的指导思想实现的。
我们把前面那台负载均衡机器叫做:director server(DR)。后面的实际服务机器叫做:real server(RS)
具体介绍请参考以下网址:
1.2. LVS的三种负载均衡模式
调度器的实现技术中,IP负载均衡技术是效率最高的,IP虚拟服务器软件(IPVS)是在linux内核中实现的。
1.2.1. NAT模式
NAT 用法本来是因为网络IP地址不足而把内部保留IP地址通过映射转换成公网地址的一种上网方式(原地址NAT)。如果把NAT的过程稍微变化,就可以成为负 载均衡的一种方式。原理其实就是把从客户端发来的IP包的IP头目的地址在DR上换成其中一台REAL SERVER的IP地址并发至此REAL SERVER,而REAL SERVER则在处理完成后把数据经过DR主机发回给客户端,DR在这个时候再把数据包的原IP地址改为DR接口上的IP地址即可。期间,无论是进来的流 量,还是出去的流量,都必须经过DR。
1.2.2. IP隧道模式
隧道模式则类似于VPN的方式,使用网络分层的原理,在从客户端发来的数据包的基础上,封装一个新的IP头标记(不完整的IP头,只有目的IP部) 发给REAL SERVER,REAL SERVER收到后,先把DR发过来的数据包的头给解开,还原其数据包原样,处理后,直接返回给客户端,而不需要再经过DR。需要注意的是,由于REAL SERVER需要对DR发过来的数据包进行还原,也就是说必须支持IP TUNNEL协议。所以,在REAL SERVER的内核中,必须编译支持IP TUNNEL这个选项。IP TUNNEL也在Networking options里面,如下图所示。
1.2.3. 直接路由模式
直接路由模式比较特别,很难说和什么方面相似,前2种模式基本上都是工作在网络层上(三层),而直接路由模式则应该是工作在数据链路层上(二层)。其原理
为,DR和REAL SERVER都使用同一个IP对外服务。但只有DR对ARP请求进行响应,所有REAL
SERVER对本身这个IP的ARP请求保持静默。也就是说,网关会把对这个服务IP的请求全部定向给DR,而DR收到数据包后根据调度算法,找出对应的
REAL SERVER,把目的MAC地址改为REAL SERVER的MAC并发给这台REAL SERVER。这时REAL
SERVER收到这个数据包,则等于直接从客户端收到这个数据包无异,处理后直接返回给客户端。由于DR要对二层包头进行改换,所以DR和REAL
SERVER之间必须在一个广播域,也可以简单的理解为在同一台交换机上。
具体请参考以下网址:/lvs3.html
1.3. LVS的安装和配置
LVS的安装在其官方网站上有详细的说明文档。网址是: /HOWTO/ 。不过一般说来以下网址/mini-HOWTO/LVS-mini- HOWTO.html就足够了。
1.3.1. 让DR内核支持 IPVS
2.6及以上内核中已经支持了IPVS功能。至于2.4的内核则看版本,2.4.23及以上的内核已经有了ipvs,所以不必且不能打包,如果打了就会编译出错。对于2.4.23以下内核则必须打IPVS补丁。2.4.23/24的内核有问题,所以不建议使用这两种内核。
IPVS只对DR需要,而RS则不需要。
Ipvs补丁和ipvsadm的下载地址:
1.3.1.1. 打补丁来支持ipvs
对于2.4.23以下内核需要这个步骤,否则请按1.3.1.2步骤。
到下载对应的补丁。假设你使用的内核 是2.4.18, 那么下载Version 1.0.10,包为ipvs-1.0.10.tar.gz。解包后阅读README文件,按中其中的方法打包。不过我对这里的说明有点不明白。下面我说说 我的方法:
cd
make patchkernel
make installsource
或者
cd /usr/src/linux
cp
cp
patch –p1 < linux_kernel_ksyms_c.diff
patch –p1 < linux_net_netsyms_c.diff
然后cd /usr/src/linux
make dep; make bzImage;
接着重新copy新的内核文件,然后lilo,然后reboot
1.3.1.2. 重新配置内核选项来支持IPVS
对于2.4.23及以上的内核已经有了ipvs,所以你可以直接在内核中配置来支持IPVS。
cd /usr/src/linux
make menuconfig
对于不同版本的内核来说,各个配置项的路径是不一致的。对于2.6.8.1菜单路径是:Device Drivers->Networking support -> Networking options->IP: Virtual Server Configuration。而在2.4.30的内核中Networking options就在第一层路径下面。请到目的菜单Networking
请选中所有的选项。
要关注的是IPVS connection table size,这个东西意思是每个连接的hash table的大小,大家知道通常hash表越大,一次命中的机会越大。这里取值范围是2-20,2的2次方到2的20次方。有的资料建议用20,个人认为 默认值就足够了。由于每个连接需要128BYTE,每个HASH位需要8BYTE,所以(128 + 8 ) * 2^20 = 128M + 8 M = 136M,对于我们的系统没问题。
最后的是IPVS application helper,这种是专门针对多次连接的情况的(可以理解为session),大家都知道一次FTP通讯需要2次连接,所以必须保证这两次都在一台服务器 上,否则将连接失败。这是个明显针对协议,或者说针对应用层的分类。有点七层交换的味道,希望这个功能尽快把HTTP的SESSION给加上,到时就不用 使用后台同步SESSION或者对原地址做HASH定向处理了。
这里负载调度算法的意思请具体参考:/lvs4.html
make dep; make bzImage;
接着重新copy新的内核文件,然后lilo,然后reboot。启动时可以看到ipvs提示信息。
1.3.2. RS的NOARP问题解决
直接路由模式肯定要处理NOARP的问题,官方文档《LVS-mini-HOWTO》3.7节指出在如下情况下必须处理:
IF( (you are using LVS-DR or LVS-Tun on the director)
AND
(you are running a Linux 2.2.x, 2.4.x, 2.6.x kernel on a realserver)
AND
(
the VIP on the realserver is on an ethernet device eg lo:0, tunl0:0
i.e. packets to the VIP are not being accepted by transparent proxy
)
AND
(
the realservers can answer arp requests from
the client/router (the realservers are on the same
piece of wire|network|segment as the director)
) )
THEN { YOU MUST HANDLE THE ARP PROBLEM }
FI
对于这断话的,我不太理解。下面引用其它的文档说明。
在使用LVS中的DR与IP Tunnel的时候,会需要有一块网络卡要设定两个IP的情形,但是Linux在2.2.14之后,就将eth0:1的-NOARP这个FLAG关闭。也 就是说在kernel 2.2.14以后,eth0:1就视为eth0的别名,任何对eth0:1的设定也同样作用在eth0,换句话说,我对eth0:1下-NOARP,同样 也会对eth0有作用,这样会使得整张网络卡收不到封包。
在直接路由、IP隧道模式下,因为我所有的机器都放在同一个网段,当该网段的Router接收到客户端(Client)对虚拟IP(Virtual IP)的TCP connection要求时,会先在网段中利用Arp request询问谁有VIP的地址,而包含Director与RealServers上所有的interface(不管Primary还是 Subinterface),只要他有那个ip,都会发送arp reply回去,造成网段内所有拥有Virtual IP的interface都会reply给Router,最后结果就是看谁的速度快,Router就将该封包送给谁,如此会造成LVS的Server并无 法发挥其效果,因此需要利用hidden这个pattch,将Subinterface上的Virtual IP给隐藏起来,如此他就不会对Arp Request进行Reply,如此就可以解决ARP的问题,而这个NOARP的问题,kernel发展小组认为不重要,所以以后都不会修改,要用请自行 编译。
所以从~ja/#hidden下载对应的补丁,对于2.6.8.1的内核我选择hidden-2.6.4-1.diff。
cp hidden-2.6.4-1.diff /usr/src/linux
cd /usr/src/linux
patch –p1 < hidden-2.6.4-1.diff
make dep;make bzImage;
copy新的内核文件到相应的启动目录。再lilo。最后reboot。
当然解决noarp的问题,不止这一种。譬如leofan在内核中通过以下四个命令解决,前提条件是有这些设备:
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
不过我在2.6.8.1的内核中试了一下好像不行。Lvs把包固定发给了rs1这台机器,估计rs1arp reply响应最快。
1.3.3. 安装ipvsadm
这是一个IPVS的管理工具,提供了一个和IPVS打交道的接口,包括配置IPVS和连接信息统计。到地址:http:
//去下载相应的版本。对于2.6.8.1内核,下了
ipvsadm-1.24-5.src.rpm。
rpm ipvsadm的存放路径/ipvsadm-1.24-5.src.rpm
cd /usr/src/rpm/SOURCE/
tar –zxvf ipvsadm-1.24.tar.gz
cd ipvsadm-1.24
make ; make install
然后:
ipvsadm,如果出现以下提示说明已经安装成功。
IP Virtual Server version 1.2.0 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
ipvsadm的具体用法可参考 man ipvsadm.
1.3.4. Ipvsadm的配置
根据/mini-HOWTO/LVS-mini-HOWTO.html4
节和5结节的说明,Ipvsadm的配置可以用官方的配置脚本配置,配置脚本可在下载,也可
以手工敲入命令配置。
官方的脚本使用perl写的,配置脚本的命令为包中文件名为cofigure的文件, 包中的lvs_dr.conf.one_NIC_one_network等文件是一些配置信息,作为configure的参数传入.下面这个命令对应两台 real server的配置, 需要自己修改lvs_dr.conf.one_NIC_two_network中的信息.
./configure lvs_dr.conf.one_NIC_two_network
不过本人试了一下自动配置没有成功,就手工配置了.读者有兴趣可自行研究如何使用官方配置脚本配置。
1.3.4.1. DR的配置
对于前台负载均衡服务器Direcrt Server(DR)的配置,我自己做一个配置脚本 config_vs.sh。里面的参数请自己替换。
#/bin/sh
#file: config_vs.sh 这里默认使用网卡eth0,如果想用其它网卡请自行替换即可。
VIP=172.30.31.200 #DR的虚拟服务IP
DIP=172.30.31.68 #DR的eth0真实地址
RS1=172.30.31.66 #real server1的真实地址
RS2=172.30.31.67 #real server2的真实地址
GW=172.30.31.1 #DR使用的网关或路由的地址
SERVICE=22 #你的服务端口
cat /proc/sys/net/ipv4/ip_forward #脚本调试信息
echo "0" >/proc/sys/net/ipv4/ip_forward
echo "1" >/proc/sys/net/ipv4/conf/all/send_redirects #脚本调试信息
cat /proc/sys/net/ipv4/conf/all/send_redirects #脚本调试信息
echo "1" >/proc/sys/net/ipv4/conf/default/send_redirects
cat /proc/sys/net/ipv4/conf/default/send_redirects#脚本调试信息
echo "1" >/proc/sys/net/ipv4/conf/eth0/send_redirects
cat /proc/sys/net/ipv4/conf/eth0/send_redirects #脚本调试信息
/sbin/ifconfig eth0 ${DIP} #配置所使用的网卡IP
#配置虚拟服务IP
/sbin/ifconfig eth0:0 ${VIP} broadcast ${VIP} netmask 255.255.255.255
/sbin/route add -host ${VIP} dev eth0:0 #添加虚拟IP的路由
/sbin/route add default gw ${GW} #添加本地路由
/sbin/ifconfig eth0:0 #脚本调试信息, 显示虚拟IP配置
#/bin/ping -b ${VIP} #脚本调试信息, 看看虚拟IP是否可以ping通
/sbin/route -n #脚本调试信息,显示路由信息
/sbin/ipvsadm –C #清除虚拟服务器表,也就是清除IPVS的原配置
#添加服务及轮调调度算法,-t:tcp服务,-A:添加服务; -s rr:指定调度算法为轮调
/sbin/ipvsadm -A -t ${VIP}:${SERVICE} -s rr
#添加real server, -a:添加一台RS, -t:tcp服务,-r: RS的地址,-g:直接路由模式。
#这里语句个数随real server的个数而定
/sbin/ipvsadm -a -t ${VIP}:${SERVICE} -r ${RS1} -g
/sbin/ipvsadm -a -t ${VIP}:${SERVICE} -r ${RS2} -g
ping -c 1 ${RS1} #脚本调试信息
ping -c 1 ${RS2} #脚本调试信息
/sbin/ipvsadm #脚本调试信息
#end of config_vs.sh
补:由于DR是个单点,为了保证高可用幸,我们使用了开源包Heartbeat来保证。所以有两台DR,一台为主,一台为辅。各自都可用这个脚本来配置,不过DIP要该成各自的真实地址,其它选项必须完全相同。
1.3.4.2. RS的配置
对于real server(RS)的配置,我自己做一个配置脚本 config_rs.sh。里面的参数请自己替换。
#/bin/sh
#file: config_rs.sh这里默认使用网卡eth0,如果想用其它网卡请自行替换即可。
VIP=172.30.31.200 #DR的虚拟服务IP
#DR的eth0真实地址,作用是在配置时测试DR的IP是否有效。但是DR切换后,DIP变了,所以这项取消了。
#DIP=172.30.31.68
LOCALIP=172.30.31.66 #real server1的真实地址
GW=172.30.31.1 #real server使用的网关或路由的地址
/sbin/ifconfig eth0 ${LOCALIP} #配置eth0的本地IP
/sbin/route add default gw ${GW} #添加默认路由
/bin/netstat -rn #脚本调试信息
ping -c 1 ${GW} #脚本调试信息,是否可以ping通网关
echo "0" >/proc/sys/net/ipv4/ip_forward
cat /proc/sys/net/ipv4/ip_forward #脚本调试信息,ip_forward是否配置正确
ping -c 1 ${DIP} #脚本调试信息, 是否可以ping通DR的真实地址
ping –c 1 ${VIP} #是否可以ping通虚拟DR的IP
#按照real server的虚拟IP
/sbin/ifconfig lo:0 ${VIP} broadcast ${VIP} netmask 0xffffffff up
#配置出口
/sbin/ifconfig lo:0
#在lo:0上添加去虚拟IP的路由
/sbin/route add -host ${VIP} dev lo:0
/bin/netstat -rn #脚本调试信息
echo "1" >/proc/sys/net/ipv4/conf/all/hidden
cat /proc/sys/net/ipv4/conf/all/hidden #脚本调试信息
echo "1" >/proc/sys/net/ipv4/conf/lo/hidden
cat /proc/sys/net/ipv4/conf/lo/hidden #脚本调试信息
#end of config_rs.sh
不同real server配置时只要改变LOCALIP选项就可以了。我只添加了172.30.31.66(real server 1)和172.30.31.67(real server 2)两台机器。DR的主节点名称为heatbeat1,副节点名称为heartbeat2
1.4. 试运行结果
安装上面的说明走完所有的步骤后,我用ssh测试了一下。奇数次去了172.30.31.66这台机器,偶数次去了172.30.31.67这台机器
2. heartbeat
2.1. heartbeat的介绍
这里的heartbeat就是linux-ha项目,被许多高可用系统采用。我们这里lvs必须是个高可用系统,所以我们采用heartbeat。 本文也以 lvs作为高可用服务来说明heartbeat的使用。Heartbeat的高版本可以负责3个及以上的节点。本文2个节点来说明,在你的两台机器(一台 作为主节点,另一台为从节点)上运行heartbeat, 并配置好相关的选项,最重要的是lvs资源一定要配置进去。那么开始时主节点提供lvs服务,一旦主节点崩溃,那么从节点立即接管lvs服务。如果是自己 开启了其它的服务资源,那么接管的时候,该服务资源相应的tcp连接必须重连,而且主从节点的应用层逻辑状态有应用层自己保证一致。Lvs不存在应用层的 逻辑状态。
具体介绍请参考:
2.2. libnet的安装
安装heatbeat前必须先安装libnet包,请到地
址下载。libnet提供了一些高层的api,让应用程序开发者可以修改网络包。我下的包为libnet.tar.gz,版本为1.1.2.1
cd 存放路径
tar –zxvf libnet.tar.gz
cd libnet
./configure; make ; make install
2.3. heartbeat的安装
到下载相应的版本,对于2.6.8.1我下载了最新的稳定版本 heartbeat-2.0.2.tar.gz。
cd 存放路径
tar –zxvf heartbeat-2.0.2.tar.gz
cd heartbeat-2.0.2
./Configureme configure
make ; make install
上述步骤完成后,heartbeat的运行程序文件为/etc/rc.d/heartbeat。并且出现/etc/ha.d目录。
2.4. heartbeat的配置
heartbeat的配置信息非常复杂,但是最关键也就是那么几项。如果你要自己弄懂所有配置选项,那么自己参 考:ConfiguringHeartbeat中的文档,特别是《Getting Started with Linux-HA(heartbeat)》文档。
这里需要配置文件有三个:ha.cf、haresources、authkeys。这三个配置文件需要在/etc/ha.d目录下面,但是默认是没有这三个文件的,所以你要
copy存放路径/ heartbeat-2.0.2/doc/ha.cf /etc/ha.d/
copy存放路径/ heartbeat-2.0.2/doc/ haresources /etc/ha.d/
copy存放路径/ heartbeat-2.0.2/doc/ authkeys /etc/ha.d/
2.4.1. authkeys
这个配置文件非常简单,就是在auth选择一个值。每个值对应一种算法,这个算法是在主节点和从节点间数据校验用的。这个配置文件权限必须是0600。
Chmod 0600 authkeys
自己选一种算法。我选md5。
配置文件的值如下:
auth 3
#1 crc
#2 sha1 HI!
3 md5 Hello!
2.4.2. haresources
这个文件配置的是节点要管理的资源也就你的高可用服务,这些资源在主节点down调时候,从节点就会开启这些资源。Heartbeat认为
你配置资源名称 start/stop
就可以开启/停止这些资源。所以让你的资源支持start/stop。其实这你只需要对你的应用服务作个脚本,脚本接受start参数就会启动应用 服务,接受stop参数就会停止服务。个人建议,你什么都不要做,就把应用程序名当作资源名就可以了,启动资源名的时候就自动启动你的服务了。而在 down机的时候,所有的程序都死了,根本就不需要heartbeat调用
你配置资源名称stop
命令来结束程序。
在文件中找到:
#node1 10.0.0.170 Filesystem::/dev/sda1::/data1::ext2
这一项,去掉#号,根据格式配置你的资源。第一字段(Node1):主节点名称(必须uname –n的保持一致);第二字段(10.0.0.170):对外虚拟服务IP;第三字段(Filesystem::/dev/sda1::/data1:: ext2):Filesystem表示资源名称,/dev/sda1表示资源启动时的第一个参数,/data1表示第二个参数,/ext2表示第三个参 数,依此类推。我们的lvs的配置如下所示:
heartbeat1 172.30.27.200 config_vs.sh
heartbeat1是主节点的名称。172.30.27.200是对外服务的虚拟IP,也是lvs对外服务的虚拟IP。Config_vs.sh是资源名称,因为这个就是DR的配置文件脚本,只要执行过这个脚本那么机器就变成DR了。
2.4.3. ha.cf
这个配置文件比较复杂。我只配了关键的几项:
debugfile /var/log/ha-debug
说明:调试日志文件文件,取默认值
logfile /var/log/ha-log
说明:系统运行日志文件,取默认值
logfacility local0
说明:日志等级,取默认值
keepalive 1
说明:心跳频率,自己设定。1:表示1秒;200ms:表示200毫秒
deadtime 10
说明:节点死亡时间阀值,就是从节点在过了10后还没有收到心跳就认为主节点死亡,自己设定
warntime 5
说明:发出警告时间,自己设定
udpport 28855
说明:心跳信息传递的udp端口,自己设定
#bcast eth0 # Linux
说明:采用udp广播播来通知心跳,建议在副节点不只一台时使用
ucast eth0 172.30.31.68
说明:采用网卡eth0的udp单播来通知心跳,eth0的IP
#mcast eth0 225.0.0.1 694 1 0
说明:采用udp多播播来通知心跳,建议在副节点不只一台时使用
auto_failback off
说明:主节点重启成功后,资源是自动拿回到主节点还是等到副节点down调后拿回资源
node heartbeat1
说明:主节点名称,与uname –n保持一致。排在第一的默认为主节点,所以不要搞措顺序
node heartbeat2
说明:副节点名称,与uname –n保持一致
watchdog /dev/watchdog
说明:看门狗。如果本节点在超过一分钟后还没有发出心跳,那么本节点自动重启
以上这些是我个人认为必配项,下面这些是可选项。
stonith baytech /etc/ha.d/conf/stonith.baytech
说明:主/副等所有节点的一种校验。
respawn userid /path/name/to/run
说明:和heartbeat必须一起启动的本地服务
ping 10.10.10.254
说明:伪节点IP,伪节点就是其失效时主/副节点不会正常工作但本身不是主/副节点之一。
respawn hacluster /usr/lib/heartbeat/ipfail
说明:与ping选项一起使用,取默认值。
baud 19200
说明:串口波特率,与serial一起使用。
serial /dev/ttyS0 # Linux
说明:采用串口来传递心跳信息。
2.5. 运行结果
在主节点heartbeat1(172.30.31.68)和副节点heartbeat2(172.30.31.69)启动heatbeat
/etc/rc.d/heartbeat start
这时,我用ssh登录172.30.31.200,第一次登录进17230.31.66,第二次则17230.31.67,第三次17230.31.66. 在主节点输入ipvsadm,显示
IP Virtual Server version 1.2.0 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 172.30.31.200:ssh rr
-> 172.30.31.67:ssh Route 1 1 1
-> 172.30.31.66:ssh Route 1 2 0
这时,reboot 主节点172.30.31.68, 那么以前的连接失效, 副节点172.30.31.69::/var/log/ha-log中显示主节点死亡,然后本节点接管资源. 这时再用ssh登录172.30.31.200,依然可以.只是所有的登录已经通过副节点转发.