一、负载均衡

  1、我们的nginx或者haproxy是模拟工作在四层的。

  2、我们的lvs是四层的负载均衡器,他是附着在(依托于)netfilter上工作的,因为我们四层作为操作系统来讲是处于内核级的,即通信子网级的,他既然工作在内核级别因此他不需要再监听套接字了。因为我们在内核级别就直接能分析对应的TCP/UDP层的TCP或UDP报文。并且他也不需要再向内核注册监听某一端口了,既然如此他也就不再受制于套接字文件数量的限制,因为他在向后端转发时不需要把自己扮演成客户端向后端发送,因为其摆脱了套接字文件数量的限制,因此lvs是真正意义上在内核中完成转发,即向上添加规则来实现。他不需要监听套接字,也不需要基于反代模型工作。因此把用户请求发给后端真正提供的服务主机时就像我们此前讲到的DNAT一样,把报文中的目标IP地址改一改。当然LVS不完全是这种方式,但是他大体上就是改一改,或二层,或三层,或四层中的一些数据然后转发到后端去的。而这种转发过程不需要自己扮演成任何客户端角色向后端请求,而是直接修改报文然后扔给后端来实现的,因此他不需要自己从用户空间发起一个请求向对方的套接字进行请求。因此我们每一个客户端应用程序只要向别人发请求他都要打开一个ip加端口,这就叫做客户端,只不过他的ip是随机的。即如果我们使用nginx进行调度时,当别人的请求来的时候自己得监听一个套接字,调度web服务就监听80端口,调度mysql服务就监听3306端口,反正他自己要监听在一个套接字上然后才能把用户请求发送给用户空间的进程。而这个进程自己提供服务吗?是不提供的,因为他只是一个调度器,他只是把报文包装一下以后再通过我们的网络协议栈发给后端主机。后端主机的进程接收到了这个请求并提供服务。因此前端主机是客户端套接字,他使用随机端口向后发,后端主机是服务端套接字。因为我们最大连接请求是65535所以我们的最大并发请求也不会超过65535个。

  3、如果是我们工作在内核空间中的LVS,他自己不是客户端,也不会基于自己的某个套接字向我们后端发请求,而是直接改了改我们请求报文中的IP,或mac地址,或端口地址,然后直接就把报文扔出去了,我们后端主机看到的请求依然是可能来自于客户端的,作为DNAT的话我们一般源IP是不变的,因此你可以看到他的真正的客户端套接字依然是来自于源IP,和中间的转发主机没有任何关系,所以他不会使用转发主机自己的端口,既然不会使用他的端口那就受限于客户端了,我们100万个客户端每个客户端都有自己的端口,而我们的服务器端是不需要去识别端口的,尤其是不需要操作客户端的端口的,而是直接扔给客户端去了,源IP源端口都不变,因此他整个并发能力不受限于我们的调度主机自己的套接字数量,即完全可以突破6万,有人做过压力测试,我们最高并发下我们lvs在内核级调度可以调度多达400万个并发请求。而我们F5的bigip也都只有六七百万个并发请求。

  4、如果我们并发访问有20万个的话,我们可以在前面加一个lvs做一级调度,然后调度到后面的nginx做二级调度,那么为什么要用nginx来做二级调度呢?因为对于http协议的应用来讲,他们能做更高级的调度方式,比如能识别应用层数据,能识别cookie,能识别url,能识别动静分离。

    

lvbs多层复杂均衡架构 lvs 四层负载均衡_请求报文

  5、我们lvs的调度能力是远超nginx和haproxy的

二、LVS(Linux Virtual Server)

  1、VS:Virtual Server

    a、我们接收用户请求的前端调度器是不直接处理请求的而是直接转交给后端服务器处理的。

    b、他叫做调度器,也叫做负载均衡器,也叫做分发器,不过lvs中我们称作为调度器。即director

    c、我们的dnat中我们请求报文要经过调度器,响应报文也要经过调度器,请求报文中我们要修改目标地址的,并且响应报文中我们还要把源地址改回我们的dnat服务器的地址。但是对于lvs来讲未必都是如此。

  2、RS:Real Server

    a、后端处理请求的服务器。

    b、我们后端的服务器称之为RS。

  3、作者:章文嵩;alibaba --> didi

  4、l4:四层路由器,四层交换机

    a、VS:根据请求报文的目标IP和目标协议及端口将其调度转发至某RealServer,根据调度算法来挑选RS;

    b、我们说过lvs是工作在内核中的TCP/IP协议栈上,根据用户所请求的目标地址和端口来决定这个请求是交给本机还是转换到后端去,我们此前做dnat就是这样子的。本来用户的请求是发送给用户空间进程的,但是不是这样子,我们强行把对方的目标地址改成后端主机的ip地址了,所以完成了转发。lvs也就类似于此原理,工作在内核级,监听用户的请求报文的IP,目标IP和目标端口,如果符合我们条件,把目标IP或目标端口甚至是目标mac地址改一改,改为后端的某个主机,从而完成真正的调度,而不是由本机来处理。因此它是一种四层转发,或者说是四层路由,或者四层交换。路由是根据目标IP,交换是根据目标mac。

  5、iptables/netfilter:

    a、iptables:用户空间的管理工具

    b、netfilter:内核空间上的框架

      (1)、流入:PREROUTING --> INPUT

      (2)、流出:OUTPUT  --> POSTROUTING

      (3)、转发:PREROUTING --> FORWARD --> POSTROUTING

    c、DNAT:目标地址转换;PREROUTING;

    d、SNAT:源地址转换:POSTROUTING;

  6、lvs:ipvsadm/ipvs

    a、ipvsadm:用户空间的命令行工具,规则管理器,用户管理集群服务及RealServer;

    b、ipvs:工作于内核空间的netfiliter的INPUT钩子之上的框架。假如用户访问的时候目标IP和目标端口是本机的IP和端口,那么就到我们的INPUT规则链上来然后到我们用户空间中去,此时我们ipvs工作在INPUT链上,这个ipvs框架上我们也可以写规则,这个规则有什么用呢?他可以监听用户请求到底是不是我们的集群服务,我们可以在ipvs框架上以规则的方式来定义集群服务,如果他发现你所访问的目标地址和端口他没在prerouting上判断而是在input上判断的,如果这个IP和端口我们在这里定义成了集群服务的地址和端口,那么本来这个请求进来以后进入用户空间中去了,而接下来他就强行扭转报文转发流程,ipvs就根据自己的调度算法挑选一个后端服务器然后把报文扔到POSTROUTING然后就到后端服务器。此时我们的报文所走的流程为:PREROUTING --> INPUT -->POSTROUTING 。我们IPVS就是这样玩的,即强行扭转报文的生命周期。这个不当紧,假如你在我们的INPUT上写了iptables的规则的话他就会影响我们的ipvs的功能的。因为我们把过滤掉的IP都阻止了不让你进本机内部来,这样的话你想调度都来不及了,所以一般来讲我们的ipvs和你的netfilter的过滤功能不要一起使用,并且这里强行扭转目标报文的触发逻辑来完成转发的,而这种转发的结果就是用户请求被强行扭转以后到后端主机上去了。怎么扭转到后端主机上去的呢?还记得DNAT功能怎么弄的么?即修改目标IP地址,而我们LVS这种扭转功能可以不修改IP地址而把它转发到后端主机上去,也可以改目标IP将其转发到后端主机上去,这取决于LVS的类型,他有多种工作机制。

      

lvbs多层复杂均衡架构 lvs 四层负载均衡_客户端_02

    c、ipvs的工作原理是什么呢?第一是框架,第二是向上面写规则,定义成哪个地址和端口是集群服务,我们才能强行扭转哪一个地址和端口。你没有定义的该到本地空间来还到本地空间来。就像我们的DNAT一样,你只改了目标端口为80的其它目标端口的我们是不会改其目标IP地址的。其它的依然交给本机来处理。这里也一样,只对特定的定义成了集群服务的ip和端口给其向后端进行分发调度而其它的不与调度。

    d、于是就需要写规则,谁来写规则呢?就像我们此前将的iptables一样,能够操作内核空间我们用户空间是做不了的,他输出的只是系统调用接口,所以你要想能够生成规则你就需要写程序,先调API,再送规则才行,但是很多一般操作人员都做不到,于是他像iptables一样给我们封装了一个应用程序,在用户空间这个程序叫做ipvsadm,他主要是用于管理规则的,比如向我们iptables框架上添加一个集群服务,向一个集群服务上定义多个后端的服务器,即先定义这个服务,然后再送给这个服务有几个后端服务器。我们要分开进行定义,这些规则都在我们INPUT链上的ipvs框架上。所以他是真正在内核空间工作的。

  7、lvs集群类型中的术语

    a、vs:Virtual Server,Dircetor,Dispatcher,Balancer

    b、rs:Real Server,upstream server,backend server。

    c、CIP:Client IP,VIP:Virtual server IP,RIP:Real server IP,DIP:Director IP

    d、CIP <--> VIP == DIP <<-->> RIP

    e、在lvs中调度器叫vs,也叫dircetor;后端主机叫rs;调度器至少要有两个IP,第一个IP面向客户端一侧提供服务,第二个IP要面向Real Server与Real Server通信的接口。这种框架中客户端IP一般就称之为CIP,也叫Client IP,LVS的Dicetor节点向客户端一侧提供服务的既然是虚拟服务器那么其地址肯定也就是虚拟IP,也就是VIP;Dicetor主机用于与RS通信他此时就扮演成一个Dicetor,因此面向Real Server一侧通信的IP就叫Dicetor IP,也叫DIP。即接到的请求的IP叫VIP,接到请求后转发到后端主机与后端主机通信的叫做DIP。我们每一个Real Server的IP叫RIP,只是我们的RIP各有不同,每一个主机都有自己的RIP地址,所以他有RIP1,RIP2,RIP3等等。我们的RIP在代理服务器负载均衡场景中他们还有另外的称呼,比如upstream server,即上游主机。backend server,即后端主机。

      

lvbs多层复杂均衡架构 lvs 四层负载均衡_请求报文_03

  8、lvs集群的类型

    a、lvs-nat:修改请求报文的目标IP;多目标IP的DNAT。即有点类似于DNAT,不过他有多个目标后端主机。因此如果有多个后端主机我们一般都用lvs来实现。

    b、lvs-dr:操纵封装新的MAC地址。这种模式他既不会动请求报文的源IP源端口,也不会动目标IP和目标端口,而是仅仅封装了mac地址守护向后端转发,这个mac地址是被挑选出的某后端的Real Server的mac地址。当然它依赖于独特的拓扑结构

    c、lvs-tun:在原请求IP报文之外新加一个IP首部。即基于隧道模式来实现,也就意味着你本来有一个源IP目标IP了,在不动的情况下又加了一个源IP和目标IP,即两级IP守护,即基于IP来运载IP,所以叫隧道。隧道可以这样来理解,比如说我们现在开着一辆小轿车到海南岛,有两种方式,第一种就是做在车上把小轿车开上飞机,让飞机跑到海南,然后你再从飞机上开下来。这和你自己开车到海南是一样的。所以你可以理解成是一种隧道逻辑来实现的,即你坐到车上没动就到目的地了。

    d、lvs-fullnat:修改请求报文的源和目标IP。我们的DNAT只会修改请求报文的目标IP和目标端口,而fullnat会修改请求报文的目标IP和目标端口

  9、lvs类型的工作逻辑

    a、lvs-nat

      (1)、多目标IP的DNAT,通过将请求报文中的目标地址和目标端口修改为某挑出的RS的RIP和PORT实现转发

      (2)、RIP和DIP必须在同一个IP网络,且应该使用私网地址;RS的网关要指向DIP;

      (3)、请求报文和相应报文都必须经由Director转发;Director易于成为系统瓶颈

      (4)、支持端口映射,可修改请求报文的目标PORT

      (5)、vs必须是Linux系统,rs可以是任意系统

      (6)、我们的lvs-nat的工作模式和DNAT类似,只是说后端主机有了多个,另外实现方式不在PREROUTING上,而是在INPUT上,所以当用户请求到达时,我们在INPUT链上的规则监控到这是一个集群服务那怎么办呢?即把请求报文的目标IP改成后端某一个被挑选出的主机的RS的IP地址,并强行给其送到POSTROUTING链上以后然后离开本机到对应的RS上去了。因此我们客户端来访问我们的server时,请求报文的源IP为CIP,目标IP为VIP。到达VIP后然后再到达我们调度器的INPUT链,然后INPUT链将目标IP改成后端某个集群的RIP并从POSTROUTING链发出去。我们后端RS收到报文响应时响应报文中源IP为RS的RIP,目标IP为CIP,而我们CIP需要的是VIP的响应报文还需要经由我们的调度器,所以我们每一个后端主机的网关要指向DIR以确保响应报文能经由Director,并且我们这个报文离开Director之前还得改,即源IP改为VIP,目标IP为CIP不变。

        因此我们的VIP应该使用公网地址,DIP应该使用私网地址,私网地址别人是访问不到的。并且后端服务器的网关必须要指向DIP。

        

lvbs多层复杂均衡架构 lvs 四层负载均衡_lvbs多层复杂均衡架构_04

    b、lvs-dr

      (1)、Direct Routing,直接路由

      (2)、通过为请求报文重新封装一个MAC首部进行转发,源MAC是DIP所在的接口的MAC,目标MAC是某挑选出的RS的RIP所在接口的MAC地址;源IP/PORT,以及目标IP/PORT均保持不变

      (3)、Director和各RS都得配置使用VIP

        1)、确保前端路由器将目标IP为VIP的请求报文发往Director

          i、在前端网关做静态绑定

          ii、在RS上使用arptables

          iii、在RS上修改内核参数以限制arp通告及应答级别

            arp_announce:限制通告级别

            arp_ignore:限制应答级别

        2)、RS的RIP可以使用私网地址,也可以是公网地址;RIP与DIP在同一IP网络;RIP的网关不能指向DIP,以确保响应报文不会经由Director

        3)、RS跟Director要在同一个物理网络

        4)、请求报文要经由Director,但响应不能经由Director,而是由RS直接发往Client

        5)、不支持端口映射

      (4)、我们的lvs-nat类型请求和响应报文都需要经过调度器的,这样我们的调度器压力会非常的大,所以我们lvs-dr可以直接响应客户端。但是需要依赖于我们特定的拓扑结构。即我们的Director和RS都连到同一个交换机,即所有主机都在同一个交换机上,假如交换机前端有一个路由器。首先当我们用户请求发出的时候他的源IP为CIP,目标IP为VIP,也就是我们Director上的VIP,然后我们Director收到请求以后发现这是一个集群服务,然后就把请求扔给我们后端的某个Real Server了,这个Real Server响应时他就不再通过我们的Director,而是直接响应给我们的客户端。那么既然要由Real Server直接响应给客户端那么他的响应报文的源IP必须得是VIP,因为客户端访问的目的IP是VIP,这也就意味着这个RS既然能把VIP当源IP那么这个主机也需要配置VIP的,那么每一个RS都可能响应用户请求的,所以都得有VIP,那么为什么用户请求从前端到达以后一定要到达Director呢?本地通信的话怎么做呢?肯定就是我们的mac封装,即我们的路由器收到一个目标IP为VIP的报文时他一看VIP就在本地网络某个接口上,我们路由器后面的接口所配置的IP就连接的我们的交换机,并且交换机连接的所有IP都是同网段的。因此接下来我们的路由器要广播,即ARP广播请求,他说我要和VIP通信,请告诉我mac地址,于是就在这个报文上封装了源mac,即路由器与交换机连接的网卡的mac地址,目标mac就是ARP广播请求的VIP响应的mac地址,然后封装目标mac,封装完后就把报文扔给交换机了,交换机调度时就是根据目标mac进行调度的。但是我们ARP是广播的,我们和交换机相连的Director,RS1和RS2都有VIP,他们都能收到,那么到底以谁为准呢?有可能发给调度器直接调度,也有可能发给某个RS了,这样的话调度器就在一定程度上失去意义了,所以我们一定要确保我们的RS不能被VIP响应,他只能拿来当源地址其它什么都不能干,而且一定要确保前端路由器发出来的这个广播报文VIP响应的只能是Director主机。这样才能保证我们的请求报文一定能到底Director主机,才能完成调度。无论是谁请求都要调度,调度完以后每个RS只能把VIP当源地址,来封装响应报文,别的什么事也干不了。但是我们知道我们在同一个网络中如果把两个主机地址配置成一样会造成地址冲突的,为什么会冲突呢?因为ARP不光有广播请求还有广播通告。所以只要配置的地址一样就会冲突的。此时我们要怎么办呢?所以我可以让后端的RS既不进行广播通告也不进行响应。

      

lvbs多层复杂均衡架构 lvs 四层负载均衡_lvbs多层复杂均衡架构_05

    c、我们拒绝响应请求有两种方式,第一使用iptables规则。但是我们的iptables控制不了iptables。还有就是arptables。我们linux内核4.0后叫做nftables,他支持iptables和arptables。第二就是我们修改内核参数,修改后就可以关闭响应请求。

    d、我们的Director是如何将请求转发的呢?他看到用户请求的目标IP是VIP且是一个集群服务的端口,因此IP地址是不会动的,然后从多个后端RS中挑一个并基于ARP广播得到一个RS的mac地址,然后在另外一层封装一个mac守护,而这个mac守护的源mac是自己网卡的mac地址,而目标mac是挑选出来的RS的mac,然后把报文就扔给交换机了,交换机的交换过程中是根据目标mac来交换的,因此这个目标mac是某个RS,然后报文就扔过来了,这个RS收到报文一看目标mac是自己,然后就拆掉IP封装,然后一看目标IP是VIP,也就是自己,然后他就处理,处理完后就相应,响应报文的网关一定不能指向Director,所以他就拿着VIP当源地址直接响应了。但是对linux来说有个特点就是这个响应报文先经由哪个接口他就会把哪个接口上的地址当源地址,很显然我们的RS要能够与客户端通信,这个报文就要经过自己的物理网卡,而他的物理网卡是RIP而不是VIP,他会把RIP当源地址的,但是对方请求的是VIP,所以把RIP当源地址是不可以的,因此基于内核参数控制的话我们一般就把VIP配置在lo的接口上了,而且是配置在lo的别名上。因此我们的RS要与外部通信他会先经由你的物理网卡,而此时我们现在IP需要强制他进入lo接口,再经由内核转发再经由物理网卡出去,这样他的源地址即VIP才会配置成lo:0这个别名上。我们需要路由限制一下以确保VIP作为源地址而不是RIP。

      

lvbs多层复杂均衡架构 lvs 四层负载均衡_lvbs多层复杂均衡架构_06