在以前的一篇文章《放好你的密码 - 从芝麻金融被攻破提及》中,一位读者在评论中提出了“若是整个过程速度比较慢登录会有问题”这样一条评论。虽说我对文章的正确性颇有把握,但也仍须要仔细思考是否本身哪里没有说清楚。在这个思考过程当中,我想起了一个很是值得一说的话题,那就是负载平衡。html
在那篇文章中咱们说到,要安全地管理好密码,计算密码哈希所使用的迭代次数应该尽量地大,从而使得单次哈希计算的速度变长,增长恶意人员破解密码的难度。反过来,若是有一百我的或者一千我的同时执行登录操做,那么这么繁琐的哈希计算将致使登录服务器产生“忙不过来”的状况。此时咱们就须要使用负载平衡将登录请求分散到多个登录服务器上,以下降单个服务器的负载。算法
负载平衡简介浏览器
或许有些读者仍然对负载平衡这个名词感到陌生,那么咱们就花一小段篇幅来说解一下到底什么是负载平衡。缓存
在一个大型网站中,在线用户有时可能有几千个甚至上万个之多。若是一个用户的请求须要服务使用0.02秒来处理,那么该服务实例每秒钟将只能处理50个这样的请求,每分钟也只能处理3000个。若是该服务是一个用户很是经常使用的功能,如浏览网站的产品列表,那么很显然单个服务实例已经没法支持该网站的运营。在这种状况下,咱们就须要对该服务进行扩容。安全
扩容主要分为Scale Up和Scale Out两种,分别对应着加强单个服务的服务能力以及加强服务数量。在某些状况下,Scale Up是一个较为简单的操做,例如为该服务所在的服务器添加更大的内存。可是任意一个服务器所能提供的能力实际上都受到其自身物理硬件能力的限制,尤为是具备越高性能的服务器其单位服务能力的价格越为昂贵,所以咱们就须要使用Scale Out方式将工做量分摊到多个服务器之中:服务器
就如上图所显示的那样,当服务器的负载过多而来不及处理的时候,服务器就处于一种过载的状态。在该状态的服务经常会出现响应速度慢甚至无响应的状况。而在执行了Scale Out以后,咱们将会使用多个服务器同时处理用户的请求。在该解决方案中,咱们须要使用一台特定的设备将这些请求分发到各个服务器。该设备会根据其内部所包含的请求分发逻辑来决定如何对这些请求进行分发,以免出现单个服务器过载的状况。这些用来对请求进行分发的设备实际上就是负载平衡服务器。网络
固然,咱们不会等到服务器真正过载了才去解决这个问题。在服务的平常运维中,咱们在服务器的平均负载和峰值负载达到某个特定阈值时就须要考虑是否须要为相应服务进行扩容。架构
一旦一个服务使用了负载平衡系统,那么它将在高可用性以及扩展性上获得极大的加强。这也是咱们使用负载平衡解决方案的最重要缘由。例如对于一个拥有三台服务器的负载平衡系统,若是其中一台发生了故障,那么负载平衡服务器能够经过向各个服务发送心跳等方式得知它们的异常,进而再也不向这个发生了故障的服务器分发任务:并发
而若是当前负载平衡系统中所负担的服务容量已经超过了阈值,那么咱们能够简单地经过在负载平衡系统中添加服务器来解决这个问题:运维
这样,每一个服务器所须要处理的任务就相对减小了,从而减轻了单个服务器的负担。
基于DNS的负载平衡
OK,在了解了负载平衡系统的大体组成及使用方式以后,咱们就来看看各类负载解决方案。
当前业界中所最常使用的负载平衡解决方案主要分为三种:基于DNS的负载平衡,L3/4负载平衡,也便是基于网络层的负载平衡,以及L7负载平衡,即基于应用层的负载平衡。在这些解决方案中,基于DNS的负载平衡是最简单的,也是最先出现的一种负载平衡解决方案。
当咱们经过在浏览器的地址栏中键入域名来访问某个网站时,浏览器将首先查找本地的DNS缓存是否拥有该域名所对应的IP地址。若是有,那么浏览器将尝试直接使用该IP地址访问该网站的内容。若是本地DNS缓存中没有该域名所对应的IP地址,那么它将向DNS发送一个请求,以得到该域名所对应的IP并添加到本地DNS缓存中。
而在DNS中,一个域名可能和多个IP地址绑定。在这种状况下,DNS响应将会按照Round Robin方式返回这些IP地址的列表。例如在屡次经过nslookup或host等命令来查看特定域名所对应的IP时,其可能的返回以下(因国内网络缘由,您须要FQ再进行试验):
$ host -t a google.com
google.com has address 72.14.207.99
google.com has address 64.233.167.99
google.com has address 64.233.187.99
$ host -t a google.com
google.com has address 64.233.187.99
google.com has address 72.14.207.99
google.com has address 64.233.167.99
能够看到,不一样的DNS请求所返回的结果会按照Round Robin进行轮换,进而使得不一样的用户访问不一样的IP地址,平衡各个服务器的负载。
虽然这种负载平衡解决方案很是容易实现,可是它有一个致命的缺点:为了减小DNS请求的次数以提升访问效率,浏览器经常缓存了DNS查询的结果。若是一个IP处的服务失效,那么浏览器可能仍会根据DNS缓存中所记录的信息向该不可用的服务发送请求(不一样的浏览器可能有不一样的行为)。虽说整个服务只有一处IP所对应的服务失效了,可是从用户的角度看来该网站已经不可访问。所以基于DNS的负载平衡方案并不能做为一个独立的负载平衡解决方案来提供高可用性的保障,而是做为其它负载平衡解决方案的补充方案来使用。
L3/4负载平衡
另外一种较为常见的负载平衡则是L3/4负载平衡。这里的L3/4实际上指的就是负载平衡服务器会根据OSI模型中的第三层网络层(Network Layer)和第四层传输层(Transport Layer)所包含的数据来进行负载平衡操做。在这种负载平衡服务器中,这些数据主要包含数据包的IP头和TCP、UDP等协议的协议头:
L3/4负载平衡服务器的工做原理很是简单:在数据到达时,负载平衡服务器将根据自身算法以及OSI模型三四层所包含的数据决定须要处理该数据的服务实例并将其转发。
整个负载平衡的运行包含三方面内容:负载平衡服务器须要知道当前有效的服务实例到底有哪些,并根据自身的分派算法来决定须要处理数据的服务实例,根据分派算法的计算结果将数据发送到目标服务实例上。
首先来看看负载平衡服务器是如何肯定服务实例的有效性的。为了可以保证从负载平衡服务器所派发的数据包能被它后面的服务器集群正常处理,负载平衡服务器须要周期性地发送状态查询请求以探测到底哪些服务实例正在有效地工做。这种状态查询请求经常会超出不少人的认知:若是服务实例崩溃可是承载它的操做系统正常工做,那么该操做系统仍然会正常响应负载平衡服务器所发出的Ping命令,只是此时TCP链接会失败;若是服务实例并无崩溃,而只是挂起,那么它仍然能够接受TCP链接,只是没法接收HTTP请求。
因为这种状态查询请求其实是特定于服务实例的具体实现,所以不少负载平衡服务器都容许用户添加自定义脚本以执行特定于服务实例的查询。这些状态查询请求经常包含了不少测试,甚至会尝试从服务实例中返回数据。
一旦负载平衡服务器发现其所管理的某个服务实例再也不有效,那么它就不会再将任何数据转发给该服务实例,直到该服务实例回归正常状态。在这种状况下,其它各个服务实例就须要分担失效服务器所本来承担的工做。
这里须要注意的一点是,在某个服务实例失效之后,整个系统仍应该具备足够的总容量以处理负载。举例来讲,假如一个负载平衡服务器管理了三个具备相同能力的服务实例,并且这三个服务实例各自的负载都在80%左右。若是其中一个服务实例失效,那么全部的负载都须要由其它两个服务实例来完成。每一个服务实例就须要承担120%的负载,远超过了它所具备的负载能力。这种状况的直接后果就是,服务显得很是不稳定,并经常有系统超时,应用没法正常工做的状况出现。
OK。 如今假设咱们的负载平衡服务器有一个设计良好的状态查询请求,那么它就会根据其所使用的负载平衡算法来为工做的服务实例分配负载。对于初次接触到负载平衡功能的人来讲,最多见的误区就是认为负载平衡服务器会根据各个服务实例的响应速度或负载情况来决定请求须要到达的服务实例。
一般状况下,Round Robin算法是最经常使用也是表现最好的负载平衡算法。若是各个服务实例的容量并不相同,那么负载平衡服务器会使用Weighted Round Robin算法,即根据各个服务实例的实际能力来安比例地分配负载。在某些商业负载平衡服务器中,其的确会根据当前服务实例的负载以及响应时间等因素对这些分配比例自动进行微小地调整,可是它们并非决定性的因素。
若是单纯地使用Round Robin算法,那么具备关联关系的各个请求将可能被分配到不一样的服务实例上。所以不少负载平衡服务器容许根据数据的特定特征对这些负载进行分配,如使用一种哈希算法来对用户所在的IP进行计算,并以计算结果决定须要分配到的服务实例。
一样地,咱们也须要考虑某个服务器实例失效的状况。若是负载平衡系统中的某个服务器实例失效,那么哈希算法中的哈希值空间将发生变化,进而致使本来的服务实例分配结果将再也不有效。在这种状况下,全部的请求将从新分配服务器实例。另外,在某些状况下,用户的IP也可能在各个请求之间发生变化,进而致使它所对应的服务实例发生更改。固然,不用担忧,后面对L7负载平衡服务器的讲解会给您一个解决方案。
在肯定了数据包的目标地址后,负载平衡服务器所须要作的事情就是将它们转发到目标实例了。负载平衡服务器所使用的转发方式主要分为三种:Direct routing,Tunnelling以及IP address translation。
在使用Direct routing方式的时候,负载平衡服务器以及各个服务实例必须在同一个网段上并使用同一个IP。在接收到数据的时候,负载平衡服务器将直接对这些数据包进行转发。而各个服务实例在处理完数据包以后能够将响应返回给负载平衡服务器,也能够选择将响应直接发送给用户,而不须要再通过负载平衡服务器。后一种返回方式被称为Direct Server Return。其运行方式以下所示:
在该过程当中,负载平衡服务器和各个服务实例都不须要对IP(Internet Protocol)层数据进行任何更改就能够对其进行转发。使用这种转发方式的负载平衡服务器的吞吐量很是高。反过来,这种组织方式也要求集群的搭建人员对TCP/IP等协议拥有足够多的理解。
另外一种转发方式Tunnelling实际上与Direct routing相似。惟一的一点不一样则是在负载平衡服务器和各个服务之间创建了一系列通道。软件开发人员仍然能够选择使用Direct Server Return来减轻负载平衡服务器的负载。
IP Address Translation则与前两种方式很是不一样。用户所链接的目标地址其实是一个虚拟地址(VIP,Virtual IP)。而负载平衡服务器在接到该请求的时候将会将其目标地址转化为服务实例所在的实际地址(RIP,Real IP),并将源地址更改成Load Balancer所在的地址。这样在对请求处理完毕后,服务实例将会把响应发送到负载平衡服务器。此时负载平衡服务器再将响应的地址更改成VIP,并将该响应返回给用户。在这种转发方式下,其运行流程则以下所示:
有些细心的读者会问:在消息传递的过程当中,用户所在的User IP已经不在消息中存在了,那负载平衡服务器在传回响应的时候应该如何恢复用户的IP地址呢?实际上在这种转发方式中,负载平衡服务器会维持一系列会话,以记录每一个经由负载平衡服务器的正在处理的各个请求的相关信息。可是这些会话很是危险。若是将会话持续的时间设置得比较长,那么在一个高并发的负载平衡服务器上就须要维护过多的会话。反之若是将会话持续的时间设置得太短,那么就有可能致使ACK Storm发生。
先看会话持续时间较长的状况。假设当前负载平衡服务器每秒钟会接收到50000个请求,并且该负载平衡服务器的会话过时时间为2分钟,那么其就须要保持6000000个会话。这些会话会占用负载平衡服务器的很大部分资源。并且在负载高峰期,其所消耗的资源可能会成倍地增加,会向服务器施加更多的压力。
可是将会话持续时间设置得比较短则更为麻烦。这会致使用户和负载平衡服务器之间产生ACK Storm,占用用户和负载平衡服务器的大量带宽。在一个TCP链接中,客户端和服务端须要经过各自的Sequence Number来进行沟通。若是负载平衡服务器上的会话快速地失效,那么其它TCP链接就有可能重用该会话。被重用的会话中客户端和服务端的Sequence Number都会被从新生成。若是此时原有的用户再次发送消息,那么负载平衡服务器将经过一个ACK消息通知客户端其拥有的Sequence Number出错。而在客户端接受到该ACK消息以后,其将向负载平衡服务器发送另外一个ACK消息通知服务端所拥有的Sequence Number出错。服务端接受到该ACK消息后,将再次发送ACK消息到客户端通知其所拥有的Sequence Number出错……这样客户端和服务端之间就将持续地发送这种无心义的ACK消息,直到某个ACK消息在网络传输过程当中丢失为止。
所以乍一看来,使用IP Address Translation的方案是最容易的,可是相较于其它两种方案,它倒是最危险也是维护成本最高的一种方案。
L7负载平衡
另外一种较为经常使用的负载平衡解决方案则是L7负载平衡。顾名思义,其主要经过OSI模型中的第七层应用层中的数据决定如何分发负载。
在运行时,L7负载平衡服务器上的操做系统会将接收到的各个数据包组织成为用户请求,并根据在该请求中所包含的的数据来决定由哪一个服务实例来对该请求进行处理。其运行流程图大体以下所示:
相较于L3/4负载平衡服务所使用的数据,L7负载平衡服务所使用的应用层数据更贴近服务自己,所以其具备更精确的负载平衡行为。
在前面对L3/4负载平衡的讲解中咱们已经介绍过,对于某些具备关联关系的各个请求,L3/4负载平衡服务器会根据某些算法(如计算IP的哈希值)来决定处理该请求的服务实例。可是这种方法并非很稳定。当一个服务实例失效或用户的IP发生变化的时候,用户与服务实例之间的对应关系就将发生改变。此时用户原有的会话数据在新的服务实例上并不存在,进而致使一系列问题。
其实产生这个问题的最根本缘由就是用户与服务实例之间的关联关系是经过某些外部环境建立的,而并不是由用户/服务实例自己来管理。所以它不能抵御外部环境变化的冲击。若是要在用户和服务实例之间创建稳定的关联关系,那么就须要一种稳定的在用户和服务实例之间传递的数据。在Web服务中,这种数据就是Cookie。
简单地说,基于Cookie的负载平衡服务实际上就是分析用户请求中的某个特定Cookie并根据其值决定须要分发到的目标地址。其主要分为两种方式:Cookie Learning以及Cookie Insertion。
Cookie Learning是不具备侵入性的一种解决方案。其经过分析用户与服务实例通信过程当中所传递的Cookie来决定如何分派负载:在用户与服务第一次通信时,负载平衡服务将找不到相应的Cookie,所以其将会把该请求根据负载平衡算法分配到某个服务实例上。而在服务实例返回的时候,负载平衡服务器将会把对应的Cookie以及服务实例的地址记录在负载平衡服务器中。当用户再次与服务通信时,负载平衡服务器就会根据Cookie中所记录的数据找到前一次服务该用户的服务实例,并将请求转发到该服务实例上。
这么作的最大缺点就是对高可用性的支持不好。若是一旦负载平衡服务器失效,那么在该负载平衡服务器上所维护的Cookie和服务实例之间的匹配关系将所有丢失。这样当备份负载平衡服务器启动以后,全部的用户请求都将被定向到随机的服务实例。
而另外一个问题就是会话维护功能对内存的消耗。与L3/4服务器上的会话维护不一样,一个Cookie的失效时间可能很是长,至少在一次用户使用中可能会持续几个小时。对于一个访问量达到每秒上万次的系统而言,负载平衡服务器须要维护很是多的会话,甚至可能会将服务器的内存消耗殆尽。反过来,若是将负载平衡服务器中的Cookie过时时间设置得过短,那么当用户从新访问负载平衡服务器的时候,其将被导向到一个错误的服务实例。
除了Cookie Learning 以外,另外一种经常使用的方法就是Cookie Insertion。其经过向响应中添加Cookie以记录被分派到的服务实例,并在下一次处理请求时根据该Cookie所保存的值来决定分发到的服务实例。在用户与服务器进行第一次通信的时候,负载平衡服务器将找不到分派记录所对应的Cookie,所以其会根据负载平衡算法为该请求分配一个服务实例。在接收到服务实例所返回的数据以后,负载平衡服务器将会向响应中插入一个Cookie,以记录该服务实例的ID。当用户再次发送请求到负载平衡服务器时,其将根据该Cookie里所记录的服务实例的ID派发该请求。
相较于Cookie Learning,Cookie Insertion不须要在内存中维护Cookie与各个服务实例的对应关系,并且在当前负载平衡服务器失效的时候,备用负载平衡服务器也能够根据Cookie中所记录的信息正确地派发各个请求。
固然,Cookie Insertion也有缺陷。最多见的问题就是浏览器以及用户自身对Cookie的限制。在Cookie Insertion中,咱们须要插入一个额外的Cookie 来记录分配给当前用户的服务实例。可是在某些浏览器中,特别是移动浏览器中,经常会限制Cookie的个数,甚至只容许出现一个 Cookie。为了解决这个问题,负载平衡服务器也会使用一些其它方法。如Cookie Modification,即修改一个已有的Cookie使其包含服务实例的ID。
而在用户禁用了Cookie的时候,Cookie Insertion将是彻底失效的。此时负载平衡服务所能利用的将仅仅是JSESSIONID等信息。所以在一个L7负载平衡服务器中,Cookie Learning和Cookie Insertion经常同时使用:Cookie Learning会在用户启用Cookie的时候起主要做用,而在Cookie被用户禁用的状况下则使用Cookie Learning来根据JSESSIONID来保持用户与服务实例之间的关联关系。
或许您会想:L3/4负载平衡服务器在处理各个关联请求的时候是经过IP的哈希值来决定处理该请求的服务实例的。既然这些基于Cookie的解决方案能达到100%的准确,为何咱们不在L3/4负载平衡服务器中使用它们呢?答案是:因为L3/4负载平衡服务器主要关注于数据包级别的转发,而Cookie信息则藏匿于数据包之中,所以L3/4负载平衡服务器很难决定单一的数据包该如何转发。
例如在执行Cookie Insertion操做的时候,原有数据包中的全部数据都将被后移。此时须要负载平衡服务器接收到全部数据包以后才能完成:
试想一下接收全部数据包所可能发生的事情吧。在网络的一端发送多个数据包的时候,网络的另外一端所接收到的数据包的顺序可能与原有的发送顺序并不一致。甚至在网络拥堵的时候,某些数据包可能会丢失,进而再次加长接收到全部数据包所须要的时间。
所以相较于将数据包直接转发的方法,等待全部的数据包到齐而后再插入Cookie的性能很是差。在后面对于解决方案的讲解中您会看到,L3/4负载平衡服务器对于性能的要求通常来讲是很高的,而L7负载平衡服务器则能够经过一个集群来解决自身的性能问题。基于DNS的负载平衡,L3/4负载平衡服务器以及L7负载平衡服务器经常协同工做,以组成一个具备高可用性以及高可扩展性的系统。
SSL Farm
在上面的讲解中,咱们忽略了一个事情,那就是L7负载平衡服务器对于SSL的支持。在L7负载平衡服务器中,咱们经常须要读写请求及响应中的Cookie。可是若是通信使用的是SSL链接,那么L7负载平衡服务器将没法对请求及响应的内容进行读写操做。
解决该问题所曾经使用的一个解决方案就是:将负载平衡服务器以反向代理的方式使用。在这种方案中,负载平衡服务器将拥有服务的证书,并能够经过证书中的密钥对请求进行解密。解密完成后,负载平衡服务器就能够开始尝试读取Cookie中的内容并根据其所记录的信息决定该请求所须要派发到的服务实例。在对该请求进行派发的时候,负载平衡服务器能够再也不使用SSL链接,进而使得各个服务实例再也不须要再次解密请求,提升服务实例的运行效率。
在请求处理完毕以后,服务实例将经过服务实例与负载平衡服务器的非SSL链接返回一个响应。在负载平衡服务器接收到该响应以后,其将会把该响应加密并经过SSL链接发出:
可是这样作的问题在于,若是全部对SSL的处理都集中在L7负载平衡服务器上,那么它将会变成系统的瓶颈。绕过该问题的方法就是在L7负载平衡服务器以前使用一系列反向代理来负责SSL的编解码操做。
此时整个系统的架构将呈现以下的层次结构:
从上图中能够看到,整个解决方案分为了四层。在用户的请求到达了第一层的负载平衡服务器时,其将会把该请求根据自身的负载平衡算法转发给处于第二层的专门负责SSL编解码工做的反向代理。该代理会将传入的由SSL链接所传输的请求由非SSL链接传出。在请求到达第三层时,L7负载平衡服务器能够直接访问这些请求所包含的Cookie,并根据Cookie中的内容决定须要处理该请求的服务实例。
这么作的好处有不少。首先就是这些反向代理很是便宜,甚至只有常见负载平衡服务器的1/20左右的价格,却在处理SSL链接上拥有几乎相同的效率。除此以外,这些反向代理还提供了很是良好的扩展性和高可用性。一旦负载平衡系统在处理SSL链接的能力上显得有些吃力,咱们就随时能够向系统中添加新的反向代理。而一旦其中一个反向代理失效,那么其它反向代理能够经过多承担一些负载来保证系统的安全运行。
须要考虑的问题
在提出具体的负载平衡解决方案以前,咱们须要首先讲解一下在设计负载平衡系统时咱们所须要考虑的一些事情。
首先要说的就是要在负载平衡系统设计时留意它的高可用性及扩展性。在一开始的讲解中,咱们就已经提到过经过使用负载平衡,由众多服务器实例所组成的服务具备很高的可用性及扩展性。当其中一个服务实例失效的时候,其它服务实例能够帮助它分担一部分工做。而在总服务容量显得有些紧张的时候,咱们能够向服务中添加新的服务实例以扩展服务的总容量。
可是因为全部的数据传输都须要通过负载平衡服务器,所以负载平衡服务器一旦失效,那么整个系统就将没法使用。也就是说,负载平衡服务器的可用性影响着整个系统的高可用性。
解决这个问题的方法要根据负载平衡服务器的类型来讨论。对于L3/4负载平衡服务器而言,为了可以让整个系统不失效,业界中的经常使用方法是在系统中使用一对负载平衡服务器。当其中一个负载平衡服务器失效的时候,另外一个还可以为整个系统提供负载平衡服务。这一对负载平衡服务器能够按照Active-Passive模式使用,也能够按照Active-Active模式使用。
在Active-Passive模式中,一个负载平衡服务器处于半休眠状态。其将会经过向另一个负载平衡服务器发送心跳消息来探测对方的可用性。当正在工做的负载平衡服务器再也不响应心跳的时候,那么心跳应用将会把负载平衡服务器从半休眠状态唤醒,接管负载平衡服务器的IP并开始执行负载平衡功能。
而在Active-Active模式中,两台负载平衡服务器会同时工做。若是其中一台服务器发生了故障,那么另外一台服务器将会承担全部的工做:
能够说,二者各有千秋。相较而言,Active-Active模式具备较好的抵抗访问量大幅波动的状况。例如在一般状况下,两个服务器的负载都在30%左右,可是在服务使用的高峰时间,访问量多是平时的两倍,所以两个服务器的负载就将达到60%左右,仍处于系统能够处理的范围内。若是咱们使用的是Active-Passive模式,那么平时的负载就将达到60%,而在高峰时间的负载将达到负载平衡服务器容量的120%,进而使得服务没法处理全部的用户请求。
反过来,Active-Active模式也有很差的地方,那就是容易致使管理上的疏忽。例如在一个使用了Active-Active模式的系统中,两个负载平衡服务器的负载常年都在60%左右。那么一旦其中的一个负载平衡服务器失效了,那么剩下的惟一一个服务器一样将没法处理全部的用户请求。
或许您会问:L3/4负载平衡服务器必定要有两个么?其实主要由各负载平衡服务器产品自身来决定的。在前面咱们已经讲过,实际上探测负载平衡服务器的可用性实际上须要很复杂的测试逻辑。所以若是一旦咱们在一个负载平衡系统中使用了过多的L3/4负载平衡服务器,那么这些负载平衡服务器之间所发送的各类心跳测试将消耗很是多的资源。同时因为不少L3/4负载平衡服务器自己是基于硬件的,所以它可以很是快速地工做,甚至能够达到与其所支持的网络带宽所匹配的处理能力。所以在通常状况下,L3/4负载平衡服务器是成对使用的。
若是L3/4负载平衡服务器真的接近其负载极限,那么咱们还能够经过DNS负载平衡来分散请求:
这种方法不只仅能够解决扩展性的问题,更能够利用DNS的一个特性来提升用户体验:DNS能够根据用户所在的区域选择距离用户最近的服务器。这在一个全球性的服务中尤其有效。毕竟一个中国用户访问在中国架设的服务实例要比访问在美国架设的服务实例快得多。
反过来因为L7负载平衡服务器主要是基于软件的,所以不少L7负载平衡服务器容许用户建立较为复杂的负载平衡服务器系统。例如定义一个具备两个启用而有一个备用的一组L7负载平衡服务器。
讲解完了高可用性,咱们就来介绍一下负载平衡服务器的扩展性。其实在上面咱们刚刚介绍过,L3/4负载平衡服务器拥有很高的性能,所以通常的服务所使用的负载平衡系统不会遇到须要扩展性的问题。可是一旦出现了须要扩展的状况,那么使用DNS负载平衡就能够达到较好的扩展性。而L7负载平衡则更为灵活,所以扩展性更不是问题。
可是一个负载平衡系统不可能都是由L3/4负载平衡服务器组成的,也不可能只由L7负载平衡服务器组成的。这是由于二者在性能和价格上都具备很是大的差别。一个L3/4负载平衡服务器实际上价格很是昂贵,经常达到上万美圆。而L7负载平衡服务器则可使用廉价服务器搭建。L3/4负载平衡服务器经常具备很是高的性能,而L7负载平衡服务器则经常经过组成一个集群来达到较高的总体性能。
在设计负载平衡系统时,还有一点须要考虑的那就是服务的动静分离。咱们知道,一个服务经常由动态请求和静态请求共同组成。这两种请求具备很是不一样的特色:一个动态请求经常须要大量的计算而传输的数据经常不是不少,而一个静态的请求经常须要传输大量的数据而不须要太多的计算。不一样的服务容器对这些请求的表现差别很大。所以不少服务经常将其所包含的服务实例分为两部分,分别用来处理静态请求和动态请求,并使用适合的服务容器提供服务。在这种状况下,静态请求经常被置于特定的路径下,如“/static”。这样负载平衡服务器就能够根据请求所发送到的路径而将动态请求和静态请求进行适当地转发。
最后要提到的就是L3/4负载平衡服务器的一个软件实现LVS(Linux Virtual Server)。相较于硬件实现,软件实现须要作不少额外的工做,例如对数据包的解码,为处理数据包分配内存等等呢个。所以其性能经常只是具备相同硬件能力的L3/4负载平衡服务器的1/5到1/10。鉴于其只具备有限的性能可是搭建起来成本很低,如利用已有的在Lab里闲置的机器等,所以其经常在服务规模不是很大的时候做为临时替代方案使用。
负载平衡解决方案
在文章的最后,咱们将给出一系列常见的负载平衡解决方案,以供你们参考。
在通常状况下,一个服务的负载经常是经过某些方式逐渐增加的。相应地,这些服务所拥有的负载平衡系统经常是从小到大逐渐演化的。所以咱们也将会按照从小到大的方式逐次介绍这些负载平衡系统。
首先是最简单的包含一对L7负载平衡服务器的系统:
若是服务的负载逐渐增大,那么该系统中惟一的L7负载平衡服务器很容易变成瓶颈。此时咱们能够经过添加一个SSL Farm以及运行LVS的服务器来解决问题:
若是咱们还要应对增加的负载,那么就须要使用真正的基于硬件的L3/4负载平衡服务器来替代LVS,并增长各层的容量:
因为该解决方案的下面三层基本都有理论上无限的扩展性,所以最容易出现过载的就是最上面的L3/4负载平衡服务器。在这种状况下,咱们就须要使用DNS来分配负载了:
转载请注明原文地址并标明转载:http://www.cnblogs.com/loveis715/p/4547968.html
商业转载请事先与我联系:silverfox715@sina.com