作者
:
田逸(
[email][email protected][/email]
) from:[url]http://server.it168.com/server/2007-12-11/200712110855723.shtml[/url]
在前面的文章里,我做了一个“可扩展、高可用服务网络设计方案”,现在我们来说明怎样实现它的技术细节。
网络环境
1、
硬件:服务器、网络附属存储(NAS)和交换机。3个服务器用来做web,2个服务器
来做流媒体,1个服务器做LVS-DR,2个mysql服务器,一个邮件服务器,2个交换机,一个NETAPP NAS。
2、
运行环境:流媒体windows,其他的都是linux。
逻辑结构:除数据库服务器和
NETAPP
存储外,其他的服务器都使用
2
个网络地址,一个公网地址和一个私有网络地址。设置为公网
ip
的网络接口连接在一个交换机,设置为私有网络
ip
的网络接另外一个交换机,处于安全和网络带宽考虑,网络存储设备和数据库只使用私有网络地址。网络拓扑图如下所示:
基本原理:
传统模式下,用户的访问请求通过
DNS
服务器解析后,把服务请求转发给
web
服务器,取得数据后返回给用户。这种模式有
2
个麻烦:同时访问的用户增加到某个程度后,服务器不能提供所需的正常访问;遇到故障,所有的访问请求都将失败。要解决这样一个难题
,LVS
是上上之选。当我们采用
lvs
方案之后,更改
dns
服务器的记录,这样用户的访问将首先到达
LVS
控制器所在的服务器,
LVS
把请求按照某种算法转发给后面真正的服务器。那么数据的返还是怎样的一个过程呢?在采用
DR
方式的集群形式下,真实服务器直接把数据返还给用户而不再经过
LVS
控制器。访问数据的流向在上图中用带箭头的虚线标识出来了,这样设计使得结构更简单一些,
lvs
控制器的压力也小很多。
根据应用的实际情况考虑,本项目采用
LVS/DR
方式。
技术实现
:
先列出个相关服务器的
ip
地址:
名称
|
Ip
地址
|
|
真实ip
地址(RIP)
|
||
LVS/DR(
控制器
)
|
61.135.55.100/24
|
|
RealServer1
(
Web1
)
|
61.135.55.150/24
|
192.168.55.150/24
|
RealServer2
(
Web2
)
|
61.135.55.151/24
|
192.168.55.151/24
|
RealServer3
(
Web3
)
|
61.135.55.152/24
|
192.168.55.152/24
|
RealServer4
(流媒体
1
)
|
61.135.55.153/24
|
192.168.55.153/24
|
RealServer5 (
流媒体
2 )
|
61.135.55.154/24
|
192.168.55.154/24
|
MysqlServer1
|
|
192.168.55.90/24
|
MysqlServer2
|
|
192.168.55.91/24
|
Netapp(
网络共享存储
)
|
|
192.168.55.92/24
|
虚拟ip
地址(VIP
)
|
||
Web
虚拟地址(
VIP1
)
|
61.135.55.160
|
|
流媒体虚拟地址(
VIP2
)
|
61.135.55.161
|
|
一、
修改
DNS
记录。
www IN A 61.135.55.160
media IN A 61.135.55.161
|
修改
bind
完成后测试一下,看是否被正确的解析。注意:主机记录应该解析到虚拟地址。
二、
配置
LVS/DR
。
LVS/DR
主要由控制器和真实服务器
2
部分构成,需要在控制器和真实服务器上做好配置才能提供正常的服务,下面分步来说明。
安装控制器部分:安装好系统(我用的是
centos 5
)
,
指定
ip
地址
61.135.55.100/24
,关闭不必要的系统
/
网络服务(执行
ntsysv
用上下键和空白键来完成)。实现
LVS/DR
最重要的两个东西是
ipvs
内核模块和
ipvsadm
工具包,幸运的是,当前的发行版已经包含
ipvs
内核模块,不必再像旧的内核版本需要打这个补丁,
ipvsadm
需要从网上下载安装,下面总结一下这个过程:
1、
检查内核模块,看
ipvs
模块是否被加载
上图实现,ipvs模块没有被加载,可以手动加载,当然这不是必需的(当安装好ipvsadm包后,执行ipvsadm命令就会把ip_vs加载到系统内核)。执行命令 modprobe ip_vs 就可以把ip_vs模块加载到内核。现在再执行 lsmod –l | grep ip_vs 应该看见ip_vs模块被列出。
2、安装ipvsadm。Ipvsadm的官方下载地址为 [url]http://www.linuxvirtualserver.org/software/kernel-2.6/ipvsadm-1.24.tar.gz[/url] ,解压后先做一个链接文件,把目录/usr/src/kernels/ 2.6.18 -8.el5-i686/ 链接为/usr/src/linux,不这样做的话,执行./configure脚本将报错。运行命令 ln –s /usr/src/kernels/2.6.18-8.el5-i686 /usr/src/linux 做好链接,再运行不带参数的脚本 ./configure,然后执行”make;make install”完成安装
(二)
控制器配置:既可以使用脚本也可以更改系统的配置文件
/etc/sysconfig/ipvsadm
。在实际应用中,我建议用脚本,这样的话,维护和移植
lvs
会很方便。下面给出本案使用的
lvs/dr
脚本:
[root@mysql2 ~]# more /usr/local/bin/lvsdr
#!/bin/bash
RIP1=61.135.55.150
RIP2=61.135.55.151
RIP3=61.135.55.152
VIP1=61.135.55.160
VIP2=61.135.55.161
/etc/rc.d/init.d/functions
case "$1" in
start)
echo " start LVS of DirectorServer"
# set the Virtual IP Address and sysctl parameter
/sbin/ifconfig eth0:0 $VIP1 broadcast $VIP1 netmask 255.255.255.255 up
/sbin/ifconfig eth0:1 $VIP2 broadcast $VIP2 netmask 255.255.255.255 up
/sbin/route add -host $VIP1 dev eth0:0
/sbin/route add -host $VIP2 dev eth0:1
echo "1" >/proc/sys/net/ipv4/ip_forward
#Clear IPVS table
/sbin/ipvsadm -C
#set LVS
#Web Apache
/sbin/ipvsadm -A -t $VIP1:80 -s wlc -p 120
/sbin/ipvsadm -a -t $VIP1:80 -r $RIP1:80 -g
/sbin/ipvsadm -a -t $VIP1:80 -r $RIP2:80 -g
/sbin/ipvsadm -a -t $VIP1:80 -r $RIP3:80 -g
#Media (mms)
/sbin/ipvsadm -A -t $VIP2:1755 -s rr -p 3600
/sbin/ipvsadm -a -t $VIP2:1755 -r $RIP3:1755 -g
/sbin/ipvsadm -a -t $VIP2:1755 -r $RIP4:1755 -g
/sbin/ipvsadm -A -t $VIP2:554 -s rr -p 3600
/sbin/ipvsadm -a -t $VIP2:554 -r $RIP3:554 –g
/sbin/ipvsadm -a -t $VIP2:554 -r $RIP4:554 –g
#Run LVS
/sbin/ipvsadm
;;
stop)
echo "close LVS Directorserver"
echo "0" >/proc/sys/net/ipv4/ip_forward
/sbin/ipvsadm -C
/sbin/ifconfig eth0:0 down
/sbin/ifconfig eth0:1 down
;;
*)
echo "Usage: $0 {start|stop}"
exit 1
esac
.RIP1=61.135.55.150
到RIP3=61.135.55.152
定义
3
个真实服务器的
ip
地址。
.VIP1=61.135.55.160
,VIP2=61.135.55.161
定义
2
个虚拟
ip
地址,一个作
web
服务的虚拟地址,一个做流媒体服务的虚拟地址。
. /etc/rc.d/init.d/functions,
执行这个系统脚本,以取得运行其他脚本所需的环境和参数。
.case
语句是一个多路选择,本脚本给出
3
个:
start,stop
及
*,3
选
1
。
$1
表示脚本带一个参数。
. /sbin/ifconfig eth0:0 $VIP1 broadcast $VIP1 netmask 255.255.255.255 up
把
web
服务所需的
ip
地址(虚拟地址)绑定在辅助接口
eth0:0
。在
LVS
方案中,虚拟
ip
地址与普通网络接口大大不同,这点需要特别注意。虚拟
ip
地址的广播地址是它本身,子网掩码是
255.255.255.255
。为什么要这样呢?因为有若干机器要使用同一个
ip
地址,用本身做广播地址和把子网掩码设成
4
个
255
就不会造成
ip
地址冲突了,否则
lvs
将不能正常转发访问请求。
. /sbin/route add -host $VIP1 dev eth0:0
添加主机路由,这
2
条可有可无,较新的
linux
发行版能正确路由这个主机地址。
. echo "1" >/proc/sys/net/ipv4/ip_forward
启用
ip
转发功能。
. /sbin/ipvsadm –C
清空
ipvs
转发表。
. /sbin/ipvsadm -A -t $VIP1:80 -s wlc -p 120
添加一个虚拟服务,服务协议是
tcp(-t)
;服务类型是
web
(
$VIP1:80
);
-s
表示采用
wlc
这种调度算法转发数据包(调度算法包括:
rr|wrr|lc|wlc|lblc|lblcr|dh|sh|sed|nq
);
-p
表示连接的持续时间为
120
秒,这个会话时间是根据实际情况调整的,如果这个值设置得不合理,用户将得到非常糟糕的访问效果。下面举例简单说明一下
从上图我们可以看出,随着时间的变化,用户的请求将可能被
lvs
转发到不同的服务器,而那些需要保持会话的请求将被丢失,导致访问不能进行。
. /sbin/ipvsadm -a -t $VIP1:80 -r $RIP1:80 –g
以直接路由的方式把请求转发到
LVS
后面的真实服务器。我曾企图把
web
(
80
端口)请求转发到真实服务器的其他端口(如
8000
),但不能如愿。
余下的行参照上面的解释,理解起来应该不是问题,因此不再一一说明。脚本写好后,把它放在目录
/usr/local/bin,
然后授与执行权限(
chmod 700 /usr/local/bin/lvsdr
),运行这个脚本,
LVS/DR
控制器部分就算配置好了。如果脚本不能正常运行,多半情况是脚本书写错误所致,如在
windows
用写字板写脚本再拷贝到
linux,
或者写丢了某个“
;
”等等。不管真实服务器端是否正确设置
lvs,LVS/DR
控制器都能独个运行。有
2
个方法检验
LVS/DR
是否正常运行了:(
1
)查看内核是否列出
ip_vs
模块;(
2
)直接运行
ipvsadm –l
看输出是否有转发规则。
(三)
真实服务器配置虚拟
ip
地址。
LVS
可以把服务请求转发到各种各样的操作系统,在本案中有
2
种操作系统:
centos
和
windows 2003 server
。其他
unix
的处理跟
centos(
一种
linux
发行版
)
相似。
(1) centos
服务器设置虚拟服务器:与
LVS/DR
控制类似,既可以修改配置文件也可以用脚本,相对来讲,还是脚本方便,下面是某个服务器设置虚拟
ip
地址的脚本:
[root@WEB2 ~]# more /usr/local/bin/lvs
#!/bin/bash
#description:start realserver
#chkconfig 235 26 26
VIP1=220.194.55.160
/etc/rc.d/init.d/functions
case "$1" in
start)
echo " start LVS of REALServer"
/sbin/ifconfig lo:0 $VIP1 broadcast $VIP1 netmask 255.255.255.255 up
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
;;
stop)
/sbin/ifconfig lo:0 down
echo "close LVS Directorserver"
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 "Usage: $0 {start|stop}"
exit 1
esac
. /sbin/ifconfig lo:0 $VIP1 broadcast $VIP1 netmask 255.255.255.255 up
跟
LVS/DR
控制器一样,广播地址设置为虚拟地址本身,子网掩码
4
个
255
,不同的是,虚拟
ip
地址被绑定在环回(
loopback
)子接口,而不是物理接口的子接口。
. echo "1" >/proc/sys/net/ipv4/conf/lo/arp_ignore
一共四行,其目的是关闭
arp
响应。
(
2
)
windows
服务器设置虚拟地址。
windows
下设置子网掩码为
255.255.255.255
比
linux
设置要麻烦些。要想在网上邻居本地连接的
tcp/ip
属性设置
4
个
255
掩码是不能得逞的,唯一的办法是修改注册表。默认状况下,
windows
并没有环回接口存在,配置之前得先安装这个“设备”。接下来介绍一下环回接口设置步骤:
①
控制面板点击添加新硬件
选“网络适配器”,按“下一步”,选“
Microsoft
”及“
Microsoft Loopback Adapter
”
点击下一步安装好
loopback adapter.
。
②
设置
loopback
的
tcp/ip
参数值。
先设置
ip
,把子网掩码设置成
255.255.255.0
。
设置
ip
地址的目的是方便在注册表中搜索
loopback
设置子网掩码的位置,我们用设置的虚拟
ip
地址做搜索关键字,很快就找到位置了。
搜索“
61.135. 55.160 ”
找到
ip
地址“
61.135. 55.160 ” 所在的位置,在这个项的下方,有个
项“SubnetMask
”,它的值为
255.255.255.0.
把其修改为
255.255.255.255,
但不幸的是,
windows 2003 server
的注册表修改编辑方式是
2
进制,修改时需要技巧。在
windows xp
的注册表编辑器上修改好,然后转换到
2
进制方式,
windows 2003 server
对照这个值更改即可。
换成
2
进制方式
修改好一个项(
SubnetMask
)后,按
F3
修改余下的几个项的
SubnetMask
值为
255.255.255.255
,然后重启
windows
就可以生效了。
一、
运行
LVS/DR
在
LVS/DR
运行
lvs
脚本,在真实服务器上启用虚拟地址,就可以把整个
LVS/DR
运行起来了。
几个需要关注的问题
一、控制器高可靠性。一个普遍的做法是使用
HA,
用
2
个服务器做双机。在条件有限的情况下,又考虑不增加网络结构的复杂性,可以把
LVS/DR
控制器脚本放在不同的服务器上,一旦当前使用的
LVS/DR
控制器出故障,立即启用其它服务器的控制器脚本,可以把停机时间控制在可以接受的范围。
二、安全。出来在真实服务器上启用安全机制外,
LVS/DR
控制器也需要做防火墙策略的。下面是某个
LVS/DR
控制器的防火墙脚本,请大家参考:
[root@mysql2 ~]# more /usr/local/bin/firewall
#!/bin/bash
#this is a common firewall created by 2007-7-29
#define some variable
IPT=/sbin/iptables
CONNECTION_TRACKING="1"
INTERNET="eth0"
CLASS_A=" 10.0.0 .0/8"
CLASS_B="172.16.0.0/12"
CLASS_C="192.168.0.0/16"
CLASS_D_MULTICAST="224.0.0.0/4"
CLASS_E_RESERVED_NET="240.0.0.0/5"
BROADCAST_SRC=" 0.0.0 .0"
BROADCAST_DEST="255.255.255.255"
IPADDR=61.135.55.100
LOOPBACK_INTERFACE="lo"
#Remove any existing rules
$IPT -F
$IPT -X
#setting default firewall policy
$IPT --policy OUTPUT ACCEPT
$IPT --policy FORWARD DROP
$IPT -P INPUT DROP
#stop firewall
if [ "$1" = "stop" ]
then
echo "Filewall completely stopped!no firewall running!"
exit 0
fi
#setting for loopback interface
$IPT -A INPUT -i lo -j ACCEPT
$IPT -A OUTPUT -o lo -j ACCEPT
# Stealth Scans and TCP State Flags
# All of the bits are cleared
$IPT -A INPUT -p tcp --tcp-flags ALL NONE -j DROP
# SYN and FIN are both set
$IPT -A INPUT -p tcp --tcp-flags SYN,FIN SYN,FIN -j DROP
# SYN and RST are both set
$IPT -A INPUT -p tcp --tcp-flags SYN,RST SYN,RST -j DROP
# FIN and RST are both set
$IPT -A INPUT -p tcp --tcp-flags FIN,RST FIN,RST -j DROP
# FIN is the only bit set, without the expected accompanying ACK
$IPT -A INPUT -p tcp --tcp-flags ACK,FIN FIN -j DROP
# PSH is the only bit set, without the expected accompanying ACK
$IPT -A INPUT -p tcp --tcp-flags ACK,PSH PSH -j DROP
# URG is the only bit set, without the expected accompanying ACK
$IPT -A INPUT -p tcp --tcp-flags ACK,URG URG -j DROP
# Using Connection State to By-pass Rule Checking
if [ "$CONNECTION_TRACKING" = "1" ]; then
$IPT -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
$IPT -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
$IPT -A INPUT -m state --state INVALID -j DROP
$IPT -A OUTPUT -m state --state INVALID -j DROP
fi
##################################################################
# Source Address Spoofing and Other Bad Addresses
# Refuse spoofed packets pretending to be from
# the external interface.s IP address
$IPT -A INPUT -i $INTERNET -s $IPADDR -j DROP
# Refuse packets claiming to be from a Class A private network
$IPT -A INPUT -i $INTERNET -s $CLASS_A -j DROP
# Refuse packets claiming to be from a Class B private network
$IPT -A INPUT -i $INTERNET -s $CLASS_B -j DROP
# Refuse packets claiming to be from a Class C private network
$IPT -A INPUT -i $INTERNET -s $CLASS_C -j DROP
$IPT -A INPUT -i $INTERNET -s 0.0.0 .0/8 -j DROP
$IPT -A INPUT -i $INTERNET -s 169.254.0.0/16 -j DROP
$IPT -A INPUT -i $INTERNET -s 192.0.2.0/24 -j DROP
###################################################################
#setting access rules
#enable ssh connect
$IPT -A INPUT -i $INTERNET -p tcp --dport 22 -j ACCEPT
$IPT -A INPUT -i $INTERNET -p tcp --dport 80 -j ACCEPT
$IPT -A INPUT -i $INTERNET -p tcp --dport 1755 -j ACCEPT
$IPT -A INPUT -i $INTERNET -p tcp --dport 554 -j ACCEPT
$IPT -A INPUT -i $INTERNET -p udp --dport 554 -j ACCEPT
$IPT -A INPUT -i $INTERNET -p tcp --dport 8080 -j ACCEPT
$IPT -A INPUT -i $INTERNET -p udp --dport 1024:5000 -j ACCEPT
在这个防火墙脚本中,
--dport 1024:5000 udp
端口是用于
mms
协议的,在项目实施过程中,没有注意这个端口,结果导致流媒体服务请求不能被转发到真实服务器。
三、数据同步。所有相同服务的服务器挂接共享服务器的同一个目录,写入数据实际上是写同一个文件或目录,因此不再需要
rsycn
这样占资源的同步工具。
四、
LVS/DR
维护和监控。系统在运行过程中,某个真实服务器多运行的服务很可能出故障,但
ipvsadm
本身不探测这个事件,它仍然按照某种算法将一些用户的请求转发给出故障的服务器,导致一些用户不能正常访问。
Ldirectord
可以动态的处理这个麻烦,也可以自己写个小工具,定期到真实服务器获取访问返还状态码,根据返还状态码执行相关的
ipvsadm
维护操作。监控报警方面,
Nagios([url]www.nagios.org[/url])
是非常好的选择,当然,监控系统最好放在
LVS/DR
环境之外,关于
Nagios
的细节,请参照我的文章
” Nagios
远程监控软件的安装与配置详解
([url]http://netsecurity.51cto.com/art/200706/48728.htm[/url]).
2007-12-5
海淀福源门悟真阁