接入服务器的负载均衡技术剖析

为什么需要负载均衡技术

负责均衡技术是用来解决下面两个问题的:
1、服务器的高可用问题,通过负责均衡将流量按一定的规则转发到后端的业务服务器,保证后端服务都可以多副本部署,从而解决服务部署的单点问问题;

2、单台服务器的性能瓶颈问题,单台物理机器的性能瓶颈是有上限的,当访问流量达到一定程度后,单机是无法处理的,通过负载均衡将流量按一定规则转发的后端多台业务服务器上,从而达到性能的提升;

使用DNS进行负载均衡

客户端在向服务器发送http请求之前,通常会使用dns将服务器的域名地址解析为ip,所以使用dns进行负载均衡是非常简单可行的。一般的方式是在dns的域名解析中提供多个A纪录或者AAAA纪录,客户端中解析的时候任意选择一个ip地址使用。这个方式虽然简单,但是有一下三个问题:
1、这个机制对客户端的行为的控制力很弱:
因为客户端是随机选择一个ip地址,所以理论上会导致所有的接入服务器都会分流等量的流量,这个是一个很大的问题,它会导致接入服务器或者集群只能平均部署。虽然目前SRV协议支持设置每一个解析ip的优先级与权重,但是http协议目前不支持;

2、不能根据用户的地理位置来返回最近的接入服务器ip:
理论上,数据在光纤中以光速折线运行,所以离接入服务器越近,访问的时延会越低。但是根据dns协议,用户很少与权威域名服务器直接联系,而是通过一个递归解析器来代理解析,并且递归解析器通常还有缓存,这样会带来下面几个问题:
a、递归的方式解析ip地址,导致权威服务器拿不到用户的ip,只能拿到递归解析器的ip地址,因而不能根据用户的信息来返回离用户最近的接入服务器ip。虽然edns0扩展协议中在递归解析器代理解析的时候,会带上用户ip的子网段,但是该扩展协议目前并没有正式通过,并且国内域名解析服务的混乱,很难保证能正常运行;
b、域名解析结构缓存的问题。域名递归解析器缓存了解析纪录,导致一次解析的结果可能只给一个用户,也可能是数万个,导致对接入服务器流量控制很慢。一个解决方案是通过分析流量的变化,来评估解析器的预期影响,从而来纠正缓存导致的数据偏差;

3、不能立即删除dns解析纪录。由于dns权威服务器不提供清除解析纪录缓存的行为,只能给dns纪录保持一个比较低的ttl,更有问题的是不是所有的dns解析都遵守权威解析服务器的ttl,这样都解析纪录中的某一个接入服务器出故障的时候,还是有一段时间用户通过dns解析访问到有故障的接入服务器。

4、dns解析结果的长度是有限制的,rfc1035将dns回复长度限制为512字节,这导致如果接入服务器过多的时候,导致接入服务器的ip不能完全返回,实际是限制了接入服务器的数量,这个对于流量大的业务是有很大问题的。

从上面可以看出,dns虽然可以进行负载均衡,但是有很多的问题,那有没有办法来解决这些问题呢?当然有,在dns负载均衡与接入服务器之间加上一层虚拟ip就可以解决这个问题。

虚拟ip

虚拟ip是通过一个调度节点来接收外地流量,然后调度节点将流量转发给后端的接入服务器来进行处理,调度节点的ip地址就是虚拟ip。在linux环境下,虚拟ip实现的技术一般都是lvs来实现的,下面来分析虚拟ip实现的几种方案:

1、nat模式:

nat模式简单来说就是调度节点收到数据包后,通过修改数据包的源ip为调度节点的ip,目的ip为后端接入服务器的ip(按一定负载均衡的策略),并且纪录好映射关系,这样后端服务器就可以收到调度节点转发过来的数据包。同时,由于后源ip是调度节点的ip,所以后端服务器处理完后,数据包会先发到调度服务器,调度服务器再按映射关系将数据包的源地址修改为调度节点的IP,目的地址修改为用户的ip地址,从而达到负载均衡的目的。这种方式存在以下问题:
a、调度服务器需要维护好映射关系,这个在高并发高qps的情况下是一个不小的负担;
b、来回的数据包都需要在调度服务器进行nat的映射,一般web服务器都是用户请求的流量比较小,服务器响应的流量比较大,这个会极大的影响调度服务器的性能;
nat模式上面的两个问题,我们可以通过dr模式来解决。

2、dr模式:

dr模式是在调度节点收到数据包后,不再修改数据包的源ip地址和目的ip地址,而是直接将数据包需要转发的mac地址修改为后端接入服务器的mac地址(按一定负载均衡的策略),然后直接发送到网卡,接入服务器收到后进行回包的时候,由于数据包的源ip地址和目的ip地址都没有修改,所以数据包直接从接入服务器发送出去,到达用户。从上面的描述中,可以看出,调度节点和接入服务器节点之前二层是需要连通的,所以这种方法存在一个问题,调度节点与接入服务器的数据包都必须在一个子网络中进行广播,当流量足够大的时候,这将是整个系统的瓶颈,因而不能应用在大流量的环境中。
dr模式导致在一个子网冲突域的问题,我们可以通过tull模式来解决。

3、tull模式:

tull模式是在调度节点收到数据包后,再进行一次封装,在原来的数据包再加一个包头,源IP为调度节点的IP,目的ip为后端接入服务器的ip(按一定负载均衡的策略),接入服务收到数据包后,去掉调度节点的封装头,按数据包中的源ip和目的ip进行回包,即回包的源ip为调度节点ip,目的ip为用户的IP,数据包直接发送给用户而不需要经过调度节点,并且由于再进行了一次封装,数据包从调度节点到接入服务器直接是通过ip层进行路由的,所有后端接入服务可以处于不同的网络,避免了dr模式只能在一个子网的限制。

总结

从上面的分析可以得出,前端接入服务的负载均衡的一个最佳实践为;利用dns解析进行第一层负载均衡,将用户的流量按一定规则负载均衡到数据中心的虚拟ip,然后虚拟ip通过tull模式再将流量负载均衡到真实的接入服务器上,如果能将虚拟ip的实时流量负载和状态反馈到dns解析服务器,实时调整虚拟ip的权重,那将是最优的方式了(google就是这么干的)。