qqip代理软件如何安全快捷访问互联网
在大规模业务场景中,已经不可能通过单机提供业务,这就衍生出了负载均衡的需求。为了满足合适可靠的负载,本文将从简单的基础需求出发,一步步推进并解释如何建立负载均衡平台。
一、怎么保证你的业务可靠
想一个问题:假设你有10台服务器对外提供相同的服务,你如何保证这10台服务器能稳定处理外部请求?
这里可能有很多种解决方案,但本质上都是处理下述两个问题:
① 客户端的请求应该分配去哪一台服务器比较好?
② 万一其中某些服务器故障了,如何隔离掉故障服务器?
问题① 处理不好,可能会导致10台服务器中的一部分服务器处于饥饿状态,没有被分配客户端请求或者是分配得很少;而另一部分则一直在处理大量的请求,导致不堪负重。
问题② 处理不好,则CAP原则中的可用性(A)可能就没法保证,除非系统不需要A。
要解决上述问题,你必须实现一套控制器,能调度业务请求和管理业务服务器。很不幸的是,大多数情况下这个控制器往往就是整个系统的瓶颈。因为控制系统如果不深入到客户端上,就必须依赖一个集中式的决策机构,这个机构必然要承载所有客户端的请求。这时候你又得去考虑这个控制器的冗余和故障隔离的问题,这就变得无休无止。
二、业务和控制隔离
那么,如何解决上述问题?
那就是专业的事情交给专业平台去做,即,我们需要独立的负载均衡提供上述2点的解决方案。
对于客户端来说,每次请求一个站点,最终都会转变成对某个IP发起请求。所以只要能控制客户端访问的IP地址,我们就能控制请求应该落到哪个后端服务器上,从而达到调度效果,这是DNS在做的事情。或者,劫持客户端所有请求流量,对流量重新分配请求到后端服务器上。这个是Nginx、LVS等的处理方式。
图4、DR模式的转发示意图,响应流量不会经过负载均衡器
图5、Tunnel模式转发示意图,和DR一样,响应流量不会经过负载均衡器
既然都不是很理想,那还有没有其他方案?
我们期望的是后端服务器不感知前端有负载均衡存在,服务可以放在任何地方,且不做任何过多配置。既然做不到原封不动传送客户端的数据包,那就代理客户端的请求。也就是对客户端发出来的数据包的源IP和目的IP分别做一次IP地址转换。
详细来说,负载均衡器收到客户端A的请求后,自己以客户端的角色向后端服务器发起相同的请求,请求所带的payload来自于客户端A的请求payload,这样保证了请求数据一致。
此时,负载均衡器相当于发起了一个新连接(不同于客户端A发起的连接),新建的连接将会使用负载均衡器的IP地址(称之为LocalIP)作为源地址直接和后端服务器IP通信。
当后端返回数据给负载均衡器时,再用客户端A的连接将数据返回给客户端A。整个过程涉及了两个连接,对应两次IP地址转换,
请求时刻:CIP→VIP, 转换成了LocalIP→后端服务器IP,数据返回时刻:后端服务器IP→ LocalIP, 转换成了VIP→ CIP。
客户端该过程完全基于IP地址转发数据,而不是MAC地址,只要网络可达,数据就可以顺畅在客户端和后端之间传输。
表1:各种模式之间的优劣势分析
3.2 如何剔除异常后端服务器
负载均衡一般提供对后端的健康检查探测机制,以便能快速剔除异常的后端IP地址。理想情况下,基于语义的探测是最好的,能更有效的检测到后端是不是异常。但这种方式一来会带来大量的资源消耗,特别是后端庞大的情况下;这还不是特别严重的,最严重的是后端可能运行了HTTP、DNS、Mysql、Redis等等很多种协议,管理配置非常多样化,太复杂。两个问题点加起来导致健康检查太过于笨重,会大量占用本来用于转发数据的资源,管理成本过高。所以一个简单有效的方式是必要的,既然作为4层负载,我们都不去识别上游业务是什么,只关注TCP或者UDP端口是不是可达即可。识别上层业务是什么的工作交给Nginx这类型的7层负载去做。
所以只要定期检查所有后端的TCP/UDP端口是否开放,开放就认为后端服务是正常的,没有开放就认为是服务异常,后端列表中剔除,后续将不再往该异常后端转发任何数据。
那么如何探测?既然只是判断TCP端口是不是正常开放,我们只要尝试建立一个TCP连接即可,如果能建立成功,则表明端口是正常开放的。但是对于UDP来说,因为UDP是无连接的,没有新建连接的这种说法,但同样能够靠直接发送数据来达到探测的目的。即,直接发送一份数据,假设UDP端口是正常开放的,所以后端通常不会做响应。如果端口是没有开放的,操作系统会返回一个icmp port unreachable状态,可以借此判断端口不可达。但有个问题,如果UDP探测数据包里带了payload,可能会导致后端认为是业务数据导致收取到无关数据。
3.3 如何实现负载均衡器的故障隔离
前面我们说过,4层负载均衡依赖于网络层衡来确保4层负载均衡器之间的负载是平衡的,那么负载均衡器的故障隔离就是依赖于网络层来做。
具体如何做?
实际上,我们是依赖于路由的方式来做网络层的负载均衡,负载均衡集群中每台服务器都把相同的VIP地址通过路由协议BGP通告给网络设备(交换机或者路由器),网络设备收到相同的一个VIP来自不同的服务器,就会形成一个等价路由(ECMP),言外之意就是形成负载均衡。所以如果我们想要隔离掉某台负载均衡器的话,只要在该服务器上把通过BGP路由协议发布的VIP撤销即可,这样,上游交换机就认为该服务器已经被隔离,从而不再转发数据到对应设备上。
图7、通过撤销VIP路由进行故障隔离
至此,我们已经实现了一个基于FULLNAT,主要依赖三层协议端口做健康检查,通过BGP和网络设备对接实现VIP收发的方式实现负通用载均衡架构模型。
四、VGW的实现方案
基于上述4层负载的架构,我们建设了VGW(vivo Gateway),主要对内网和外网业务提供4层负载均衡服务。下面我们将从逻辑架构、物理架构、冗余保障、如何提高管理性转发性能等方面进行说明。
4.1 VGW组件
VGW核心功能是复杂均衡,同时兼具健康检查,业务引流等功能,所以组成VGW的组件主要就是核心的负载均衡转发模块、健康检查模块、路由控制模块。
负载均衡转发模块:主要负责负载计算和数据转发;健康检查模块:主要负责检测后端(RealServer)的可用状态,并及时清除不可用后端,或者恢复可用后端;路由控制模块:主要进行VIP发布引流和隔离异常VGW服务器。
4.2 逻辑架构方案
为了方便理解,我们把客户端到VGW环节的部分称之为外部网络(External),VGW到后端(RealServer)之间的环节较内部网络(Internal)。从逻辑架构上将,VGW功能很简单,就是把External的业务请求均匀分发到Internal的RealServer上。
图8、VGW逻辑示意图
4.3 物理架构方案
物理架构上,对于提供内网的VGW和外网的VGW会有一定差异。
外网VGW集群使用了至少2张网卡,分别接外网侧网络设备和内网侧网络设备。对于VGW服务器来说,两个网口延伸出两条链路,类似人的一双手臂,所以称这种模式为双臂模式,一个数据包只经过VGW服务器的单张网卡一次。
图9、外网VGW物理示意图
而内网VGW和外网不同,内网VGW则只用使用了1张网卡,直接内网侧网络设备。相对应的,该方式称为单臂模式,一个数据包需要需要先从仅有的一张网卡进,然后再从网卡出,最后转发到外部,总计穿过网卡2次。
图10、内网VGW物理示意图
4.4 VGW现有业务模型
前面我们说过,负载均衡可以为7层负载提供更上一层的负载均衡。
当前VGW最大的业务流量来自于7层接入接出平台(也就是Nginx)的流量,而Nginx基本承载了公司绝大部分核心业务。当然Nginx并不能支持所有类型的业务,直接构建于TCP、UDP之上的非HTTP类型这一部分流量7层Nginx并不支持,这类业务直接有VGW将数据转发至业务服务器上,中间没有其他环节,比如kafka、Mysql等等。还有一部分业务是用户自建了各种代理平台,类似于Nginx等等,但也由VGW为其提供4层负载均衡。
图11、VGW业务模型图
4.5 VGW的冗余保障
为了提高可用性,那么考虑哪些风险?大家自然而然的考虑到服务器故障、进程故障等场景。但VGW场景需要考虑更多,因为VGW整个系统包括了链路、网络设备、服务器、进程等。而且还不能只考虑设备宕机这种简单的场景,实际上,上述任何设备出现不宕机但转发异常的情况才是最麻烦的。
所以监控VGW服务转发是不是正常是第一步,我们通过布放在不同机房和地区的探测节点定期和VIP建立连接,通过建立连接的失败比列来作为衡量VGW是不是正常的标准。实际上,该监控相当于检测了整个涉及VGW的所有环节的链路和转发是不是良好的。
上面的监控覆盖到的是集群级别的探测,当然我们也建立了其他更细粒度的监控来发现具体问题点。
在有监控一手数据之后,我们就能提供服务器级别故障处理和集群级别的故障处理能力。
所有设备级别的直接宕机,VGW做到自动隔离;所有链路级别的异常,一部分能自动隔离;所有进程级别的异常,能达到自动隔离;其他非完全故障的异常,人工介入隔离。
服务器级别故障隔离是将某一些VGW服务器通过路由调整将取消VIP的发布,从而达到隔离目的;
集群级别故障隔离是将整个VGW集群的VIP取消发布,让流量自动被备用集群牵引,由备用集群接管所有业务流量。
图12、服务器、链路级别故障隔离
图13、集群级别的故障隔离
4.6 如何提高VGW性能
随着业务量级越来越大,VGW单机要接收近百万的QPS请求,同时要达到500W/s以上的包处理能力。显然一般服务器根本无法达到这么大量的请求和包处理速度,主要原因在于Linux的网络处理机制。网络数据包都必须经过Linux内核,网卡收到数据包后都要发送中断给CPU,由CPU在内核处理,然后再拷贝一份副本给应用程序。发送数据也要经过内核进行处理一遍。频繁的中断、用户空间和内核空间之间不断的拷贝数据,导致CPU时长严重被消耗在了网络数据处理上,包速率越大,性能越差。当然还有其他诸如Cache Miss,跨CPU的数据拷贝消耗等等问题。
这里会很容易想到,能不能把上面CPU干的这些脏活累活扔网卡去干了,CPU就纯粹处理业务数据就行。目前很多方案就是根据这个想法来的,硬件方案有智能网卡,纯软件方案当前用的较多的是DPDK(Intel Data Plane Development Kit)。显然智能网卡的成本会偏高,而且还在发展阶段,应用有一定成本。而DPDK纯软件来说在成本和可控方面要好得多,我们选择了DPDK作为底层的包转发组件(实际上是基于爱奇艺开源的DPVS的二次开发)。
DPDK主要是拦截了内核的包处理流程,将用户数据包直接上送至应用程序中,而不是由内核进行处理。同时摈弃了依靠网卡中断的方式处理数据的行为,转而采用轮询的方式从网卡中读取数据,从达到降低CPU中断的目的。当然还利用了CPU亲和性,使用固定的CPU处理网卡数据,减少进程的切换消耗。另外还有很多关于Cache、内存等方面的优化技术。总体上能够将服务器网卡包处理速度达到千万PPS,极大提升网卡的包处理能力,进而能提升服务器的CPS(每秒新建连接数目)。当前我们在100G网卡下,能够达到 100w 的CPS和1200w PPS的业务处理量(有限条件下的测试结果,非理论值)。
图14、VGW使用的底层工具DPVS(DPDK LVS)对比几种现有的负载均衡方案性能
五、总结
通过上述讲解,我们逐步从一个业务可靠性的需求推演出一套可行的负载均衡方案,同时结合vivo的实际需求,落地了我们的VGW负载均衡接入平台。当然,当前的负载均衡方案都是大量取舍后的结果,不可能做到完美。同时我们未来还面临着新的业务协议支持的问题,以及数据中心去中心化的业务模型对负载均衡的集中式控制之间冲突的问题。但技术一直在进步,但总会找到合适的方案的!
作者:vivo 互联网运维团队- Duan Chengping
来源:微信公众号:vivo互联网技术
出处:https://mp.weixin.qq.com/s/hPB3STR39MuoSAJkf1pYmg
如发现本站有涉嫌抄袭侵权/违法违规等内容,请<举报!一经查实,本站将立刻删除。