一、LVS简介
LVS即Linux Virtual Server的缩写,意思为Linux的虚拟服务器,是一个四层负载均衡技术的开源项目。
Linux内核从2.6.10版本之后就集成了LVS,之前的内核版本可以通过打补丁的方式安装。
LVS工作需要基于内核的Netfilter,其主要工作INPUT链上。
二、LVS几个重要概念
(一)负载调度算法
负载调度是实现在内核中,调度是以连接为粒度。LVS实现了10种静态算法和动态算法,如下:
静态算法:
-
轮叫调度(Round-Robin Scheduling)
-
加权轮叫调度(Weighted Round-Robin Scheduling)
-
源地址散列调度(Source Hashing Scheduling)
-
目标地址散列调度(Destination Hashing Scheduling)
动态算法:
-
最小连接调度(Least-Connection Scheduling)
-
加权最小连接调度(Weighted Least-Connection Scheduling)
-
最短预期延时调度(Shortest Expected Delay Scheduling)
-
不排队调度(Never Queue Scheduling)
-
基于局部性的最少链接(Locality-Based Least Connections Scheduling)
-
带复制的基于局部性最少链接(Locality-Based Least Connections with Replication Scheduling)
下面就以上算法做一个说明:
1、轮叫调度rr(Round-Robin Scheduling)
最为简单的调度算法,实现无状态的调度,也就是轮询。
挑选算法为i = (i + 1) mod n
不适用于服务器组中性能不一致的情况
不适用于请求服务时间较大的情况
不适用于使用session的站点
注:如果权重为0,则不调度。之后的所有算法都支持该规则。
2、加权轮叫调度wrr(Weighted Round-Robin Scheduling)
根据不同权重,分配较多的连接到权重大的服务器上。
算法在RR轮询调度的基础上,算出所有服务器权重的最大公约数,使用服务器最大权重和这个公约数求差求得一个调度权重,然后服务器自身权重大于这个调度权重的就可以被调度。
3、源地址散列调度(Source Hashing Scheduling)
它是针对请求的源IP地址的负载均衡,是一种静态映射算法。将源地址IP求hash值后,映射到一台服务器。以后该目标地址访问将始终使用该服务器。直到该服务器权重为0,或者超载的情况下,将重新调度到另一台服务器。
它将来自同一IP的请求尽可能的指向同一台服务器处理,这可以实现Session绑定效果。
算法中使用一个Hash表,使用源IP地址的Hash值作为key,value指向的服务器IP地址。
4、目标地址散列调度(Destination Hashing Scheduling)
它是针对目标IP地址的负载均衡,是一种静态映射算法。将目标地址IP求hash值后,映射到一台服务器。以后该目标地址访问将始终使用该服务器。直到该服务器权重为0,或者超载的情况下,将重新调度到另一台服务器。
在实际应用中,源地址散列调度和目标地址散列调度可以结合使用在防火墙集群中,它们可以保证整个系统的唯一出入口。
算法中使用一个Hash表,使用目标服务器IP地址的Hash值作为key,value中的值就是指向的服务器IP地址。
5、最小连接调度(Least-Connection Scheduling)
把新的连接请求分配到当前连接数最小的服务器。
调度器记录各个服务器的连接数,它很好的把负载分配到负载较少的服务器上。但是如果服务器性能有差异,性能好的服务器处理完请求后,处于TIME_WAIT状态的连接还占用这资源,也还算做连接数,所以此时负载还是会调度到性能差的服务器上。
overhead = (activeconns<<8) + inactconns,这相当于(activeconns*256) + inactconns
调度到overhead最小的服务器上。
注:算法取自ip_vs_lc_dest_overhead函数。
6、加权最小连接调度(Weighted Least-Connection Scheduling)
它是LC的超集。使用权重值后,算法调度新建连接尽可能保证已建立的连接和其权重成正比。
overhead = activeconns*50 + inactconns
load = overhead / weight
然后比较load的大小,取load最小的
注:算法取自ip_vs_wlc_schedule函数
7、最短预期延时调度(Shortest Expected Delay Scheduling)
server expected overhead = activeconns + 1
(server expected overhead) / weight
保证优先从权重大的服务器开始建立连接,+1是解决了起点公平,同时+1对权重小的SED值影响大,这也使得算法计算结果倾向选择权重大的服务器。此算法不使用非活动连接数。
注:算法取自ip_vs_sed_dest_overhead
8、不排队调度(Never Queue Scheduling)
SED算法的改进。
算法中保证,如果发现有一个空闲的服务器,就立即返回这个服务器给调度器使用。
如果存在空闲服务器,请求将不在性能最好的服务器后排队,而是被调度到空闲的服务器上。
如果不存在空闲的服务器,请求将被发送到最小期望延时的服务器上。
9、基于局部性的最少链接(Locality-Based Least Connections Scheduling)
它是针对请求报文的目标IP地址的负载均衡调度,目前主要用于Cache集群系统。
10、带复制的基于局部性最少链接(Locality-Based Least Connections with Replication Scheduling)
它也是针对目标IP地址的负载均衡,目前主要用于Cache集群系统。它与LBLC算法的不同之处是它要维护从一个目标IP地址到一组服务器的映射,而LBLC算法维护从一个目标IP地址到一台服务器的映射。
(二)LVS的实现模型
VS/NAT
基于NAT实现的虚拟服务器。
数据通过均衡器后,其数据报文中目标地址(VIP)或者端口将被映射为指定的IP地址(RIP)或端口,然后指定的IP地址或端口的服务器处理完客户请求后,返回给数据报文给均衡器,均衡器根据以前的记录,将响应报文的源地址或端口改回均衡器响应请求时的VIP或端口。
基于NAT技术,实现简单,对于客户端来说整个机器架构是透明的,这很好的隐藏了内部网络主机,同时节约了IP V4的地址。
请求报文和响应报文进出都要经过均衡器,而且均衡器还要修改报文,这势必会使得均衡器称为系统性能的瓶颈。
VS/DR
基于直接路由实现的虚拟服务器。
VS/NAT的好处显而易见,但也存在明显的瓶颈问题,响应能力有限。
如果能够将接收请求和响应请求的步骤分离,这样就能减轻均衡器的工作负担,让服务器多承担一点工作,这样整个集群的处理能力大大提升。
DR模型是在均衡器上,将请求报文中的帧首部的源MAC地址指向使用调度算法挑选出的真实服务器(Real Server)的MAC地址,通过本地非路由交换网络,交由Real Server处理并直接响应请求的客户端。
为了响应客户端,Real Server需要配置VIP地址,要阻止这个VIP的ARP广播和响应,使它在网络中不可见。只有均衡器的VIP才能对外可见。
DR模型解决了NAT模型的瓶颈问题,减轻了Director的压力,提高了虚拟服务器的并发处理能力。
由于修改的是MAC地址,所以不支持端口映射,且发送给Real Server的数据报文不能跨路由。
VS/TUN
基于IP隧道实现的虚拟服务器。
Director接收到客户请求之后,将根据调度方法选择合适的目标服务器,只不过这些目标服务器都不在同一网络中,可能是互联网的其他网络中的主机。使用IP隧道技术封装数据报文,也就是将报文封装在新的指向Real Server的IP报文中。这个IP报文层层路由后到达目标服务器后,目标服务器必须能够识别IP隧道封包并解开它,发现数据是发往自身具有的VIP的,就接收下来并直接响应客户端。
TUN模型,减轻了Director的压力,提高了负载均衡系统的吞吐量。
但相对于DR模型来说,其IP隧道开销较大,且广域网路由,在响应速度上可能要慢于DR模型。
所有通讯地址都要使用公网地址,这也是不小的成本。
VS/FULLNAT
NAT模型不太适合跨路由(笔者认为NAT可以在内网跨路由,但是内部路由配置较为复杂且不通用),这也限制其能够调度的服务器的个数,扩展能力有限。
FULLNAT将请求报文的源地址、源端口、目标地址、目标端口全部转换。是否端口映射视情况而定。
SNAT: CIP:CPORT-->DIP:DPORT
DNAT: VIP:VPORT-->RIP:RPORT
通过内网路由到目标服务器,目标服务器处理后将响应报文回传给Director。Director再做一次地址转换后,将数据报文发回客户端。
SNAT: RIP:RPORT-->VIP:VPORT
DNAT: DIP:DPORT-->CIP:CPORT
这种模型提高了系统的吞吐能力,使后端可以扩展更多服务器,同时允许内网拥有复杂拓扑。
但是Director的瓶颈问题没有解决。
FULLNAT已经由阿里巴巴开源,项目地址https://github.com/alibaba/LVS
(三)ARP相关内核参数
DR模型的实现,比较特殊,需要Real Server捆绑VIP,同时在网络中不可见,也就是说VIP要配置在Non-ARP网络设备上。
为了让VIP在网络不可见,可以采用以下方法:
arptables过滤arp协议相关的包
配置内核参数,阻止设备响应arp报文或者主动发布arp包。
在DR的配置中多采用第二种配置内核参数的方法。
/proc/sys/net/ipv4/conf参数
all 其参数值将应用到所有网络接口
default 用来作为缺省参数初始化一个网络接口的
eth0 这是个例子,要根据网络接口名称而定。定义某一个指定的网络接口参数。
下面以eth0来说明两个重要参数
arp_ignore
定义对目标地址为本机IP地址的ARP询问的不同应答方式。
0 - 任意网络接口收到请求,所有接口都应答
1 - 只在来访的网络接口上做出应答,但是要求目的IP配置在其上。
2 - 同1,进一步要求请求方的IP和目标IP必须属于同一子网。
3 - 如果目的IP的范围不是本地主机,才应答。
4-7 保留
8 不做任何应答
arp_announce
为网络接口上,发送ARP请求的IP包中的宣称的本地IP地址,定义不同程度的级别。
0 - 缺省,配置在任意接口上的任意本地地址。
1 - 如果可能,选择和目的地址位于同一子网内的地址。否则,使用级别2的结果。
2 - 优先使用主地址。
需要说明的是,如果在all下和eth0都定义相同的参数值,将取这个值的最大值。
在VS/DR模型中,需要配置这两个参数。
三、NAT模型实验
(一)规划
(二)测试页面test.php
<?php session_start(); ?>
<html>
<header><title><?php echo getenv('SERVER_ADDR') ?></title></header>
<body>
<?php
if (!isset( $_SESSION [ 'count' ])) {
$_SESSION [ 'count' ] = 0 ;
} else {
$_SESSION [ 'count' ]++;
}
printf("sessionid=%s",session_id());
printf("Client IP is &lt;b>%s</b>:<b>%s</b>",getenv('REMOTE_ADDR'),getenv('REMOTE_PORT'));
printf("Server IP is <b>%s</b>:<b>%s</b>",getenv('SERVER_ADDR'),getenv('SERVER_PORT'));
printf("Filename=%s",getenv('SCRIPT_FILENAME'));
printf("Conn_Count=%d",$_SESSION [ 'count' ]);
phpinfo();
?>
</body>
</html>
说明:
getenv('SERVER_ADDR'),getenv函数返回指定环境变量的值。
session_id()返回SessionID。
'REMOTE_ADDR'指的是取浏览器IP地址,'REMOTE_PORT'指的是取浏览器端端口。
'SERVER_ADDR'指的是取服务器IP地址,'SERVER_PORT'指的是取服务器端端口。
'SCRIPT_FILENAME'取请求的文件名称。
printf是格式化输出函数。
phpinfo函数返回当前php运行环境的所有信息。
$_SESSION [ 'count' ]定义一个会话变量count,每一次同一个会话访问就加1,以示区别。
(三)PHP-FPM构建
IP地址192.168.23.85
详细配置过程,请参看《LAMP的几种简单实现及drupal、WordPress、phpMyAdmin部署》。
# yum -y install gcc libxml2-devel bzip2-devel openssl-devel gd-devel
[root@localhost php-5.6.0]# rpm -ivh ~/libmcrypt-2.5.8-9.el6.x86_64.rpm
warning: /root/libmcrypt-2.5.8-9.el6.x86_64.rpm: Header V3 RSA/SHA256 Signature, key ID 0608b895: NOKEY
Preparing... ########################################### [100%]
1:libmcrypt ########################################### [100%]
[root@localhost php-5.6.0]# rpm -ivh ~/libmcrypt-devel-2.5.8-9.el6.x86_64.rpm
warning: /root/libmcrypt-devel-2.5.8-9.el6.x86_64.rpm: Header V3 RSA/SHA256 Signature, key ID 0608b895: NOKEY
Preparing... ########################################### [100%]
1:libmcrypt-devel ########################################### [100%]
./configure --prefix=/usr/local/php54 --enable-fpm --with-config-file-path=/etc --with-config-file-scan-dir=/etc/php.d --with-libxml-dir --with-openssl --with-pcre-regex --with-zlib --with-bz2 --with-jpeg-dir --with-png-dir -with-freetype-dir --with-mcrypt --enable-sockets --with-mysql --with-mysqli --with-pdo-mysql --enable-mysqlnd --enable-mbstring --with-gd
[root@localhost php-5.6.0]# cp sapi/fpm/init.d.php-fpm /etc/rc.d/init.d/php-fpm
[root@localhost php-5.6.0]# chmod +x /etc/rc.d/init.d/php-fpm
[root@localhost php-5.6.0]# chkconfig --add php-fpm
[root@localhost php-5.6.0]# chkconfig --list php-fpm
php-fpm 0:off 1:off 2:on 3:on 4:on 5:on 6:off
[root@localhost php-5.6.0]# cp /usr/local/php54/etc/php-fpm.conf.default /usr/local/php54/etc/php-fpm.conf
[root@localhost php-5.6.0]# vim /usr/local/php54/etc/php-fpm.conf
pid = run/php-fpm.pid
error_log = log/php-fpm.log
[www]
listen = 9000
[root@localhost ~]# service php-fpm start
Starting php-fpm done
[root@localhost ~]# ss -tnlp | grep 9000
LISTEN 0 128 *:9000 *:* users:(("php-fpm",1276,7),("php-fpm",1277,0),("php-fpm",1278,0))
[root@localhost ~]# service php-fpm status
php-fpm (pid 1276) is running...
[root@localhost ~]# mkdir /web/
最后在创建的/web/目录下放置测试页面test.php
(四)WEB1和WEB2配置
因为最后实现的是PHP-FPM,需要支持FastCGI,因此需要2.4版本的httpd。以前的博文中都有,请查阅。
[root@localhost ~]# yum install gcc pcre-devel openssl-devel -y
[root@localhost ~]# tar xf apr-1.5.1.tar.bz2
[root@localhost ~]# tar xf apr-util-1.5.3.tar.bz2
[root@localhost ~]# tar xf httpd-2.4.10.tar.bz2
[root@localhost ~]# cd apr-1.5.1
[root@localhost apr-1.5.1]# ./configure
[root@localhost apr-1.5.1]# make && make install
[root@localhost apr-1.5.1]# cd
[root@localhost ~]# cd apr-util-1.5.3
[root@localhost apr-util-1.5.3]# ./configure --with-apr=/usr/local/apr/
[root@localhost apr-util-1.5.3]# make && make install
[root@localhost ~]# cd ~/httpd-2.4.10
[root@localhost httpd-2.4.10]# ./configure --prefix=/usr/local/apache24 --sysconfdir=/etc/httpd24 --enable-so --enable-ssl --enable-cgi --enable-rewrite --with-z --with-pcre --enable-mpms-shared=all --with-mpm=event --enable-modules=most
[root@localhost ~]# vim /etc/httpd24/httpd.conf
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_fcgi_module modules/mod_proxy_fcgi.so
DocumentRoot "/usr/local/apache24/htdocs"
<Directory "/usr/local/apache24/htdocs">
Options None
AllowOverride None
Require all granted
</Directory>
ProxyRequests Off
ProxyPassMatch ^(/.*\.php)$ fcgi://192.168.23.85:9000/web$1
<IfModule dir_module>
DirectoryIndex index.php index.html
</IfModule>
<IfModule mime_module>
AddType application/x-httpd-php .php
# vim /etc/profile.d/httpd24.sh
export PATH=/usr/local/apache24/bin:$PATH
# source /etc/profile.d/httpd24.sh
# apachectl start
WEB1
修改监听的在TCP的8080端口
Listen 8080
# apachectl restart
# vim /usr/local/apache24/htdocs/index.html
<html><body><h1>192.168.23.80:8080</h1></body></html>
WEB2
# vim /usr/local/apache24/htdocs/index.html
<html><body><h1>192.168.23.81:80</h1></body></html>
(五)Director
部署ipvs
# yum -y install ipvsadm
1、RR调度
[root@localhost ~]# ipvsadm -A -t 172.16.23.80:80 -s rr
[root@localhost ~]# ipvsadm -a -t 172.16.23.80:80 -r 192.168.23.80:8080 -m
[root@localhost ~]# ipvsadm -a -t 172.16.23.80:80 -r 192.168.23.81:80 -m
[root@localhost ~]# 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.23.80:80 rr
-> 192.168.23.80:8080 Masq 1 0 0
-> 192.168.23.81:80 Masq 1 0 0
测试一下效果:
可以看出在两台服务器间调度
2、WRR调度
更换调度算法,增加权重
[root@localhost ~]# ipvsadm -E -t 172.16.23.80:80 -s wrr
[root@localhost log]# ipvsadm -e -t 172.16.23.80:80 -r 192.168.23.80:8080 -m -w 1
[root@localhost log]# ipvsadm -e -t 172.16.23.80:80 -r 192.168.23.81:80 -m -w 5
[root@localhost log]# 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.23.80:80 wrr
-> 192.168.23.80:8080 Masq 1 0 0
-> 192.168.23.81:80 Masq 5 0 0
[root@localhost log]# ipvsadm -L -n -c
IPVS connection entries
pro expire state source virtual destination
TCP 14:57 ESTABLISHED 172.16.0.100:25799 172.16.23.80:80 192.168.23.80:8080
TCP 14:57 ESTABLISHED 172.16.0.100:25798 172.16.23.80:80 192.168.23.81:80
从上面可以看到,确实调度器做到了负载均衡。来测试分析一下
从以上的图可以看出,在一定范围内做到了按照权重分配。
注意Conn_Count值的变化,测试了10次,调度192.168.23.80:8080和192.168.23.81:80的次数比值是1:5。
3、SH调度
[root@localhost log]# ipvsadm -E -t 172.16.23.80:80 -s sh
[root@localhost log]# 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.23.80:80 sh
-> 192.168.23.80:8080 Masq 1 0 0
-> 192.168.23.81:80 Masq 5 0 0
由上图可以看出,在一段时间内,从同一客户端发起的所有连接被定向到了同一台服务器。
(六)NAT模型的特点
实现简单,有较好的负载均衡效果。
基于NAT可以实现目标地址、目标端口的转换。
所有数据进出都要经过Director这个咽喉要道,Director就成整个系统的瓶颈所在。
在Director上所有数据都要进行NAT转换,这限制了Director处理连接的能力,不适合高负载的场景使用。
四、DR模型
(一)规划图
说明:
上图基本上模拟了公网访问内网WEB站点,使用LVS/DR来完成响应的实现规划。
首先在网络边界处,放置防火墙,并在防火墙上做DNAT。
192.168.23.0/24这个网络所有主机的默认网关都是指向192.168.23.1
图中的MAC地址,只是为了后面抓包的时候看着方便而标记在图上,实际实验中视自己网卡硬件地址而定。
有些配置都是直接使用命令即时生效的,如果需要永久生效,请写入配置文件,这些都很简单,参考文档非常多,不再赘述。
(二)WEB1和WEB2
注意下面几步骤都是在两台WEB服务器都做
1)调整内核参数
# echo 1 > /proc/sys/net/ipv4/conf/all/arp_ignore
# echo 2 > /proc/sys/net/ipv4/conf/all/arp_annunce
# echo 1 > /proc/sys/net/ipv4/conf/eth0/arp_ignore
# echo 2 > /proc/sys/net/ipv4/conf/eth0/arp_annunce
上面配置的内核参数的意义是:
发起arp请求时只能从来访的接口上响应,内部发起的ARP请求的源地址也使用出口接口上的IP地址。
这样在LVS的时候,很好的屏蔽了内部接口上的IP地址,在外部不可见。
实际上配置all就可以了,但是怕接口上参数值有其他可能,所以显式的配置在接口上,例如eth0。如果是这样配置,干脆就直接使用后两句eth0的就可以了。
也可以写在配置文件中,永久生效。
# vim /etc/sysctl.conf
net.ipv4.conf.all.arp_announce = 2
net.ipv4.conf.all.arp_ignore = 1
net.ipv4.conf.eth0.arp_announce = 2
net.ipv4.conf.eth0.arp_ignore = 1
# sysctl -p
2)配置VIP
# ip addr add 192.168.23.100/32 broadcast 192.168.23.100 dev lo
# ip route add 192.168.23.100 dev lo
3)启动WEB服务
# apachectl start
默认页面还是VS/NAT实验中的index.html页面。
(三)调度服务器IP配置
使用接口eth0上配置2个IP
DIP,192.168.23.99/24,默认网关指向192.168.23.1
VIP,192.168.23.100/32
# ifconfig eth0:0 192.168.23.100 netmask 255.255.255.255 broadcast 192.168.23.100 up
# ipvsadm -A -t 192.168.23.100:80 -s rr
# ipvsadm -a -t 192.168.23.100:80 -r 192.168.23.81:80 -g
# ipvsadm -a -t 192.168.23.100:80 -r 192.168.23.80:80 -g
# ipvsadm -L -n
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 192.168.23.100:80 rr
-> 192.168.23.80:80 Route 1 0 0
-> 192.168.23.81:80 Route 1 0 0
注:
这里使用rr算法,是因为后面抓包分析的方便,可以根据实际情况选择合适的算法。
Director上的VIP也可以使用24位掩码,不一定非要照着上面语句做。
一定要注意,不能把VIP放到主地址上,否则ICMP(ping)和ARP都会失败。因为这些报文中都有源地址且为VIP,Real Server收到后,认为是自己的VIP发的,Director就无法收到任何回应。
(四)防火墙DNAT
DNAT要指向VIP。
# iptables -t nat -A PREROUTING -d 172.16.23.80 -p tcp --dport 80 -j DNAT --to-destination 192.168.23.100
# ping 192.168.23.100
# arp -n
Address HWtype HWaddress Flags Mask Iface
192.168.23.100 ether 00:0c:29:06:13:ea C eth1
192.168.23.99 ether 00:0c:29:06:13:ea C eth1
看到上面VIP一定要和192.168.23.99指向同一个MAC,也就是要指向Director,否则就要追查问题。看看WEB1和WEB2配置VIP是否正确。
(五)测试
为了能看出区别,我们把WEB1的配置文件的参数修改如下:
DR模型不支持端口映射,所以修改 Listen 为80。
修改 ServerName www2.test.com:8888,注意这一句不会影响监听的80端口,只是影响服务器端变量。
从图上看出,确实实现了rr的效果。注意端口号是8888的,不是真正监听在8888端口。它只是声称监听在8888端口而已。
(六)抓包分析
在防火墙的内网接口上eth1上抓包,因为这是必经之路。
考虑到版面大小,图片被限制了宽度,可以自行放大,下面表格逐句分析。
序号 | 说明 |
1、2 | ssh相关的,不再解释。从序号3开始 |
3 | 192.168.23.1收到了从外围接口上的请求后,要把数据包发往192.168.23.100,所以广播发起ARP请求,询问谁拥有VIP 192.168.23.100 |
4 | Director回应了ARP请求,看MAC地址,这时候后几位是06:13:ea |
5 | 防火墙DNAT后的数据包(第一次握手)发给Director。源地址是CIP,目标地址是VIP。源MAC是192.168.23.1的接口的,目标MAC是Director的。 |
6 | Director使用调度算法挑选出Real Server后,修改目标MAC为这个RS的MAC。这里MAC是WEB1的。 |
7 | WEB1发起对网关192.168.23.1的ARP请求 |
8 | 网关回应 |
9 | WEB1把第二次握手的回应发给网关 |
10 | 网关把第三次握手发给Director。 |
11 | Director把第三次握手发给WEB1的 |
12 | http请求终于来了。依然先到Director。 |
13 | 修改MAC转发WEB1 |
14 | 把对12回应送给网关 |
15 | 发回http报文包含网页内容给网关 |
16 | 发送ACK回应给Director |
17 | 转发给WEB1 |
18 | 新的http连接的握手发给Director |
19 | Director修改为WEB2的MAC |
20 | WEB2广播ARP请求,询问网关192.168.23.1的MAC地址。以下的过程和WEB1相同。 |
以上的分析很好说明了RR调度算法,可以清楚的看到整个DR模型的工作流程。
五、动静分离的discuz的部署
在VS/DR实验的基础上,做一些扩展
(一)数据库服务器
使用MariaDB 5.5,使用二进制发布版本,配置简单即可使用。具体安装方法参看以前的博文。
进入管理界面后,创建数据库bbs,并授权。
> create database bbs;
> grant all on bbs.* to bbs@'192.168.23.%' identified by 'bbs';
(二)部署discuz
1、PHP-FPM上部署discuz
# unzip -q Discuz_X3.2_SC_UTF8.zip
# cp -r ~/upload/* /web/
# chmod 777 -R /web/*
2、在WEB1和WEB2上部署discuz
因为discuz中有一些静态资源,而非*.php的资源都要在WEB服务器上访问,因此也要在WEB服务器上部署discuz。但是由于不是非常的了解discuz的动静资源的详细路径,最简单的方式就是把upload目录下的所有文件复制到WEB1和WEB2的站点根目录下
# unzip -q Discuz_X3.2_SC_UTF8.zip
# cp -r ~/upload/* /web/
顺便说一句,请把WEB1上的配置文件的内容修改回来。
ServerName www2.test.com:80
3、安装discuz
安装过程,如下:
安装完毕后,运行后,发现论坛首页样式错乱
这是怎么回事呢?
其实还是动静分离的问题,在安装论坛的工程中,应该是生成了一些css和图片的新的文件或者路径,而WEB1和WEB2没有。解决的办法很简单。把php-fpm上的文件tar后,在WEB1和WEB2上重新部署就行了。
[root@www1 ~]# cd /usr/local/apache24/htdocs/
[root@www1 htdocs]# rm -rf *
[root@www2 ~]# cd /usr/local/apache24/htdocs/
[root@www2 htdocs]# rm -rf *
[root@localhost ~]# cd /web
[root@localhost web]# tar jcf web.tar.bz2 *
[root@localhost web]# scp web.tar.bz2 root@192.168.23.80:/usr/local/apache24/htdocs/
[root@localhost web]# scp web.tar.bz2 root@192.168.23.81:/usr/local/apache24/htdocs/
[root@www1 htdocs]# tar xf web.tar.bz2
[root@www1 htdocs]# rm -f web.tar.bz2
[root@www2 htdocs]# tar xf web.tar.bz2
[root@www2 htdocs]# rm -f web.tar.bz2
再次运行,首页正常表现
(三)共享存储
1、discuz的配置
进入后台管理页面,选择全局/上传设置
也就是说,data/p_w_upload目录要作为共享的存储的挂载点。看看这个目录下面有什么?
这些文件和目录都是论坛程序需要的,怎么办?还是把p_w_upload目录下所有的内容归档tar,然后挂载nfs目录,然后使用tar解压到这个目录中。
2、NFS服务器配置
# yum install nfs-utils –y
# useradd nfs -u 600
# service nfs start
Starting NFS services: [ OK ]
Starting NFS mountd: [ OK ]
Starting NFS daemon: [ OK ]
Starting RPC idmapd: [ OK ]
# chkconfig nfs on
# chkconfig --list nfs
nfs 0:off 1:off 2:on 3:on 4:on 5:on 6:off
# mkdir /sharedir/
# vim /etc/exports
/sharedir 192.168.23.0/24(rw,all_squash,anonuid=600,anongid=600)
# showmount -e 192.168.23.134
Export list for 192.168.23.134:
/sharedir 192.168.23.0/24
# chmod 777 /sharedir/
为了简单起见,没有做过多的限制,如果需要压缩所有用户权限,可以参看以前的博文。
注意:
挂载nfs目录的各个服务器要安装# yum -y install nfs-utils
3、PHP-FPM上配置nfs目录
[root@localhost web]# cd data/p_w_upload/
[root@localhost p_w_upload]# tar jcf p_w_upload.tar.bz2 *
[root@localhost p_w_upload]# mv p_w_upload.tar.bz2 /tmp
[root@localhost p_w_upload]# cd ..
[root@localhost data]# mount -t nfs 192.168.23.134:/sharedir p_w_upload/
[root@localhost data]# cd p_w_upload/
[root@localhost p_w_upload]# mv /tmp/p_w_upload.tar.bz2 ./
把文件和目录的归档文件,放到nfs服务器上
4、nfs服务器
还原文件和目录,并重新设置属主、属组。
# cd /sharedir/
# tar xf p_w_upload.tar.bz2
# chown -R nfs:nfs /sharedir
5、WEB1和WEB2配置nfs目录
如法炮制,只是mount就行了。
[root@www1 p_w_upload]# cd ..
[root@www1 data]# mount -t nfs 192.168.23.134:/sharedir p_w_upload/
[root@www2 p_w_upload]# cd ..
[root@www2 data]# mount -t nfs 192.168.23.134:/sharedir p_w_upload/
[root@www2 data]# ls p_w_upload/
album p_w_upload.tar.bz2 category common forum group index.htm portal profile swfupload temp
注意p_w_upload.tar.bz2这个文件,这个是192.168.23.134:/sharedir目录下的,说明挂载成功了。
在nfs服务器上把p_w_upload.tar.bz2文件挪个位置# mv p_w_upload.tar.bz2 /tmp/
(四)测试
图片上传成功,提交帖子
帖子浏览成功,多种方式、多次浏览帖子都没有问题。
至此,动静分离且使用同一数据库和NFS共享目录的网站基本搭建完成。
六、总结
本文参照LVS的源码,简单描述了LVS的调度算法。
采用LVS的NAT、DR模型分别作了简单的实验。对于NAT模型,构建了一个特殊的PHP测试页,可以较为清楚看到动静分离后调度的执行效果。对DR模型作了抓包分析,尝试从更加深入的层次理解DR模型的报文走向。
最后,安装配置discuz,看看一个真正的实用WEB程序在这种DR负载均衡下如果实现动静分离的。
本文内容较多,涉及概念非常多,可以参看笔者以前的博文。
本文只是简单的实验分析,所以很多服务器存在单点问题,这个可以通过扩展实现高可用。而且整个实验中, 最大的问题是均衡器并不知道后端服务器的健康状况,这需要借助其他的工具来监测联动控制,详情后述。
参考资料
http://zh.linuxvirtualserver.org/node/25
http://www.linuxvirtualserver.org/software/ipvs.html#kernel-2.6
http://www.linuxinsight.com/proc_sys_net_ipv4_conf.html
http://kb.linuxvirtualserver.org/wiki/Using_arp_announce/arp_ignore_to_disable_ARP
转载于:https://blog.51cto.com/me2xp/1550738