一、怎么保证你的业务可靠
想一个问题:假设你有10台服务器对外提供相同的服务,你如何保证这10台服务器能稳定处理外部请求?
这里可能有很多种解决方案,但本质上都是处理下述两个问题:
① 客户端的请求应该分配去哪一台服务器比较好?
② 万一其中某些服务器故障了,如何隔离掉故障服务器?
问题① 处理不好,可能会导致10台服务器中的一部分服务器处于饥饿状态,没有被分配客户端请求或者是分配得很少;而另一部分则一直在处理大量的请求,导致不堪负重。
问题② 处理不好,则CAP原则中的可用性(A)可能就没法保证,除非系统不需要A。
要解决上述问题,你必须实现一套控制器,能调度业务请求和管理业务服务器。很不幸的是,大多数情况下这个控制器往往就是整个系统的瓶颈。因为控制系统如果不深入到客户端上,就必须依赖一个集中式的决策机构,这个机构必然要承载所有客户端的请求。这时候你又得去考虑这个控制器的冗余和故障隔离的问题,这就变得无休无止。
二、业务和控制隔离
那么,如何解决上述问题?
那就是专业的事情交给专业平台去做,即,我们需要独立的负载均衡提供上述2点的解决方案。
对于客户端来说,每次请求一个站点,最终都会转变成对某个IP发起请求。所以只要能控制客户端访问的IP地址,我们就能控制请求应该落到哪个后端服务器上,从而达到调度效果,这是DNS在做的事情。或者,劫持客户端所有请求流量,对流量重新分配请求到后端服务器上。这个是Nginx、LVS等的处理方式。
图1、通过DNS实现负载均衡的效果示意图
图2、通过LVS/Nginx实现负载均衡的效果示意图
这两个方式都能达到负载均衡的效果。但这里面有个严重的问题,DNS、Nginx、LVS等服务在互联网时代不可能单机就能提供业务,都是集群式(也就是有N台服务器组成),那这些集群的可靠性和稳定性又该如何保证呢?
DNS主要负责域名解析,有一定的负载均衡效果,但往往负载效果很差,不作为主要考虑手段。Nginx提供7层负载均衡,主要靠域名来做业务区分和负载。LVS是4层负载均衡,主要靠TCP/UDP协议、IP地址、TCP/UDP端口来区分服务和负载。
为了解决Nginx、LVS这些负载均衡器集群的负载均衡及可靠性,我们可以做下述简单的方案:
业务服务器的负载和可靠性由Nginx保障;Nginx的负载和可靠性由LVS保障。
上述方案是遵循了业务 的逻辑,实际上是在网络分层模型中的应用层的做两级负载。可以看出,其实这个方案是用另一层负载均衡来解决当前层级的负载和可靠性的问题。但这个方案还是有问题,业务和Nginx集群这两层的负载和可靠性是有保障了,但LVS集群这一层的可靠性怎么办?
既然我们在网络分层模型中应用层做了两级负载,那有没有可能做到应用层的三级负载?很幸运的是,基于IP路由的方式,网络设备(交换机、路由器)天然具备了网络层负载均衡功能。
到此,我们可以实现整个负载均衡链条:业务 ;
从这里可以看出,要确保整个负载均衡体系是有效可靠的,必须从网络层开始构筑。处于高层级的业务,可以为低层级的业务提供负载。相对于低层级,高层级的业务都可以认为是低层级业务的控制面,可以交给专业团队去实现和管理,低层级业务侧只需要关注业务本身实现即可。
图3、网络7层模型和LVS、Nginx之间的对应关系
网络7层分层模型说明:
7、应用层: 支持网络应用,应用协议仅仅是网络应用的一个组成部分,运行在不同主机上的进程则使用应用层协议进行通信。主要的协议有:HTTP、FTP、、SMTP、POP3等。
6、表示层: 数据的表示、安全、压缩。(实际运用中该层已经合并到了应用层)
5、会话层: 建立、管理、终止会话。(实际运用中该层已经合并到了应用层)
4、传输层: 负责为信源和信宿提供应用程序进程间的数据传输服务,这一层上主要定义了两个传输协议,传输控制协议即TCP和用户数据报协议UDP。
3、网络层: 负责将数据报独立地从信源发送到信宿,主要解决路由选择、拥塞控制和网络互联等问题。
2、数据链路层: 负责将IP数据报封装成合适在物理网络上传输的帧格式并传输,或将从物理网络接收到的帧解封,取出IP数据报交给网络层。
1、物理层: 负责将比特流在结点间传输,即负责物理传输。该层的协议既与链路有关也与传输介质有关。
三、如何实现4层负载均衡
上面说过,3层负载由网络设备天然提供,但实际使用中是和4层负载紧耦合的,一般不独立提供服务。4层负载可以直接为业务层提供服务,而不依赖7层负载(7层负载主要面向HTTP/HTTPS等业务),所以我们这里主要针对4层负载来讲。
3.1 如何转发流量
实现负载均衡,言外之意就是实现流量重定向,那么,首要解决的问题是如何转发流量。
4个问题要解决:
① 如何把客户端的流量吸引到负载均衡器上?
② 负载均衡器如何选择合适的后端服务器?
③ 负载均衡器如何将请求数据发送到后端服务器上?
④ 后端服务器如何响应请求数据?
对于①,
解决方案很简单,给一批后端服务器提供一个独立的IP地址,我们称之为 IP(也即VIP)。所有客户端不用直接访问后端IP地址,转而访问VIP。对于客户端来说,相当于屏蔽了后端的情况。
对于②,
考虑到处于低层级的负载均衡通用性,一般不做复杂的负载策略,类似RR(轮询)、WRR(带权重轮询)的方案更合适,可以满足绝大多数场景要求。
对于③,
这里的选择会往往会影响这④的选择。理想情况下,我们期望是客户端的请求数据应该原封不动的发送到后端,这样能避免数据包被修改。前面提到的网络七层分层模型中,数据链路层的转发可以做到不影响更上层的数据包内容,所以可以满足不修改客户端请求数据的情况下转发。这就是网络常说的二层转发(数据链路层,处在七层网络模型中的第二层),依靠的是网卡的MAC地址寻址来转发数据。
那么,假设把客户端的请求数据包当成一份应用数据打包送到后端服务器是不是可行?该方式相当于负载均衡器和后端建立了一个隧道,在隧道中间传输客户端的请求数据,所以也可以满足需求。
上述两种解决方案中,依赖数据链路层转发的方案称之为直接路由方式( Route),即DR模式;另一种需要隧道的方案称之为隧道()模式。DR模式有一个缺点,因为依赖MAC地址转发,后端服务器和负载均衡器必须在同一个子网中(可以不严谨认为是同一个网段内),这就导致了只有和负载均衡服务器在同子网的服务器能接入,不在同一个子网的这部分就没有使用负载均衡的机会了,这显然不可能满足当前大规模的业务。模式也有缺点:既然数据转发依赖隧道,那就必须在后端服务器和负载均衡器之间建立隧道。如何确保不同业务人员能正确在服务器上配置隧道,并且能监控隧道正常运行,难度都很大,需要一套完成的管理平台,言外之意即管理成本过高。