跳到主要内容

load_balancing

对于Web站点的水平扩展,负载均衡是一种常见的手段。

负载均衡的目标是将各个服务器的运算能力最大化但不过载。

HTTP重定向

假设我们有四台服务器,我们用其中一台当做主服务器,它负责将任务转发到其他三台服务器。使用HTTP,响应码为302,Location为其他几台服务器的网址。这样,用户访问某个网址先到主服务器,而实际提供服务的为其他服务器。 主服务器的代码大概为:

$domains = [
'www1.web.com',
'www2.web.com',
'www3.web.com',
];
$index = substr(microtime(), 5, 3) % count($domains);
$domain = $domains[$index];

header("Location: http://$domain");

转发策略:

  • 随机转发
  • RR:Round Robin。将请求依次给每个服务器。

HTTP重定向可以将任务交给其他服务器,但是依然有很多问题。

DNS负载均衡

DNS提供域名解析服务。DNS服务将域名映射到IP,这种映射可以是一对多的。这样,DNS服务器就蹭了负载均衡调度器了,将用户请求分散到多台服务器上。

DNS的各种记录类型中,A记录负责实现DNS的基本功能,用来指定服务器对应的IP地址。一个域名可以指定多个。

可见,DNS服务器替代了前面的主站点。

健康检测:当某台服务器down机了,DNS不解析到该服务器。

但是DNS缓存是一个很大的问题。动态DNS让这个提供了可能。

动态域名进行:每次IP地址变更是及时的更新DNS服务器。

DNS负载均衡除了缓存以外,负载策略无法根据HTTP上下文动态调度等诸多限制。

反向代理负载均衡

HTTP负载均衡是将任务“转移”,我们可以“转发”。 在基于反向代理的负载均衡系统中,我们把实际服务器称为后端服务器。不同能力的后端服务器共存时,我们要能者多劳。在nginx中,配置如下:

upstream backend{
server ip_a:80 weight=2;
server ip_b:80 weight=1;
}

server{
...

location ~ \.php {
...
fastcgi_pass backend;
}
}

探测器:当某台后端服务器down了,自动将其从后端服务器群剔除出去。

不同的Web服务器有不同的配置。

粘滞会话:让用户的一次会话周期能的所有请求始终转发到一台特定的后端服务器上。

可以根据用户的IP地址进行hash计算并散列到不同的后端服务器。不同的服务器有不同的配置。

使用会话粘滞,它破坏了均衡策略。在后端服务器上保存Session数据和本地化缓存是一件不明智的事情,它让后端服务器个性化。我们可以使用Cookies,也可以使用分布式Session或分布式缓存等,让后端服务器的应用与本地无关。

IP负载均衡

我们了解了反向代理服务器作为负载均衡调度器的工作机制,其本身的开销会严重制约这种框架的可扩展性,进而限制性能。 我们要是能够在HTTP层以下实现负载均衡,这些开销就没有了。实际上,在数据链路层、网络层和传输层都可以实现不同机制的负载均衡。它在网络数据包在从内核缓冲器进入进程用户地址空间之前由Linux内核直接转发到其他实际服务器。

DNAT

NAT:Network Address Translation,网络地址转换,让处在内部网络的用户与互联网通信。

后端服务器组放在内部网络,作为网关的NAT服务器将来自用户的数据转发给具体的后端服务器。

DNAT:反向NAT,它会修改数据包的目标地址和端口。

我们看DNAT的工作流程:

  • 浏览器通过DNS服务器得到站点IP A
  • 浏览器向该A发IP数据包
  • 数据包达到服务器的内核缓冲区后,NAT服务器不直接给用户空间的进程去处理,而是将目标地址修改为后端服务器的IP B
  • NAT服务器将数据包原封不动的投递到内部网络中
  • B会收到,处理并返回
  • 数据包回到NAT服务器,NAT服务器将来源地址(原目标地址 )改回原样,发送
  • 浏览器得到数据包

好了,我们可以使用Linux的Netfilter模块来实现IP数据包的修改,具体的是使用iptables命令行;再使用IPVS作为调度器。

现在,所有的瓶颈就到网卡了,接收和发送数据的在这。

直接路由

通过修改数据表的目标MAC地址,将数据表转发到实际服务器上,实际服务器将数据直接发给用户端。工作在数据链路层。

可用性

对于关键Web应用可用性至关重要,我们不能容忍任何的单点故障。

对于调度器,我们对主调度器进行心跳检测,让调度任务在主调度器很备用调度器之间转移。