在日常的使用中,一台服务器足够胜任很多的工作,但是当很多人同时访问的时候就会显得稍有些无力,这个时候。可以有两种解决的方法,第一种是不断的改善这台服务器的性能,但是总是会有一个上限存在,而且提升的效果并不明显。另外一种方法就是使用多台服务器,来均摊需要处理的任务,这就是集群,通过一定的组合方式,将很多功能一样的服务器祖喝道一起,但是使用时感受不到他们的差异。组合的方式目前有四种,分别是lvs-nat、lvs-dr、lvs-tunnel和热心网友提供的lvs-fullnat,在Linux内核中仅支持前三种,最后一种如果想要使用需要自己重新编译内核。在开始介绍之前我们需要了解几个常用术语:
<code>vs:virtual server,构成集群的调度器(中心节点)</code>
<code>rs:real server,用户只能找到vs,但是真正提供服务的是rs</code>
<code>CIP:Client IP,客户端的IP地址,即请求发送方的IP地址</code>
<code>VIP:Virtual Server IP,,虚拟服务器的虚拟IP地址,客户端访问的目的地址</code>
<code>DIP:Director IP,调度器IP地址,向后方Real Server转发客户端请求时使用的IP地址</code>
<code>RIP:Real Server IP,后方真实服务器的IP地址</code>
简单来说就是当用户访问服务器的时候首先访问到的是调度器,然后由调度器查看有哪一台集群中的服务器是相对空闲,那么就将请求送到这一台服务器上进行处理。用户的地址叫做CIP,用户访问的地址叫做VIP,调度器上用于访问集群的地址叫做DIP,集群中各个服务器的地址叫做RIP。下面开始依次介绍各种集群方式。
一、lvs-nat
这种方式构建集群的架构如图所示:
<a href="https://s4.51cto.com/oss/201710/21/06f5c94b6eb77ac14d53f352eeb14ed3.png-wh_500x0-wm_3-wmp_4-s_3303131388.png" target="_blank"></a>
首先由客户端的CIP发起请求,由调度器分发到后端服务器上进行处理,在处理之后返回处理结果。具体是哪个主机由调度器根据算法进行选择,根据lvs在调度时是否考虑各RS当前的负载状态,可以将调度算法分为两类,分别是静态算法和动态算法,静态算法是事先就将分配的过程安排好,而动态算法是在实时的处理过程中根据服务器的忙碌程度进行分配。(每种架构方式使用的基本都是如下算法,后边不再重复说明)
静态算法,根据算法本身的特点进行调度,注重起点公平,包括以下几种:
<code>RR:RoundRobin,轮询(一人一个任务,但是有的服务器性能好,有的差,所以这种分配方式不太好)</code>
<code>WRR:Weighted RR,加权轮询(有额外的权重干扰分配结果)(能力越大责任越大)(权重高,代表工作能力强,就会被多分配任务)</code>
<code>SH:Source Hashing,源地址哈希,将来自于同一个IP地址的请求始终发往后端第一次被挑中的RS,从而可以实现会话绑定,例如购物等操作,最好要保持在同一台服务器上</code>
<code>DH:Destination Hashing,目的地址哈希,将发往同一个目标地址的请求,始终发送至后端第一次被挑中的RS,一般用于正向代理服务器集群</code>
动态算法,主要根据每个RS当前的负载状态进度调度,注重结果公平,包括以下几种:
(后端RS的负载情况,用Overhead表示,使用这个变量可以来实时的观测任务最好分配给哪台服务器,通过active connection(活动的连接数)和inavtive connection(不活动的连接数)来进行计算)
<code>LC:least connections,最少连接数</code>
计算公式:Overhead=activeconnections*256+inactiveconnections
注意:第一次调度时,按照在ipvsadm中配置的顺序自上而下进行分配
<code>WLC:Weighted LC,加权最小连接(如果在部署时未指定,默认为这个)</code>
计算公式:Overhead=(activeconnections*256+inactiveconnections)/weight
注意:第一次调度时,按照在ipvsadm中配置的顺序自上而下进行分配,权重在第一次调度时不发挥作用
<code>SED:Shortest Expection Delay,最短期望延迟</code>
计算公式:Overhead=(activeconnections+1)*256/weight
注意:SED可以解决起点不公平的问题,但是在权重差距比较大时,可能会导致不公平
例如:weight一个1,一个10,那么为10的会连续获得多个任务
<code>NQ:Never Queue,改进版的SED算法,首次调度时,根据后端RS的权重依次为每台RS分配一个连接;然后再按照SED算法调度;必然会保证后端每台RS至少有一个 activeconnection;</code>
<code>LBLC:Locality-Based Least Connections:基于本地的最少连接,动态的DH算法</code>
<code>LBLCR:LBLC with Replication,带有复制功能的LBLC</code>
集群部署时最难的是理解架构方式,在理解了之后,部署是十分简单的,在lvs-nat的方式下,我们只需要将各个网段设置好,使相同网段之间能够ping通即可,然后在调度器上使用“ipvsadm”命令(在内核中有ipvs,是实现集群的功能,主要工作在INPUT链上,ipvs(INPUT):内核中的TCP/IP协议栈上的组件,而ipvsadm用来编写规则送给ipvs(类似于防火墙的iptables软件的功能,是用户空间中的用于编写ipvs规则的组件)查看内核中是否支持ipvs功能:~]# grep -i -C 10 "ipvs" /boot/config*):
<code>ipvsadm:</code>
<code> </code><code>格式:</code>
<code> </code><code>ipvsadm -A|E -t|u|f service-address [-s scheduler] [-p [timeout]]</code>
<code> </code><code>ipvsadm -D -t|u|f service-address</code>
<code> </code><code>ipvsadm -C</code>
<code> </code><code>ipvsadm -R</code>
<code> </code><code>ipvsadm -S [-n]</code>
<code> </code><code>ipvsadm -a|e -t|u|f service-address -r server-address [-g|i|m] [-w weight]</code>
<code> </code><code>ipvsadm -d -t|u|f service-address -r server-address</code>
<code> </code><code>ipvsadm -L|l [options]</code>
<code> </code><code>ipvsadm -Z [-t|u|f service-address]</code>
<code> </code><code>ipvsadm --</code><code>set</code> <code>tcp tcpfin udp</code>
<code> </code><code>ipvsadm --start-daemon state [--mcast-interface interface]</code>
<code> </code><code>[--syncid syncid]</code>
<code> </code><code>ipvsadm --stop-daemon state</code>
<code> </code><code>ipvsadm -h</code>
<code>管理集群服务:增,删,改(对集群整体的处理)</code>
<code> </code><code>增加lvs集群服务:ipvsadm -A -t|u|f service-address [-s scheduler] [-p [timeout]]</code>
<code> </code><code>-t:基于TCP协议的集群服务</code>
<code> </code><code>service-address:与VIP绑定的套接字</code>
<code> </code><code>-u:基于UDP服务的集群服务</code>
<code> </code><code>-f:基于防火墙协议(FWM—Firewall mark,防火墙标记)的集群服务</code>
<code> </code><code>通过iptables的mangle表对数据设置的标记</code>
<code> </code><code>-s:指定集群服务的调度算法(如果省略,默认是wlc)</code>
<code> </code><code>-p:是否开启持久连接</code>
<code> </code><code>修改lvs集群服务:ipvsadm -E -t|u|f service-address [-s scheduler] [-p [timeout]]</code>
<code> </code><code>参数和增加类似</code>
<code> </code><code>删除lvs集群服务:ipvsadm -D -t|u|f service-address</code>
<code> </code><code>清除lvs集群服务:ipvsadm -C(类似于iptables的“-F”)(最好不要轻易的使用)</code>
<code>管理集群中的RS:增,删,改(这是对集群中的哪些服务器进行处理的命令)</code>
<code> </code><code>在集群中添加RS:ipvsadm -a -t|u|f service-address -r server-address [-g|i|m] [-w weight]</code>
<code> </code><code>-r:指定要添加到集群中的后端RS的IP地址和端口</code>
<code> </code><code>-g:选择集群类型为DR(默认值)</code>
<code> </code><code>-i:选择集群类型为TUN</code>
<code> </code><code>-m:选择集群的类型为NAT</code>
<code> </code><code>-w:为RS(Real Server)设定的权重(不要设定的悬殊过大,否则分配会不当)</code>
<code> </code><code>修改集群中的RS:ipvsadm -e -t|u|f service-address -r server-address [-g|i|m] [-w weight]</code>
<code> </code><code>从集群中删除的RS:ipvsadm -d -t|u|f service-address -r server-address</code>
<code>查看lvs集群状态及属性信息:</code>
<code> </code><code>ipvsadm -L|l [options]:</code>
<code> </code><code>options包括:</code>
<code> </code><code>-c, --connection:查看当前的ipvs中的各种连接的状态</code>
<code> </code><code>--stats:显示lvs集群的统计数据信息</code>
<code> </code><code>--rate:显示lvs集群与传输速率有关的内容</code>
<code> </code><code>--timeout:显示TCP、TCP的FIN标志位及UDP会话的超时时长</code>
<code>保存和重载ipvs的规则(两种方法都可以):</code>
<code> </code><code>保存:</code>
<code>ipvsadm -S [-n](只是显示出来并不是保存,需要重定向,自己保存) > </code><code>/PATH/TO/IPVS_RULE_FILE</code>
<code>ipvsadm-save > </code><code>/PATH/TO/IPVS_RULE_FILE</code>
<code> </code><code>重载:</code>
<code>ipvsadm -R < </code><code>/PATH/TO/IPVS_RULE_FILE</code>
<code>ipvsadm-restore < </code><code>/PATH/TO/IPVS_RULE_FILE</code>
<code> </code><code>保存规则并于开机时自动载入:</code>
<code> </code><code>CentOS 6-:</code>
<code> </code><code># chkconfig ipvsadm on</code>
<code> </code><code>将规则保存至:</code><code>/etc/sysconfig/ipvsadm</code>
<code> </code><code>CentOS 7:</code>
<code> </code><code># systemctl enable ipvsadm.service</code>
<code>清空计数器(当想要重置的时候可以清空计数器):</code>
<code> </code><code>ipvsadm -Z [-t|u|f service-address]</code>
<code> </code><code>后头如果没参数则清空所有的计数器</code>
在了解了命令之后,我们就可以开始部署lvs-nat集群了,首先按照图中所示,配置好相应的IP,并在调度器上使用以下命令:
<code>~]</code><code># yum install ipvsadm -y #安装管理软件ipvsadm</code>
<code>~]</code><code># ipvsadm -A -t 172.15.0.2:80 -s rr #创建一个集群服务</code>
<code>~]</code><code># ipvsadm -a -t 172.15.0.2:80 -r 172.16.128.18:80 -m -w 1</code>
<code> </code><code>#在刚才创建的集群中添加一台服务器,“-m”指定为NAT方式</code>
<code>~]</code><code># ipvsadm -a -t 172.15.0.2:80 -r 172.16.128.19:80 -m -w 2</code>
<code> </code><code>#在刚才创建的集群中添加一台服务器,“-w”指定权重(在NAT中权重没用,但是先写上,后边会用)</code>
然后在RS上安装httpd服务(所有服务器上都要安装)(默认是已经安装完的):
<code>~]</code><code># yum install httpd -y</code>
<code>~]</code><code># route add default gw 172.16.128.17 #并指定网关,否则即使服务转到服务器上也回不去</code>
<code>~]</code><code># echo "This is 172.16.128.18" > /var/www/html/index.html 在172.16.128.18上执行</code>
<code>~]</code><code># echo "This is 172.16.128.19" > /var/www/html/index.html 在172.16.128.19上执行</code>
最后将服务都开启:
<code>~]</code><code># service httpd start #CentOS 6 上</code>
回到调度器上进行验证:
<a href="https://s3.51cto.com/oss/201710/21/76a6ada70f6b8731b0c31eb3f5eac9e2.png-wh_500x0-wm_3-wmp_4-s_2781817197.png" target="_blank"></a>
验证通过之后,在调度器上开启转发功能:
<code>~]</code><code># echo 1 > /proc/sys/net/ipv4/ip_forward</code>
这样,lvs-nat集群就配置完成了,我们可以在作为客户端的主机上通过命令来进行查看:
<code> </code><code>~]</code><code># for i in {1..10} ; do curl http://172.15.0.2 ; done #使用循环的方式连续访问10次</code>
<a href="https://s3.51cto.com/oss/201710/21/ecd2a118f9a70b5419d0dd4d2a1fa567.png-wh_500x0-wm_3-wmp_4-s_3451384316.png" target="_blank"></a>
从图中我们可以看出,调度器安装轮询的方式,一次访问172.16.128.19,一次访问172.16.128.18,此时我设置的是两个不同的网页,如果两个相同,那么在用户使用的时候就看不出差距,就可以实现任务均摊,来减轻服务器的负担。
然后,我们可以更换一个算法,改为wlc算法:
<code>~]</code><code># ipvsadm -E -t 172.15.0.2:80 -s wlc</code>
再使用上面的方式进行查看发现,两台服务器的工作分配方式变成了2比1,这是因为在上面添加服务器的时候172.16.128.18的权重为1,而172.16.128.19的权重为2:
<a href="https://s1.51cto.com/oss/201710/21/de01b7d83dbe69ea864db3d7b61f5956.png-wh_500x0-wm_3-wmp_4-s_2373958296.png" target="_blank"></a>
二、lvs-dr
lvs-dr的配置相对于lvs-nat来说减轻了调度器的工作压力,如果是lvs-nat方式,那么不管是进入集群的数据包还是从集群中出来的数据包都要经过调度器进行分发,那么调度器就是这个集群的效率瓶颈,如果调度器不够好,集群的工作效率就会大打折扣。所以lvs-dr模型减轻了调度器的工作压力,只有进入集群的数据包才会经过调度器,而从集群中出来的数据包直接由服务器发送回客户端。不过这样又会遇到一个问题,就是IP地址的问题,如果直接从服务器进行发送,那么源地址就不是客户端请求的地址,客户端就会禁止这种数据包,所以lvs-dr模型通过伪装用户访问的IP地址来实现集群。架构的方式如图所示(客户端的IP现实中不会是这个,在这里只是为了进行简单的验证)(如果做过上面lvs-nat的实验,主机IP等配置需要重置):
<a href="https://s4.51cto.com/oss/201710/21/75c58b1b2a0697c07707235141f207f7.png-wh_500x0-wm_3-wmp_4-s_2342196951.png" target="_blank"></a>
此时的客户端可以和上图中所有的IP进行通信:
<a href="https://s1.51cto.com/oss/201710/21/3dfb9fb91e3a988be29838308f086cc0.png-wh_500x0-wm_3-wmp_4-s_4210366236.png" target="_blank"></a>
在DR模型中,各个主机均需要配置VIP;解决地址冲突的方法通常有三种:
1.在前端网关上静态绑定VIP和MAC;
2.在各个RS中使用arptables进行arp报文的过滤;
3.在各个RS中修改对应的内核参数,来限制ARP的通告和应答的级别;
在内核中通过更改下面两个值可以达到相应的效果:
<code>arp_ignore:</code>
<code>0:默认值,对于从任何网络接口接收到对本机任意IP地址的ARP查询请求均予以回应;</code>
<code>1:只应答目标IP地址是入站接口上配置的IP地址所在网段的IP地址的ARP请求;</code>
<code>2:只应答目标IP地址是入站接口上配置的IP地址所在网段的IP地址的ARP请求,且来访IP地址也必须与该接口的IP地址在同一子网中;</code>
<code>3:不响应该网络接口的ARP请求,而只对设置为全局的IP地址做应答;</code>
<code>4-7:保留;</code>
<code>8:不应答所有的ARP请求;</code>
<code>arp_announce:</code>
<code>0:默认值,将本机所有接口的信息向所有接口所连接的网络中通告;</code>
<code>1:尽量避免向与本接口不同网络中的其他接口通告;</code>
<code>2:绝对避免向非本网络的主机通告;</code>
在两台服务器上都运行下面的命令:
<code>echo</code> <code>1 > </code><code>/proc/sys/net/ipv4/conf/all/arp_ignore</code> <code>#设置所有接口(在所有中包含lo接口)</code>
<code>echo</code> <code>1 > </code><code>/proc/sys/net/ipv4/conf/lo/arp_ignore</code> <code>#设置lo接口(为了安全起见,在lo接口上再设置一次)</code>
<code>echo</code> <code>2 > </code><code>/proc/sys/net/ipv4/conf/all/arp_announce</code>
<code>echo</code> <code>2 > </code><code>/proc/sys/net/ipv4/conf/lo/arp_announce</code>
<code>ifconfig</code> <code>lo:0 172.16.128.128 netmask 255.255.255.255 broadcast 172.16.128.128 up</code>
<code>route add -host 172.16.128.128 dev lo:0</code>
这样,在服务器上的配置就完成了,然后还是像lvs-nat一样将httpd服务开启,并设置主页,之后回到调度器上执行命令:
<code>~]</code><code># ifconfig eth0:0 172.16.128.128 netmask 255.255.255.255 broadcast 172.16.128.128 up</code>
<code>~]</code><code># ipvsadm -C #情空规则</code>
<code>~]</code><code># ipvsadm -A -t 172.16.128.128:80 -s rr #添加集群</code>
<code>~]</code><code># ipvsadm -a -t 172.16.128.128:80 -r 172.16.128.18 -g -w 1 #向集群中添加服务器</code>
<code>~]</code><code># ipvsadm -a -t 172.16.128.128:80 -r 172.16.128.19 -g -w 3 #添加几个,就写几个</code>
<code> </code><code>“-g”选项是选择集群类型为DR,不写也可以,因为默认就是这个</code>
到此,lvs-dr模型就配置好了,可以到客户端(172.16.128.17)上使用命令进行查看:
<code>~]</code><code># for i in {1..10} ; do curl http://172.16.128.128 ; done</code>
<a href="https://s2.51cto.com/oss/201710/21/7a65e02163d66680f73ade024690d85d.png-wh_500x0-wm_3-wmp_4-s_3269935146.png" target="_blank"></a>
更改算法的方式和lvs-nat一样。
三、基于标记的转发
上面是两种架构的方式,接下来要说一说基于标记的转发方式,可以使用任何一个架构方式。通过防火墙的mangle表的PREROUTING链来对访问调度器的数据包进行标记,例如访问80端口就给其标记为6,然后在配置集群的时候就可以使用这个标记来进行分配。这样的方式相对于其他的方法更为灵活。配置的方法是首先使用iptables进行标记:
<code>iptables -t mangle -F </code><code>#清空规则,目的是防止其他规则的影响,可以不用执行</code>
<code>iptables -t mangle -A PREROUTING -d 172.16.128.128 -p tcp --dport 80 -j MARK --</code><code>set</code><code>-mark 6</code>
然后使用ipvsadm命令基于标记进行服务器调度:
<code>ipvsadm -C</code>
<code>ipvsadm -A -f 6 -s rr </code><code>#“-f”后跟的是标记的记号,根据上头设定的记号进行修改</code>
<code>ipvsadm -a -f 6 -r 172.16.128.18:80 -g -w 1</code>
<code>ipvsadm -a -f 6 -r 172.16.128.19:80 -g -w 3</code>
上面的命令都是在调度器上进行配置,服务器不用管,下面使用客户端查看
四、长连接
在上面的基础上,在调度器上使用下面这条命令:
<code>~]</code><code># ipvsadm -E -f 6 -s wrr -p</code>
这条命令的作用是构建长连接,即如果一个客户端连接了集群中的服务器之后,那么在“-p”选项后指定的时间(默认360秒)之内访问还是这个服务器。
如图所示,在调度器上使用这个命令:
<a href="https://s4.51cto.com/oss/201710/21/f2e6e35b243c7ef9a9f34eefb8d98c6d.png-wh_500x0-wm_3-wmp_4-s_3958481770.png" target="_blank"></a>
最后就可以在客户端上重复连接10次,可以发现10次都是连接的同一个服务器:
<a href="https://s4.51cto.com/oss/201710/21/b8c92dd8c41fe18109265e4f04a63424.png-wh_500x0-wm_3-wmp_4-s_4231710900.png" target="_blank"></a>
如果换一个主机,就会是另外一个服务器了(根据算法进行选择)
本文转自正经的青年51CTO博客,原文链接: http://blog.51cto.com/11142243/1974868,如需转载请自行联系原作者