用户
 找回密码
 注册

QQ登录

只需一步,快速开始

cnjn

Web负载均衡

热度 75已有 808 次阅读2009-9-14 12:09 |

Web负载均衡
1. 一些思考
1. 外包?
2. 接口人?
3. 工作量分配?
4. 风险管理?
5. 制约?
2. HTTP重定向
1. 熟悉的镜像下载
2. 用代码来实现
3. 重定向的性能和扩展能力
4. RR策略下的性能
5. 更多考虑
3. DNS负载均衡
1. 多个A记录
2. 扩展能力和可管理性
3. 智能解析
4. 故障转移?
5. 一些不足
4. 反向代理负载均衡
1. 转移和转发?
2. 按照权重分配任务
3. 调度器的并发处理能力
4. 扩展的制约
5. 健康探测
6. 粘滞会话
5. IP负载均衡
1. DNAT
2. NAT服务器做了什么?
3. Netfilter/iptables
4. 用iptables来实现调度器?
5. IPVS/ipvsadm
6. LVS-NAT
7. 性能
8. 动态调度策略
9. 网关瓶颈
6. 直接路由
1. 使用IP别名
2. 将实际服务器接入外部网络
3. LVS-DR
4. 与LVS-NAT的性能比较
5. 转型到DNS-RR?
7. IP隧道
8. 调度器的高可用性
9. 集群间的负载均衡
10. 额外的安全性
1. DDoS保护
2. 天然防火墙
以下为本章的部分内容节选
IP负载均衡
我们已经充分了解了反向代理服务器作为负载均衡调度器的工作机制,其本身的开销已经严重制约了这
种框架的可扩展性,从而也限制了它的性能极限。
那么,能否在HTTP层面以下实现负载均衡呢?答案是肯定的,还记得本书开头那个星际铁路系统的故
事吗?回忆一下网络分层模型,事实上,在数据链路层(第二层)、网络层(第三层)、传输层(四
层),都可以实现不同机制的负载均衡,但有所不同的是,这些负载均衡调度器的工作必须由Linux内
核来完成,因为我们希望网络数据包在从内核缓冲区进入进程用户地址空间之前,尽早的被转发到其它
的实际服务器上,没错,Linux内核当然可以办的到,随后我们会介绍位于内核的Netfilter和IPVS,
而用户空间的应用程序对此束手无策。
另一方面,也正是因为可以将调度器工作在应用层以下,这些负载均衡系统可以支持更多的网络服务协
议,比如FTP、SMTP、DNS,以及流媒体和VoIP等应用。
这里我们先来介绍基于NAT技术的负载均衡,因为它可以工作在传输层,对数据包中的IP地址和端口信
息进行修改,所以也称为四层负载均衡。
DNAT
前边曾经提到过网络地址转换(Network Address Translation,NAT),它可以让用户身处内部网
络却与互联网建立通信,而在这里,为了突出应用场景的差异,我想创造一个更加适合的名称,那就是
“反向NAT”,有点类似反向代理的命名动机,是的,我们将实际服务器放置在内部网络,而作为网关的
NAT服务器,将来自用户端的数据包转发给内部网络的实际服务器,这为进一步实现负载均衡提供了可
能。
这里说的“反向NAT”,其实就是DNAT,不同于SNAT的是,它需要修改的是数据包的目标地址和端
口,这种技术在很多普通的家用宽带路由器上都有支持,如果你曾经配置过任意一款宽带路由器,你或
许会看到NAT设置,或者也称为端口映射设置,因为我们知道通过NAT可以修改数据包的目的地端口,
很好的隐藏内网服务器的实际端口,提高安全性。
正如下图中所展现的例子,我们利用家用宽带路由器进行NAT设置,再加上前边提到的动态DNS,完
全可以在家里搭建一个公开的小型Web站点。
[图]家用宽带路由器的端口映射设置
NAT服务器做了什么?
那么,基于NAT的负载均衡系统是如何工作的呢?这里我们举个简单的例子,你将会了解NAT服务器在
整个过程中做了什么。
如下图所示,NAT服务器拥有两块网卡,分别连接外部网络和内部网络,IP地址分别为125.12.12.12
和10.0.1.50。与NAT服务器同在一个内部网络的,是两台实际服务器,IP地址分别为10.0.1.210和
10.0.1.211,它们的默认网关都是10.0.1.50,并且都在8000端口上运行着Web服务。另外,用户
端的IP地址我们假想为202.20.20.20。
[图]基于NAT的负载均衡系统网络结构图
服务器用途内部网络IP 外部网络IP 默认网关
NAT服务器10.0.1.50 125.12.12.12 125.12.12.1
实际服务器10.0.1.200 - 10.0.1.50
实际服务器10.0.1.201 - 10.0.1.50
[表]基于NAT的负载均衡系统网络结构图中的服务器说明
现在我们以一个数据包的真实旅程为例,来跟踪它是如何从用户端到实际服务器,又如何从实际服务器
返回用户端,在这一系列过程中,数据包的命运发生了多次改变。
首先,用户端通过DNS服务器得知站点的IP地址为125.12.12.12,当然,这一步也可能省略,如果站
点不使用域名的话。
接下来,用户端便向125.12.12.12发送了IP数据包,我们将目光放在其中的一个数据包上,它的来源
地址和目标地址如下:
来源地址: 202.20.20.20:6584
目标地址: 125.12.12.12:80
当数据包到达125.12.12.12的内核缓冲区后,NAT服务器并没有把它交给用户空间的进程去处理,而
是挑选了一台实际服务器,这里恰好为10.0.1.210,接下来NAT服务器将刚刚收到数据包进行了修
改,修改后的来源地址和目标地址如下:
来源地址: 202.20.20.20:6584
目标地址: 10.0.1.210:8000
可以看到,NAT服务器修改了数据包的目标地址和端口号,紧接着,NAT服务器指定内部网卡将这个数
据包原封不动的投递到内部网络中,根据IP层的寻址机制,数据包自然会流入10.0.1.210这台实际服
务器。
接下来,运行在10.0.1.210上的Web服务处理了这个数据包,然后将要包含结果数据的响应数据包投
递到内部网络,它的来源地址和目标地址如下:
来源地址: 10.0.1.210:8000
目标地址: 202.20.20.20:6584
显然,这个数据包必须先到达默认网关,于是它又再次回到了NAT服务器,这时候NAT服务器再次修改
数据包,修改后的来源地址和目标地址如下:
来源地址: 125.12.12.12:80
目标地址: 202.20.20.20:6584
最后,数据包终于回到了用户端。
在整个过程中,NAT服务器的动作可谓天衣无缝,它欺骗了实际服务器,而在实际服务器上运行的进程
总是天真的以为数据包是用户端直接发给自己的,不过,这也许是善意的欺骗。
同时,NAT服务器也扮演了负载均衡调度器的角色,那么,在讨论调度策略之前,你也许更关心的是,
究竟如何实现NAT服务器呢?
Netfilter/iptables
首先,我们必须得知道Linux如何修改IP数据包,可以肯定的是,Linux内核已经具备这样的能力,从
Linux2.4内核开始,其内置的Netfilter模块便肩负起这样的使命,它在内核中维护着一些数据包过滤
表,这些表中正是包含了用于控制数据包过滤的规则。
我们知道,当网络数据包到达服务器的网卡并且进入某个进程的地址空间之前,先要通过内核缓冲区,
这时候内核中的Netfilter便对数据包有着绝对控制权,它可以修改数据包,改变路由规则。
既然Netfilter工作在内核中,我们看不见摸不着,那么如何让它按照我们的需要来工作呢?Linux提供
了iptables,它是工作在用户空间的一个命令行工具,我们可以通过它来对Netfilter的过滤表进行插
入、修改或删除等操作,也就是建立了与Netfilter沟通的桥梁,告诉它我们的意图。
那么,我们要做的就是让Linux服务器成为连接外部网络和私有网络的路由器,但这不是普通的路由
器,我们知道路由器的工作是存储转发,除了修改数据包的MAC地址以外,通常它不会对数据包做其
它手脚,而我们要实现的路由器,恰恰是要对数据包进行必要的修改,包括来源地址和端口,或者目标
地址和端口。
总之,可以说,Linux内核改变数据包命运的惊人能力,决定了我们可以构建强大的负载均衡调度器,
将请求分散到其它实际服务器上。
用iptables来实现调度器?
用iptables来实现负载均衡调度器?可以吗?我们来试试吧。
如果你对iptables的使用并不熟悉,你可以通过丰富的在线文档进行系统的学习,遗憾的是,我们这里
不会介绍iptables的详细使用规则,事实上要想在有限的篇幅中把它说清楚并不容易,而且还可能会给
你留下阴影。
说到iptables,最多的应用场景就是防火墙了,我几乎为每台Linux服务器都毫不犹豫的进行iptables
防火墙配置,比如以下的这段简单的iptables规则:
iptables -F INPUT
iptables -A INPUT -i eth0 -p tcp --dport 80 -j ACCEPT
iptables -P INPUT DROP
它完成了重要的任务,那就是告诉内核只允许外部网络通过TCP协议与这台服务器的80端口建立连
接,这项规则可以很好的用在Web服务器上。
另外,我们还会用iptables来实现本机端口重定向,比如以下的规则:
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j REDIRECT
--to-port 8000
它将所有从外部网络进入服务器80端口的请求转移到了8000端口,这有什么意义呢?当然是隐藏某些
服务的实际端口,同时也便于将一个端口快速切换到其它端口的服务上,提高端口管理的灵活性。
关键的时刻到了,我们将用iptables来实现NAT,在此之前,我们需要执行以下的命令行操作:
echo 1 > /proc/sys/net/ipv4/ip_forward
这意味着该服务器将被允许转发数据包,这也为它成为NAT服务器提供了可能。
接下来,我们在作为调度器的服务器上执行以下的iptables规则:
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 8001 -j DNAT -
-to-destination 10.0.1.210:8000
这条规则几乎完成所有DNAT的实现,它将调度器外网网卡上8001端口接收的所有请求转发给
10.0.1.210这台服务器的8000端口,至于转发的具体过程,前边我们已经详细的介绍过。
同样,我们在调度器上再来执行以下的iptables规则:
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 8002 -j DNAT -
-to-destination 10.0.1.211:8000
不用多说,这条规则你一定明白了。
这两条规则已经进入了Netfilter的过滤表,我们可以通过iptables来查看它们,如下:
s-director:~ # iptables -nL -t nat
Chain PREROUTING (policy ACCEPT)
target prot opt source destination
DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp
dpt:8001 to:10.0.1.210:8000
DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp
dpt:8002 to:10.0.1.211:8000
Chain POSTROUTING (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
可以看到,转发规则已经存在,但是,还缺少一个环节,这至关重要,我们必须将实际服务器的默认网
关设置为NAT服务器,也就是说,NAT服务器必须为实际服务器的网关,否则,数据包被转发后将一去
不返。
添加默认网关非常容易,在实际服务器上执行以下命令行操作:
route add default gw 10.0.1.50
现在,查看路由表,刚才的默认网关已经出现了:
s-rs:~ # route
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use
Iface
10.0.1.0 * 255.255.255.0 U 0 0 0
eth1
125.12.12.0 * 255.255.255.0 U 0 0 0
eth0
link-local * 255.255.0.0 U 0 0 0
eth0
loopback * 255.0.0.0 U 0 0 0
lo
default 10.0.1.50 0.0.0.0 UG 0 0 0
eth0
现在,我们终于可以通过调度器的8001和8002端口分别将请求转发到两个实际服务器上,可是,回想
前边的问题,用iptables来实现负载均衡调度器,看起来有点困难,iptables似乎只能按照我们的规则
来干活,没有调度器应该具备的调度能力和调度策略。
接下来,就是IPVS上场的时刻。
IPVS/ipvsadm
熟悉了Netfilter/iptables的机制后,理解IPVS(IP Virtual Server)就一点也不难了,它的工作性
质类似于Netfilter模块,也工作在Linux内核中,但是它更专注于实现IP负载均衡。
IPVS不仅可以实现基于NAT的负载均衡,同时还包括后边要介绍的直接路由和IP隧道等负载均衡。令
人振奋的是,IPVS模块已经内置到Linux2.6.x内核中,这意味着使用Linux2.6.x内核的服务器将不用
重新编译内核,就可以直接使用它。
要想知道内核中是否已经安装IPVS模块,可以进行以下查看:
s-mat:~ # modprobe -l | grep ipvs
/lib/modules/2.6.16.21-0.8-bigsmp/kernel/net/ipv4/ipvs/ip_vs_wrr.ko
/lib/modules/2.6.16.21-0.8-bigsmp/kernel/net/ipv4/ipvs/ip_vs_wlc.ko
/lib/modules/2.6.16.21-0.8-bigsmp/kernel/net/ipv4/ipvs/ip_vs_sh.ko
/lib/modules/2.6.16.21-0.8-bigsmp/kernel/net/ipv4/ipvs/ip_vs_sed.ko
/lib/modules/2.6.16.21-0.8-bigsmp/kernel/net/ipv4/ipvs/ip_vs_rr.ko
/lib/modules/2.6.16.21-0.8-bigsmp/kernel/net/ipv4/ipvs/ip_vs_nq.ko
/lib/modules/2.6.16.21-0.8-bigsmp/kernel/net/ipv4/ipvs/ip_vs_lc.ko
/lib/modules/2.6.16.21-0.8-bigsmp/kernel/net/ipv4/ipvs/
ip_vs_lblcr.ko
/lib/modules/2.6.16.21-0.8-bigsmp/kernel/net/ipv4/ipvs/
ip_vs_lblc.ko
/lib/modules/2.6.16.21-0.8-bigsmp/kernel/net/ipv4/ipvs/ip_vs_dh.ko
/lib/modules/2.6.16.21-0.8-bigsmp/kernel/net/ipv4/ipvs/ip_vs.ko
/lib/modules/2.6.16.21-0.8-bigsmp/kernel/net/ipv4/ipvs/ip_vs_ftp.ko
这样的结果就意味着IPVS已经安装在内核中。
当然,IPVS也需要管理工具,那就是ipvsadm,它为我们提供了基于命令行的配置界面,你可以通过
它快速实现负载均衡系统,这里也称为LVS(Linux Virtual Server,Linux虚拟服务器),或者集
群。
你可以从LVS的官方站点下载与内核匹配的ipvsadm源代码,然后编译它,需要注意的是,在编译过
程中,你还需要在/usr/src/linux中存有内核源代码(Kernel-source)。
接下来,我们将使用ipvsadm来实现基于NAT的负载均衡系统,也就是LVS-NAT。
LVS-NAT
当一切都准备好后,你会发现使用ipvsadm组建基于NAT的负载均衡系统,是一件非常有乐趣的事
情。
现在我们暂时可以完全忘记iptables,因为ipvsadm这里可以完全取代它。首先不要忘了打开调度器的
数据包转发选项,如下:
echo 1 > /proc/sys/net/ipv4/ip_forward
然后,你还需要检查实际服务器是否已经将NAT服务器作为自己的默认网关,如果不是,赶快添加它,
比如:
route add default gw 10.0.1.50
接下来,就是见证IPVS的时刻,我们执行以下命令行操作:
ipvsadm -A -t 125.12.12.12:80 -s rr
ipvsadm -a -t 125.12.12.12:80 -r 10.0.1.210:8000 -m
ipvsadm -a -t 125.12.12.12:80 -r 10.0.1.211:8000 -m
第一行规则用来添加一台虚拟服务器,也就是负载均衡调度器,这里的-s rr是指采用简单轮询的RR调
度策略。后边两行用来为调度器添加实际服务器,其中-m表示采用NAT方式来转发数据包,这正是我
们这里所希望的。
接下来,我们还可以通过ipvsadm来查看所有实际服务器的状态,如下:
s-director:~ # ipvsadm -L -n
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn
InActConn
TCP 125.12.12.12:80 rr
-> 10.0.1.210:80 Masq 1 0 2
-> 10.0.1.211:80 Masq 1 0 2
大功告成,我们对调度器进行连续的HTTP请求,没错,它正是采用RR方式将请求均衡的分散到了两台
实际服务器上。
关键的问题来了,我们费了很大的力气,终于搭建起基于NAT的负载均衡系统,它的性能如何呢?
性能
还记得前边对反向代理负载均衡系统的一系列不同内容的压力测试吗?在使用了LVS-NAT后,我们同
样针对这些内容,再次对调度器进行压力测试,同时和之前的数据进行比较,如下:
内容类型10.0.1.210 10.0.1.211 反向代理负载均衡LVS-NAT
静态(10Bytes) 13022.53 13328.71 7778.5 15953.03
动态(num=100) 10529.97 10642.43 7589.22 13850.88
动态(num=500) 8244.66 817**5 7137.96 13513.79
动态
(num=1000)
6950.16 6634.42 6458.53 12941.28
动态
(num=5000)
2771.98 2654.07 4454.4 5310.58
动态
(num=10000)
1444 1478.96 2468.48 2870.92
动态
(num=50000)
322.26 331.79 635.39 646.03
动态
(num=100000)
151.9 157.48 296.6 303.68
[表]后端服务器、反向代理服务器、NAT服务器分别对于不同内容的压力测试结果
对于以上的数据,我们仍然绘制了柱状图和曲线图。通过前边对基于反向代理的负载均衡系统扩展能力
的分析,我们知道,当实际服务器的吞吐率达到一定高度时,反向代理服务器的吞吐率将很快达到极
限,而从以下对比图中可以看出,在基于NAT的负载均衡系统中,作为调度器的NAT服务器可以将吞吐
率继续提升到一个新的高度,几乎是反向代理服务器的两倍以上,这当然归功于在内核中进行请求转发
的较低开销。
[图]反向代理负载均衡和LVS-NAT对比柱状图
[图]反向代理负载均衡和LVS-NAT对比曲线图
另外,从上边的曲线图中可以直观的看出,对于n<=500的动态内容,也就是实际服务器的吞吐率在
2000-3000reqs/s时,不论是基于反向代理,还是基于NAT,负载均衡的整体吞吐率都基本相当,这
意味着对于一些开销较大的内容,使用简单的反向代理来搭建负载均衡系统是非常值得考虑的,至少在
初期是一个快速有效的方案,而且它可以非常容易的迁移到NAT方式。
动态调度策略
在刚才的LVS-NAT中,我们使用了RR调度策略,我们知道,它是一种静态调度策略,当集群中的实际
服务器承载能力相当的环境下,它可以很好的实现均衡调度。同时,LVS也支持带权重的RR调度,只
需要配置实际服务器的weight值即可,当然,这也属于静态调度策略。
除此之外,LVS提供了一系列的动态调度策略,比如最小连接(LC)、带权重的最小连接(WLC)、
最短期望时间延迟(SED)等,它们都可以根据实际服务器的各种实时状态,作出调度决策,可谓是察
言观色,全面兼顾。
由于篇幅限制,我们不打算对这些动态调度策略进行详细的介绍和测试,另一方面,不同的动态调度策
略适合不同的场景,由于测试环境的局限,我们也无法全都模拟这些场景。但是,你可以通过LVS官方
文档详细了解这些动态调度策略的机制,一旦了解后,你可以根据站点需要和部署环境,选择合适的动
态调度策略并充分测试性能。
网关瓶颈
尽管如此,作为NAT服务器的网关,也成为了制约集群扩展的瓶颈,我们知道,NAT服务器不仅要将用
户的请求转发给实际服务器,同时还要将来自实际服务器的响应转发给用户,所以,当实际服务器数量
较多,并且响应数据流量较大时,来自多个实际服务器的响应数据包将有可能在NAT服务器发生拥挤。
显然,考验NAT服务器转发能力的时刻到了,由于转发数据包工作在内核中,我们几乎可以不考虑额外
的开销,所以,转发能力这时候主要取决于NAT服务器的网络带宽,包括内部网络和外部网络。
举个例子,假如NAT服务器通过100Mbps的交换机与多台实际服务器组成内部网络,通过前边介绍带
宽的章节,我们知道,这些实际服务器到NAT服务器的带宽为共享100Mbps,这样一来,尽管实际服
务器本身可以很容易达到100Mbps的响应流量,比如提供下载服务,但是NAT服务器的100Mbps出口
带宽成为了制约,使得无论添加多少台实际服务器,整个集群最多只能提供100Mbps的服务。
要解决网关带宽的瓶颈,也并不困难,我们可以为NAT服务器使用千兆网卡,并且为内部网络使用千兆
交换机,下图中展示了理想的带宽配置,其中提及的网卡和交换设备都是工作在全双工模式下的,也就
是两个方向的数据传输都具备同样的带宽。
[图]LVS-NAT的理想带宽配置
[图]LVS-NAT的流量走向图
这样做的出发点是没错的,但是,如果我们希望继续扩展带宽,比如实际服务器使用千兆网卡,那么
NAT服务器将使用万兆(10Gb)网卡,以及万兆交换机,可是,这些设备的昂贵价格,足可以让你再
购买几台服务器,至少目前是这样。
即便是为NAT服务器使用万兆网卡,充分满足网络带宽,但是服务器本身能够以这样的速度转发数据包
吗?我们得看服务器的总线带宽,这取决于总线频率和总线位宽,比如对于支持400MHz前端总线频率
的32位处理器,理论上它的总线带宽为:
32bit × 400MHz = 12.8Gbps = 1.6GB/s
这意味着CPU和内存直接交换数据的速度,当网络数据包通过10Gbps的带宽进入内核缓冲区后,理论
上可以快速的执行转发,也就是将缓冲区中的数据包进行简单修改后拷贝到另一块负责发送数据的缓冲
区。当然,实际的转发速度肯定是达不到12.8Gbps的,还要考虑处理时间等其它因素。
当然,如果条件允许,你也可以购买专业级的负载均衡硬件产品,比如Cisco的LocalDirector或F5的
BIG-IP Local Traffic Manager,它们都可以实现基于NAT的负载均衡,并且支持丰富的调度策略,
它们可以达到较高级别的带宽,而且拥有强大的管理功能,但是,价格相当的不菲。
我们不打算详细介绍这些硬件产品,如果有兴趣,你可以查阅他们的官方介绍。但是可以肯定的是,它
们实现数据转发和调度策略的方式和我们这里的介绍没有太大的差异。
假如你不想花钱去购买千兆交换机或万兆交换机,甚至负载均衡硬件设备,但又不想让NAT服务器成为
制约扩展的瓶颈,怎么办呢?
一个简单有效的办法是,将基于NAT的集群和前边的DNS-RR混合使用,你可以组建多个条件允许的
NAT集群,比如5个100Mbps出口带宽的集群,然后通过DNS-RR方式来将用户请求均衡的指向这些
集群,同时,你还可以利用DNS智能解析,来实现地域就近访问。
事实上,对于大多数中等规模的站点,拥有5个100Mbps的NAT集群,并且再加上DNS-RR,通常足
可以应付全部的业务。
但是,对于提供下载或视频等服务的大规模站点,100Mbps的集群带宽就显得微不足道了,其中一台
实际服务器甚至就要吞没上百M的带宽,现在,NAT服务器的瓶颈出现了,你会选择提高NAT服务器的
带宽,还是其它的方案呢?幸运的是,LVS提供了另一种实现负载均衡的方式,那就是直接路由
(Direct Route,DR),接下来我们会详细的介绍它。

    评论 (0 个评论)

    facelist

    doodle 涂鸦板

    您需要登录后才可以评论 登录 | 注册

    广告中心|Archiver|手机版|小黑屋|记易自媒体 ( 豫ICP备14001670号-1 | beian豫公网安备 41108102000012号  

    GMT+8, 2024-5-22 06:46 , Processed in 0.459969 second(s), 21 queries .

    Powered by Discuz! X3.4|本站由阿里云提供云计算服务

    © 2001-2019 Comsenz Inc.

    返回顶部