负载均衡 订阅
负载均衡建立在现有网络结构之上,它提供了一种廉价有效透明的方法扩展网络设备和服务器的带宽、增加吞吐量、加强网络数据处理能力、提高网络的灵活性和可用性。负载均衡(Load Balance)其意思就是分摊到多个操作单元上进行执行,例如Web服务器、FTP服务器、企业关键应用服务器和其它关键任务服务器等,从而共同完成工作任务。 展开全文
负载均衡建立在现有网络结构之上,它提供了一种廉价有效透明的方法扩展网络设备和服务器的带宽、增加吞吐量、加强网络数据处理能力、提高网络的灵活性和可用性。负载均衡(Load Balance)其意思就是分摊到多个操作单元上进行执行,例如Web服务器、FTP服务器、企业关键应用服务器和其它关键任务服务器等,从而共同完成工作任务。
信息
外文名
Load Balancing
别    称
负载分担
释    义
将负载进行平衡
中文名
负载均衡
负载均衡概述
负载均衡,英文名称为Load Balance,其含义就是指将负载(工作任务)进行平衡、分摊到多个操作单元上进行运行,例如FTP服务器、Web服务器、企业核心应用服务器和其它主要任务服务器等,从而协同完成工作任务。负载均衡构建在原有网络结构之上,它提供了一种透明且廉价有效的方法扩展服务器和网络设备的带宽、加强网络数据处理能力、增加吞吐量、提高网络的可用性和灵活性。
收起全文
精华内容
下载资源
问答
  • 负载均衡

    万次阅读 多人点赞 2018-05-28 10:08:23
    流量负载均衡介绍1 负载均衡产生的背景LB(Load Balance,负载均衡)是一种集群技术,它将特定的业务(网络服务、网络流量等)分担给多台网络设备(包括服务器、防火墙等)或多条链路,从而提高了业务处理能力,保证...

    流量负载均衡介绍

    1 负载均衡产生的背景

    LB(Load Balance,负载均衡)是一种集群技术,它将特定的业务(网络服务、网络流量等)分担给多台网络设备(包括服务器、防火墙等)或多条链路,从而提高了业务处理能力,保证了业务的高可靠性。

    负载均衡技术具有一下优势:

    (1)高性能:负载均衡技术将业务较均衡的分担到多台设备或链路上,从而提高了整个系统的性能;

    (2)可扩展性:负载均衡技术可以方便的增加集群中设备或链路的数量,在不降低业务质量的前提下满足不断增长的业务需求;

    (3)高可靠性:单个甚至多个设备或链路法神故障也不会导致业务中断,提高了整个系统的可靠性;

    (4)可管理性:大量的管理共组都集中在使用负载均衡技术的设备上,设备集群或链路集群只需要维护通过的配置即可;

    (5)透明性:对用户而言,集群等于一个或多个高可靠性、高性能的设备或链路,用户感知不到,也不关心具体的网络结构,增加或减少设备或链路数量都不会影响正常的业务。

    负载均衡技术分类:

    (1)             服务器负载均衡:在数据中心等组网环境中,可以采用服务器负载均衡,将网络服务分担给多台服务器进行处理,提高数据中心的业务处理能力;

    (2)             链路负载均衡:在有多个运营商出接口的组网环境中,可以采用出方向多链路动态负载均衡,实现链路的动态选择,提高服务的可靠性;

    (3)             防火墙负载均衡:在防火墙处理能力成为瓶颈的组网环境中,可以采用防火墙负载均衡,将网络流量分担给多台防火墙设备,提高防火桥的处理能力;

    1.1 服务器负载均衡

    随着Internet的快速发展和业务量的不断提高,基于网络的数据访问流量迅速增长,特别是对数据中心、大型企业以及门户网站等的访问,其访问流量甚至达到了10Gb/s的级别;同时,服务器网站借助HTTP,FTP,SMTP等应用程序,为访问者提供了越来越丰富的内容和信息,服务器逐渐被数据淹没;另外,大部分网站(尤其电子商务等网站)都需要提供不间断24小时服务,任何服务中断或通信中的关键数据丢失都会造成直接的商业损失。这些都对应用服务提出了高性能和高可靠性的需求。

    但是,相对于网络技术的发展,服务器处理器速度和内存访问速度的增长却远远低于网络带宽和应用服务的增长,网络带宽增长的同时带来的用户数量的增长,也使得服务器资源消耗严重,因而服务器成为了网络瓶颈;传统的单机模式,也往往成为网络故障点。

    1.1.1 服务器负载均衡解决方案

    多台服务器通过网络设备相连组成一个服务器集群,每台服务器都提供相同或相似的网络服务。服务器集群前端部署一台负载均衡设备,负责根据已配置均衡策略将用户请求在服务器集群中的分发,为用户提供服务,并对服务器可用性的维护。

    该方案的优势:

    (1)低成本:按照业务量增加服务器个数即可;已有资源不会浪费,新增资源无需选择昂贵的高端设备。

    (2)可扩展性:当业务量增长时,系统可通过增加服务器来满足需求,且不影响已有业务,不降低服务质量。

    (3)高可靠性:单台服务器故障时,由负载均衡设备将后续业务转向其他服务器,不影响后续业务提供,7 × 24小时业务不中断。

    1.2 链路负载均衡

    就互联网接入来说,众所周知,由于国内的两大运营商---电信与网通之间的瓶颈问题,导致电信网通用户互访时出现延迟较,响应缓慢,更有甚者会直接导致用户正常的业务无法运行。而且单条链路存在单点故障的隐患,当互联网链路DOWD掉时,可能引起的直接问题就是用户所有依赖互联网的业务及对互联网的访问都会因此而无法使用,这对于一个用户来说是无法想象的。

    目前在互联网接入时存在的主要问题:

    (1)电信网通瓶颈问题

    (2)单条链路存在单点故障

    (3)主备链路需要人工切换

    1.2.1 链路负载均衡解决方案

    通过接入电信网通两条(或多条链路)来保障网络的连通性,持续性以及快速访问。并提供各链路间的智能备份,实现链路级别的快速高可用。

    1.2.1.1 outbound方向链路负载均衡(从内到外的链路负载均衡)

    通过电信、网通双链路的接入,并使用静态和动态相结合的多链路负载均衡功能,使内部用户无论是访问网通资源还是电信资源,都可以从相应的线路进行访问.解决了从内到外的电信网通的互访瓶颈。

    1.2.1.2 inbound方向链路负载均衡(从外到内的链路负载均衡)

    解决外部用户访问内部服务器时所遇到的不同ISP的互访瓶颈.当ISP A的用户访问内部的www.abc.com时把ISP A接口的地址解析给用户,使其通过ISP A线路来访问www.abc.com. 当ISP B用户来访问内部的www.abc.com时,再把ISP B接口的地址解析给用户,使其通过ISP B的线路来访问www.abc.com.

    1.2.1.3 多条链并行使用以及智能备份

    多链路负载均衡还提供了链路的自动探测及备份功能,当某条链路断掉时,自动将流量切换到正常链路上,同时对外提供的访问,也将只解析正常链路的地址,使访问人员通过当前正常的链路来访问内部的服务。从进出双向来保障链路的正常工作。

    1.3 网关负载均衡

    SSL-VPN网关,IPSec网关,防火墙网关等网关设备,因为业务处理的复杂性,往往成为网络瓶颈,以防火墙网关为例:防火墙作为网络部署的“警卫”,在网络中不可或缺,但其往往不得不面临这样的尴尬:网络防卫越严格,需要越仔细盘查过往的报文,从而导致转发性能越低,成为网络瓶颈。

    在这种情况,如果废弃现有设备去做大量的硬件升级,必将造成资源浪费,随着业务量的不断提升,设备也将频繁升级。频繁升级的高成本是相当可怕的。因此将网关设备等同于服务器,组建网关集群的方案应运而生:将多个网关设备并联到网络中,从而形成集群处理能力,提高网络处理能力。

    1.3.1 网关负载均衡解决方案

    防火墙负载均衡包括以下几个基本元素:

    (1)      集群:提供网络流量负载均衡的群体,包括LB、Fireall;

    (2)      LB:负责分发请求发起方的网络流量到多台Firewall设备,LB又分为一级和二级,如果请求发起方的流量方向为Host A-àHost B,则LB A为一级,LB B为二级;方向类似;

    (3)      Firewall:正常处理数据的防火墙。

    2 负载均衡调度算法

    负载均和产品中的关键技术是调度,目前常用的调度算法有

    轮询(Round Robin

     

    加权轮询(Weighted Round Robin

     

     

     

    最少连接(Least Connections

     

     

     

    加权最少连接(Weighted Least Connections

     

     

     

    随机(Random

     

     

     

    加权随机(Weighted Random

     

     

     

    源地址散列(Source Hashing

     

     

     

    源地址端口散列(Source&Port Hashing

     

     

    2.1 负载均衡算法介绍

    (1)轮询算法

    新的连接被依次轮询分发到各个实服务上,比如第一个连接分发到第一台服务器,第二个连接分发到第二台服务器上;

    轮询算法适用于服务器集群中所有服务器都有相同的软硬件配置,并且平均服务器请求相对均衡的情况;

     

    (2)加权轮询算法

     

    根据服务器不同的处理能力,给服务器分配不同的权值,使其能接受相应权值的服务器请求;

    加权轮询算法能确保高性能的服务器能得到更多的使用率,避免低性能的服务器过载过重;

     

    (3)最少连接数算法

     

    最少连接数算法对内部需要负载的每一台服务器上的连接数都一个记录,记录当前该服务器正在处理的连接数,当有新的服务连接请求时,把请求分发给连接数最少的服务器,使均衡更加符合实际情况,负载更具啊均衡;

    最少连接数算法适合长时间处理的请求,例如:FTP。

    加权最少连接数算法,即将加权与连接数配合使用,根据连接数与加权的比例计算出当前请求应该分发给哪个具体的服务器;

     

    (4)随机算法

    将新连接请求随机分发给各个服务器;

    加权随机算法,即将加权与随机算法配合使用,根据随机数与加权的比例计算出当前请求应该分发给哪个具体的服务器;

     

    (5)源地址散列

    根据新连接请求的源IP地址进行散列HASH的结果,决定将请求分发给具体的服务器;

    来在相同客户端的连接会被分发到相同的服务器上;

     

    2.2 持续性

    将多个连接持续重定向到同一个服务器的策略,就是持续性功能。根据持续性原则,建立会话表项,保证后续业务报文都送往同一个服务器处理。比如使用源地址建立持续性表项,保证持续性。

    u  基于源IP地址的持续性功能:

    负载均衡设备接收到某一客户端的某一业务的首次请求时,建立持续性表项,记录为该客户分配的服务器情况,在会话表项生存周期内,后续该业务报文都将发往该服务器处理。基于源IP地址持续性功能的特点是:实现简洁快速。

    u  Cookies保持

    Cookies持续性利用客户机存储的cookies信息来吧客户机连接到合适的服务器上,其原理如下:

    (1)      首次命中Http请求(不带cookes)进行LB,此时LB任选一台服务器,将请求转发至该服务器;

    (2)      来自该服务器的Http回复报文此时包括一个空白的cookies,LB重写cookies,并再粘贴一个特殊的cookies后将http报文发送回去;

    (3)      再次命中Http请求(带有与上面形相同的cookies)进入LB,LB设备借助cookies信息确定合适的服务器;

    3 服务器负载均衡技术介绍

    3.1 概念介绍

    u  虚服务:负载均衡设备对外提供的服务称为虚服务,虚服务由VPN实例,虚服务IP地址、服务协议、服务端口号唯一标识,配置负载均衡设备上,客户的访问请求通过公关网络或私有网络到达负载均衡设备时,匹配到虚服务后,由负载均衡设备按照既定的策略分发给实服务;

    u  实服务:实服务器是真实服务器提供一种服务,该服务含义比较广泛,可以是传统的FTP,HTTP等业务,也可以是广泛的转发服务,如防火墙网关负载均衡中,实服务只是报文的转发路径;

    u  实服务组:为了便于对实服务进行管理,将多个实服务的一些共有属性提取出来形成实服务组,一个虚服务对应一个实服务组,一个实服务组对应多个实服务,相同的实服务组不能属于不同的虚服务;

    3.2 服务器负载均衡工作机制

    服务器负载均衡有两种工作方式:

    u  NAT(Network Address Translation,网络地址转换)方式

    u  直接路由(DirectRouting,简称DR)方式

    (1)NAT方式

    NAT方式组网灵活,后端服务器可以位于不同的物理位置,不同的局域网内。

    1、实现原理

    客户端将到VSIP的请求发送给服务器群前端的负载均衡设备,负载均衡设备上的虚服务接收客户端请求,通过调度算法,选择真实服务器,再通过网络地址转换,用真实服务器地址重写请求报文的目标地址后,将请求发送给选定的真实服务器;真实服务器的响应报文通过负载均衡设备时,报文的源地址被还原为虚服务的VSIP,再返回给客户,完成整个负载调度过程。

    2、技术特点

    组网灵活,对服务器没有额外要求,不需要修改服务器配置,适用于各种组网。

    步骤

    说明

    源IP

    目的IP

    1

    Host发放请求报文

    Host-IP

    VIP

    2

    LB收到请求报文后,根据调度算法计算出请求报文分发给哪台服务器

    -

    -

    3

    LB使用DNAT技术分发报文

    Host-IP

    Server IP

    4

    Server接收并处理请求,返回相应报文

    Server IP

    Host-IP

    5

    LB接收相应报文,转换源IP后转发

    VIP

    Host-IP

     

    (2)DR方式

    相对于NAT 组网方式,DR 组网方式,只有客户端的请求报文通过LB,服务器的响应报文不经过LB,从而减少了LB的负载,有效的避免了LB成为网络瓶颈。

    1、实现原理

    DR方式的服务器负载均衡时,除了LB设备上配置了VSIP,真实服务器也都配置了VSIP址,配置的VSIP要求不能响应ARP请求,例如在环回接口上配置VSIP。发送给VSIP的报文,由LB分发给相应的真实服务器,从真实服务器返回给客户端的报文直接通过交换机返回。

    2、技术特点

    只有单边报文经过负载均衡设备,负载均衡设备负担小,不易成为瓶颈,转发性能更强。

    步骤

    说明

    源IP

    目的IP

    1

    Host发放请求报文

    Host-IP

    VIP

    2

    General device收到请求后转发给LB,Server上的VIP不能发送和相应ARP报文,因此General device只能将报文转发给LB

    Host-IP

    VIP

    3

    LB使用调度算法决定将报文分发给哪台服务器,在封装报文时目的IP为VIP,目的MAC为Server的目的MAC(根据ARP请求Server IP获取)

    -

    -

    4

    LB转发报文给Server服务器

    Host-IP

    VIP

    MAC=Server-MAC

    5

    Server接收并处理请求,返回相应报文给General device

    VIP

    Host-IP

    6

    General device收到报文后,直接转发给Host

    VIP

    Host-IP

    3.3 服务器状态检查

    所谓状态检查就是指负载均衡设备定期对真实服务器运行状态进行探测,收集相应信息,及时隔离工作异常的服务器。健康检查的结果除标识服务器能否正常工作外,还可以统计出服务器影响时间,作为选择服务器的依据。负载均衡技术支持丰富的健康状态检查算法,可以有效地探测和检查服务器的运行状态。

    ICMP:向服务器发送ICMPEcho报文,若收到ICMP Reply,则服务器正常;

    TCP:向服务器的某端口建立TCP连接,若成功,则服务器正常;

    HTTP:和服务器的80端口建立TCP连接,然后发出HTTP请求,若所收到的HTTP应答内容争取,则服务器正常;

    FTP:和服务器21端口建立连接,然后获取一个服务器相关目录放置的文件,若所收到的文件内容正确,则服务器正常;

     

    4 链路负载技术介绍

    链路负载均衡根据业务流量方向可以分为outbound链路负载均衡和inbound链路负载均衡两种情况。

    4.1 outbound链路负载均衡

    内网用户和外网之间存在多条链路时,通过outbound链路负载均衡可以实现在多条链路上分担内网用户访问外网服务器的流量。

    1、  实现原理

    Outbound链路负载均衡中VSIP为内网用户发送报文的目的IP,用户将访问VSIP的报文发送到负载均衡设备上后,负载均衡设备依次根据持续性、ACL策略、就近性、调度算法选择最佳的物理链路,并将内网流量分发到该链路上。

    2、  技术特点

    可以和NAT应用网关共同组网,不同的链路使用不同的源地址,从而保证往返报文穿过同一条链路;

    通过健康性检查,可以检查链路内任意节点的连通性,从而有效保证整条链路上的可达性;

    通过调度算法,在多条链路间均衡流量,并支持按照带宽进行负载均衡;

    利用就近性算法动态计算链路的质量,将流量分发到当前最优链路上。

    步骤

    说明

    1

    LB设备接收到内网流量

    2

    LB设备依据就近性,ACL策略,持续性,调度算法选择链路

    3

    LB设备将流量分发到选择出的链路上

    4

    LB接收外网用户流量

    5

    LB将外网用户流量转发给设备

    4.2 inbound链路负载均衡

    内网和外网之间存在多条链路时,通过inbound链路负载均衡可以实现在多条链路上分担外网用户访问内网服务器的流量。

    1、  实现原理

    Inbound链路负载均衡中,负载均衡设备作为权威服务器记录域名与内网服务器IP地址的映射关系,一个域名可以映射多个IP地址,其中每个IP地址对应一条物理链路;

    外网用户通过域名方式访问内网服务器时 ,本地DNS服务器将域名解析请求发送给权威名称服务器——负载均衡设备,负载均衡设备依据持续性、ACL策略、就近性等算法选择最大的链路,并将通过该链路与外网接口的IP地址作为DNS解析结果反馈给外网用户,外网用户通过该链路访问内网服务器。

    2、  技术特点

    可以和服务器负载均衡配置使用,实现外网用户访问内网服务器的流量在多条链路间均衡的同时,也实现了流量在多台服务器间均衡;

    通过健康检查,可以检查链路内任意节点的连通性,从而有效保证整条链路的可达性;

    利用就近性算法动态计算链路的质量,保证转发流量的链路时当前最佳的链路。

    步骤

    说明

    1

    外网用户通过域名访问内网服务器时,首先要进行DNS解析,向本地DNS服务器发送DNS解析请求

    本地DNS服务器将DNS请求转发给权威的名称服务器——LB

    2

    LB设备根据请求的域名,持续性,ACL策略,就近性等算法选择最用的物理链路,并将给物理链路与外网连接的接口IP地址作为域名解析结果

    3

    LB设备将解析结果返回给本地DNS

    4

    本地DNS将结果返回给Host

    5

    用户使用返回的结果对内网发起访问

    5 网关负载均衡

    LB Device负载分发请求发起方的网络流量到多个网关设备,LB又分为一级和二级,如果请求发起方的网络流量为Host A->Host B,则LB Device A为一级,LB Device B为二级;

    网络设备:正常处理数据的网络设备;

    1、  实现原理

    防火墙是基于会话开展业务的,即一个会话的请求和应答报文必须通过同一个防火墙,为了保证防火墙业务正常进行,内部组网不受影响,需要采用双侧防火墙,即防火墙三明治。在这种组网环境中,对于流入流量一级LB设备做防火墙负载均衡,二级LB设备保证从哪个防火墙进来的流量,还要从哪个防火墙返回;流出链路正好相反。

    2、  技术特点

    服务对象为防火墙,提高防火墙组网灵活性。没有特殊要求,适用于任何组网环境。

    步骤

    说明

    1

    LB A接收网络流量

    2

    LB A根据调度算法将流量转发给某台Firewall

    3

    Firewall将流量转发给LB B

    4

    LB B记录转发流量的防火墙,并把流量转发到目的地

    5

    LB B接收来自目的地的回应流量

    6

    LB B根据记录将流量转发给相应的防火墙

    7

    Firewall将流量转发给LB A,LB A将流量转发回源地址

    防火墙负载均衡也可以服务器负载均衡配置使用:

    Cluster A为防火墙负载均衡的集权,ClusterB为服务器的负载均衡集群,综合组网的工作流程就是防火墙和服务器负载均衡的叠加,这种组网方式避免了防火墙称为网络中的瓶颈,也提高了网络服务的性能和可用性。

    6 智能选路

    智能选路系统——不仅仅是一项功能

    智能选路系统——是一系列功能组成的解决方案

    6.1 关键用户走某条优质链路——默认路由+策略路由

    选路原理

    关键用户走某条优质链路

    普通用户按照流量在出口设备被均衡分配

    优势

    实现简单,业内路由器均可支持

    缺点

    优质链路跑满,关键用户业务受影响

    存在跨运营商现象,影响用户上网体验

     

    6.2 从运营商下载IP列表——静态路由+默认路由

    选路原理

    从运营商下载ISP的IP地址列表

    通过静态路由的方式静态选路,访问电信的走电信,访问联调的走联调

    其余流量走大带宽链路(默认路由)

    优势

    解决了跨运营商问题,

    选择正确的IPS链路,保证用户体验

    实现简单,业内标准路由器都可以支持

    缺点

    1、ISP列表变化频繁,第一次实施后不易更新和维护

    2、若链路跑满,路由策略无法自动变更,例如:

    (a)电信链路跑满,联调链路空闲,若用户命中电信地址,仍然会选择电信链路,从而造成丢包

    (b)电信链路空闲,默认路由链路跑满,后续命中默认路由的数据仍会现则满载链路,造成丢包

    6.3 智能选路

    链路健康监测优先级最高,若链路失效,则链路上所有路由策略都会失效

    策略路由高于过载保护,即使某条链路负载已经超过设定的保护阀值,通过策略路由仍可使用该链路

    若应用路由、静态路由、地址库路由、默认路由中,存在等价路由,则可以通过MLLB进行负载

     

    6.4 链路过载保护

    链路负载超过设置的阈值,后续流量切换到其他链路

    切换的前提是NPE自动探测到链路到目的IP地址可到

    策略路由不受过载保护的影响

    6.5 应用路由

    首包识别数据流的应用,根据应用做选路,传统应用路由的难点:

    u  基于应用的路由,首先要把应用识别出来;

    u  目前应用的识别无外乎DPI,DFI等;

    u  DPI识别是通过7层特征识别,需要等待流的连接建立完成,7层协议开始传出后才能识别出来,简单的说,DPI的是被落后与连接的建立,当DPI识别出该应用的时候,连接已经建立起来,这时如果再做选路,必须首先要断掉之前建立的流连接;

    6.5.1 大流量协议识别

    技术点

    协议识别:

    大容量传输的应用通常有控制流量和传输流量,比如:FTP,迅雷,BT,电驴,QVOD等

    原理

    控制流量不做应用路由

    识别传输流量做应用路由

     

    6.5.2 DNS识别

    技术点

    特定网站,只需要截获DNS报文,就可以知道其类型。

    如:优酷、土豆、奇艺、新浪视频等

    原理

    监测DNS报文,发现URL请求是特定网站,记录DNS回应报文(即该网站的IP)进行路由,影响IP流量通过设备时会被路由到特定的链路上;

    若门户网站包含视频,则只监控视频类。如新浪,只监控video.sina.com.cn

     

    6.5.3 主动控制


    技术点

    P2P协议,如果断流,双方会发起重传机制

    原理

    对于P2P,在初期通过DPI、DFI识别后,主动将其切断;

    通过NPE记录的流信息,根据应用路由重传请求;

    用户端不会有任何感知;

     

    6.5.4 地址库

    技术点

    某些应用的目的IP固定,且流量大,如网盘、移动终端应用下载等

    原理

    人工收集此类应用的目的IP

     

    6.6 DNS代理

    u  DNS代理不属于路由体系,但能影响选路结果;所有的路由体系的选路都是目的IP通过DNS确认后,才开始工作的;而DNS代理是帮助用户获得更合理IP的技术,所以其生效是在路由体系之前;

    u  适用范围:目标URL拥有多个ISP的服务器(一般大型网站都如此);

    u  用户价值:在链路负载过高时,提升用户体验,合理分配目的IP所属运营商,结合地址库,使链路利用更均衡。(如,不开此功能,用户DHCP分配电信DNS,则10个网站解析出9个电信+1个联通,电信链路压力大;开启该功能后,解析出5个电信+5个联通,减小电信链路压力);

    6.6.1 DNS代理实现原理

     

    原理

    u  设备上开启DNS代理功能;

    u  配置电信和联调的DNS服务器;

    u  当有DNS请求到达设备时,设备会根据链路负载情况决定向电信DNS服务器或联调DNS服务器发送DNS请求报文;

    u  DNS回应报文到达设备后,设备透传给Host

     

    6.7 智能选路实现效果

    展开全文
  • 负载均衡Ribbon和Feign---SpringCloud

    万次阅读 2021-01-15 15:44:20
    负载均衡Ribbon和Feign Ribbon负载均衡(基于客户端) 6.1 负载均衡以及Ribbon Ribbon是什么? Spring Cloud Ribbon 是基于Netflix Ribbon 实现的一套客户端负载均衡的工具。 简单的说,Ribbon 是 Netflix 发布的...

    负载均衡Ribbon和Feign

    Ribbon负载均衡(基于客户端)

    6.1 负载均衡以及Ribbon

    Ribbon是什么?

    • Spring Cloud Ribbon 是基于Netflix Ribbon 实现的一套客户端负载均衡的工具
    • 简单的说,Ribbon 是 Netflix 发布的开源项目,主要功能是提供客户端的软件负载均衡算法,将 Netflix 的中间层服务连接在一起。Ribbon 的客户端组件提供一系列完整的配置项,如:连接超时、重试等。简单的说,就是在配置文件中列出 LoadBalancer (简称LB:负载均衡) 后面所有的及其,Ribbon 会自动的帮助你基于某种规则 (如简单轮询,随机连接等等) 去连接这些机器。我们也容易使用 Ribbon 实现自定义的负载均衡算法!

    Ribbon能干嘛?

    在这里插入图片描述

    • LB,即负载均衡 (LoadBalancer) ,在微服务或分布式集群中经常用的一种应用。
    • 负载均衡简单的说就是将用户的请求平摊的分配到多个服务上,从而达到系统的HA (高用)。
    • 常见的负载均衡软件有 Nginx、Lvs 等等。
    • Dubbo、SpringCloud 中均给我们提供了负载均衡,SpringCloud 的负载均衡算法可以自定义

    负载均衡简单分类

    • 集中式LB
      • 即在服务的提供方和消费方之间使用独立的LB设施,如Nginx(反向代理服务器),由该设施负责把访问请求通过某种策略转发至服务的提供方!
    • 进程式 LB
      • 将LB逻辑集成到消费方,消费方从服务注册中心获知有哪些地址可用,然后自己再从这些地址中选出一个合适的服务器。
      • Ribbon 就属于进程内LB,它只是一个类库,集成于消费方进程,消费方通过它来获取到服务提供方的地址!

    集成Ribbon

    springcloud-consumer-dept-80向pom.xml中添加Ribbon和Eureka依赖

    <!--Ribbon-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-ribbon</artifactId>
        <version>1.4.6.RELEASE</version>
    </dependency>
    <!--Eureka: Ribbon需要从Eureka服务中心获取要拿什么-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-eureka</artifactId>
        <version>1.4.6.RELEASE</version>
    </dependency>
    

    在application.yml文件中配置Eureka

    # Eureka配置
    eureka:
      client:
        register-with-eureka: false # 不向 Eureka注册自己
        service-url: # 从三个注册中心中随机取一个去访问
          defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
    

    主启动类加上@EnableEurekaClient注解,开启Eureka

    //Ribbon 和 Eureka 整合以后,客户端可以直接调用,不用关心IP地址和端口号
    @SpringBootApplication
    @EnableEurekaClient //开启Eureka 客户端
    public class DeptConsumer_80 {
        public static void main(String[] args) {
            SpringApplication.run(DeptConsumer_80.class, args);
        }
    }
    

    自定义Spring配置类:ConfigBean.java 配置负载均衡实现RestTemplate

    @Configuration
    public class ConfigBean {//@Configuration -- spring  applicationContext.xml
    
        @LoadBalanced //配置负载均衡实现RestTemplate
        @Bean
        public RestTemplate getRestTemplate() {
            return new RestTemplate();
        }
    }
    

    修改conroller:DeptConsumerController.java

    //Ribbon:我们这里的地址,应该是一个变量,通过服务名来访问
    //private static final String REST_URL_PREFIX = "http://localhost:8001";
    private static final String REST_URL_PREFIX = "http://SPRINGCLOUD-PROVIDER-DEPT";
    

    数据库导出

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9eSa5VMs-1610696634599)(C:\Users\王东梁\AppData\Roaming\Typora\typora-user-images\image-20210115135531598.png)]

    使用Ribbon实现负载均衡

    流程图:

    在这里插入图片描述

    1.新建两个服务提供者Moudle:springcloud-provider-dept-8003、springcloud-provider-dept-8002

    2.参照springcloud-provider-dept-8001 依次为另外两个Moudle添加pom.xml依赖 、resourece下的mybatis和application.yml配置,Java代码

    3.启动所有服务测试(根据自身电脑配置决定启动服务的个数),访问http://eureka7001.com:7002/查看结果

    在这里插入图片描述

    测试访问http://localhost/consumer/dept/list 这时候随机访问的是服务提供者8003

    在这里插入图片描述

    再次访问http://localhost/consumer/dept/list这时候随机的是服务提供者8001

    在这里插入图片描述

    以上这种每次访问http://localhost/consumer/dept/list随机访问集群中某个服务提供者,这种情况叫做轮询,轮询算法在SpringCloud中可以自定义。

    自定义负载均衡

    在springcloud-provider-dept-80模块下的ConfigBean中进行配置,切换使用不同的规则

    @Configuration
    public class ConfigBean {//@Configuration -- spring  applicationContext.xml
    
        /**
         * IRule:
         * RoundRobinRule 轮询策略
         * RandomRule 随机策略
         * AvailabilityFilteringRule : 会先过滤掉,跳闸,访问故障的服务~,对剩下的进行轮询~
         * RetryRule : 会先按照轮询获取服务~,如果服务获取失败,则会在指定的时间内进行,重试
         */
        @Bean
        public IRule myRule() {
            return new RandomRule();//使用随机策略
            //return new RoundRobinRule();//使用轮询策略
            //return new AvailabilityFilteringRule();//使用轮询策略
            //return new RetryRule();//使用轮询策略
        }
    }
    

    也可以自定义规则,在myRule包下自定义一个配置类MyRule.java,注意:该包不要和主启动类所在的包同级,要跟启动类所在包同级

    在这里插入图片描述

    MyRule.java

    /**
     * @Auther: csp1999
     * @Date: 2020/05/19/11:58
     * @Description: 自定义规则
     */
    @Configuration
    public class MyRule {
    
        @Bean
        public IRule myRule(){
            return new MyRandomRule();//默认是轮询RandomRule,现在自定义为自己的
        }
    }
    

    主启动类开启负载均衡并指定自定义的MyRule配置类

    //Ribbon 和 Eureka 整合以后,客户端可以直接调用,不用关心IP地址和端口号
    @SpringBootApplication
    @EnableEurekaClient
    //在微服务启动的时候就能加载自定义的Ribbon类(自定义的规则会覆盖原有默认的规则)
    @RibbonClient(name = "SPRINGCLOUD-PROVIDER-DEPT",configuration = MyRule.class)//开启负载均衡,并指定自定义的规则
    public class DeptConsumer_80 {
        public static void main(String[] args) {
            SpringApplication.run(DeptConsumer_80.class, args);
        }
    }
    

    自定义的规则(这里我们参考Ribbon中默认的规则代码自己稍微改动):MyRandomRule.java

    public class MyRandomRule extends AbstractLoadBalancerRule {
    
        /**
         * 每个服务访问5次则换下一个服务(总共3个服务)
         * <p>
         * total=0,默认=0,如果=5,指向下一个服务节点
         * index=0,默认=0,如果total=5,index+1
         */
        private int total = 0;//被调用的次数
        private int currentIndex = 0;//当前是谁在提供服务
    
        //@edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "RCN_REDUNDANT_NULLCHECK_OF_NULL_VALUE")
        public Server choose(ILoadBalancer lb, Object key) {
            if (lb == null) {
                return null;
            }
            Server server = null;
    
            while (server == null) {
                if (Thread.interrupted()) {
                    return null;
                }
                List<Server> upList = lb.getReachableServers();//获得当前活着的服务
                List<Server> allList = lb.getAllServers();//获取所有的服务
    
                int serverCount = allList.size();
                if (serverCount == 0) {
                    /*
                     * No servers. End regardless of pass, because subsequent passes
                     * only get more restrictive.
                     */
                    return null;
                }
    
                //int index = chooseRandomInt(serverCount);//生成区间随机数
                //server = upList.get(index);//从或活着的服务中,随机获取一个
    
                //=====================自定义代码=========================
    
                if (total < 5) {
                    server = upList.get(currentIndex);
                    total++;
                } else {
                    total = 0;
                    currentIndex++;
                    if (currentIndex > =upList.size()) {
                        currentIndex = 0;
                    }
                    server = upList.get(currentIndex);//从活着的服务中,获取指定的服务来进行操作
                }
                
                //======================================================
                
                if (server == null) {
                    /*
                     * The only time this should happen is if the server list were
                     * somehow trimmed. This is a transient condition. Retry after
                     * yielding.
                     */
                    Thread.yield();
                    continue;
                }
                if (server.isAlive()) {
                    return (server);
                }
                // Shouldn't actually happen.. but must be transient or a bug.
                server = null;
                Thread.yield();
            }
            return server;
        }
    
        protected int chooseRandomInt(int serverCount) {
            return ThreadLocalRandom.current().nextInt(serverCount);
        }
    
        @Override
        public Server choose(Object key) {
            return choose(getLoadBalancer(), key);
        }
    
        @Override
        public void initWithNiwsConfig(IClientConfig clientConfig) {
            // TODO Auto-generated method stub
        }
    }
    
    

    Feign负载均衡(基于服务端)

    7.1 Feign简介

    Feign是声明式Web Service客户端,它让微服务之间的调用变得更简单,类似controller调用service。SpringCloud集成了Ribbon和Eureka,可以使用Feigin提供负载均衡的http客户端

    只需要创建一个接口,然后添加注解即可~

    Feign,主要是社区版,大家都习惯面向接口编程。这个是很多开发人员的规范。调用微服务访问两种方法

    1. 微服务名字 【ribbon】
    2. 接口和注解 【feign】

    Feign能干什么?

    • Feign旨在使编写Java Http客户端变得更容易
    • 前面在使用Ribbon + RestTemplate时,利用RestTemplate对Http请求的封装处理,形成了一套模板化的调用方法。但是在实际开发中,由于对服务依赖的调用可能不止一处,往往一个接口会被多处调用,所以通常都会针对每个微服务自行封装一个客户端类来包装这些依赖服务的调用。所以,Feign在此基础上做了进一步的封装,由他来帮助我们定义和实现依赖服务接口的定义,在Feign的实现下,我们只需要创建一个接口并使用注解的方式来配置它 (类似以前Dao接口上标注Mapper注解,现在是一个微服务接口上面标注一个Feign注解),即可完成对服务提供方的接口绑定,简化了使用Spring Cloud Ribbon 时,自动封装服务调用客户端的开发量。

    Feign默认集成了Ribbon

    • 利用Ribbon维护了MicroServiceCloud-Dept的服务列表信息,并且通过轮询实现了客户端的负载均衡,而与Ribbon不同的是,通过Feign只需要定义服务绑定接口且以声明式的方法,优雅而简单的实现了服务调用。

    Feign的使用

    1. 创建springcloud-consumer-fdept-feign模块

      在这里插入图片描述

      拷贝springcloud-consumer-dept-80模块下的pom.xml,resource,以及java代码到springcloud-consumer-feign模块,并添加feign依赖。

      <!--Feign的依赖-->
      <dependency>
          <groupId>org.springframework.cloud</groupId>
          <artifactId>spring-cloud-starter-feign</artifactId>
          <version>1.4.6.RELEASE</version>
      </dependency>
      

      通过Ribbon实现:—原来的controller:DeptConsumerController.java

      /**
       * @Auther: csp1999
       * @Date: 2020/05/17/22:44
       * @Description:
       */
      @RestController
      public class DeptConsumerController {
      
          /**
           * 理解:消费者,不应该有service层~
           * RestTemplate .... 供我们直接调用就可以了! 注册到Spring中
           * (地址:url, 实体:Map ,Class<T> responseType)
           * <p>
           * 提供多种便捷访问远程http服务的方法,简单的Restful服务模板~
           */
          @Autowired
          private RestTemplate restTemplate;
      
          /**
           * 服务提供方地址前缀
           * <p>
           * Ribbon:我们这里的地址,应该是一个变量,通过服务名来访问
           */
      //    private static final String REST_URL_PREFIX = "http://localhost:8001";
          private static final String REST_URL_PREFIX = "http://SPRINGCLOUD-PROVIDER-DEPT";
      
          /**
           * 消费方添加部门信息
           * @param dept
           * @return
           */
          @RequestMapping("/consumer/dept/add")
          public boolean add(Dept dept) {
              // postForObject(服务提供方地址(接口),参数实体,返回类型.class)
              return restTemplate.postForObject(REST_URL_PREFIX + "/dept/add", dept, Boolean.class);
          }
      
          /**
           * 消费方根据id查询部门信息
           * @param id
           * @return
           */
          @RequestMapping("/consumer/dept/get/{id}")
          public Dept get(@PathVariable("id") Long id) {
              // getForObject(服务提供方地址(接口),返回类型.class)
              return restTemplate.getForObject(REST_URL_PREFIX + "/dept/get/" + id, Dept.class);
          }
      
          /**
           * 消费方查询部门信息列表
           * @return
           */
          @RequestMapping("/consumer/dept/list")
          public List<Dept> list() {
              return restTemplate.getForObject(REST_URL_PREFIX + "/dept/list", List.class);
          }
      }
      

      通过Feign实现:—改造后controller:DeptConsumerController.java

      /**
       * @Auther: csp1999
       * @Date: 2020/05/17/22:44
       * @Description:
       */
      @RestController
      public class DeptConsumerController {
      
          @Autowired
          private DeptClientService deptClientService;
      
          /**
           * 消费方添加部门信息
           * @param dept
           * @return
           */
          @RequestMapping("/consumer/dept/add")
          public boolean add(Dept dept) {
              return deptClientService.addDept(dept);
          }
      
          /**
           * 消费方根据id查询部门信息
           * @param id
           * @return
           */
          @RequestMapping("/consumer/dept/get/{id}")
          public Dept get(@PathVariable("id") Long id) {
             return deptClientService.queryById(id);
          }
      
          /**
           * 消费方查询部门信息列表
           * @return
           */
          @RequestMapping("/consumer/dept/list")
          public List<Dept> list() {
              return deptClientService.queryAll();
          }
      }
      

      Feign和Ribbon二者对比,前者显现出面向接口编程特点,代码看起来更清爽,而且Feign调用方式更符合我们之前在做SSM或者SprngBoot项目时,Controller层调用Service层的编程习惯!

      主配置类

      /**
       * @Auther: csp1999
       * @Date: 2020/05/17/22:47
       * @Description:
       */
      @SpringBootApplication
      @EnableEurekaClient
      // feign客户端注解,并指定要扫描的包以及配置接口DeptClientService
      @EnableFeignClients(basePackages = {"com.haust.springcloud"})
      // 切记不要加这个注解,不然会出现404访问不到
      //@ComponentScan("com.haust.springcloud")
      public class FeignDeptConsumer_80 {
          public static void main(String[] args) {
              SpringApplication.run(FeignDeptConsumer_80.class, args);
          }
      }
      
    2. 改造springcloud-api模块

      pom.xml添加feign依赖

      <!--Feign的依赖-->
      <dependency>
          <groupId>org.springframework.cloud</groupId>
          <artifactId>spring-cloud-starter-feign</artifactId>
          <version>1.4.6.RELEASE</version>
      </dependency>
      

      新建service包,并新建DeptClientService.java接口,

      package com.kuang.springcloud.controller;
      
      import com.kuang.springcloud.pojo.Dept;
      import com.kuang.springcloud.service.DeptClientService;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.web.bind.annotation.PathVariable;
      import org.springframework.web.bind.annotation.RequestMapping;
      import org.springframework.web.bind.annotation.RestController;
      
      import java.util.List;
      
      /**
       * @Auther: csp1999
       * @Date: 2020/05/17/22:44
       * @Description:
       */
      @RestController
      public class DeptConsumerController {
      
          @Autowired
          private DeptClientService deptClientService=null;
      
          /**
           * 消费方添加部门信息
           * @param dept
           * @return
           */
          @RequestMapping("/consumer/dept/add")
          public boolean add(Dept dept) {
              return deptClientService.addDept(dept);
          }
      
          /**
           * 消费方根据id查询部门信息
           * @param id
           * @return
           */
          @RequestMapping("/consumer/dept/get/{id}")
          public Dept get(@PathVariable("id") Long id) {
              return deptClientService.queryById(id);
          }
      
          /**
           * 消费方查询部门信息列表
           * @return
           */
          @RequestMapping("/consumer/dept/list")
          public List<Dept> list() {
              return deptClientService.queryAll();
          }
      }
      

    Feign VS Ribbon

    根据个人习惯而定,如果喜欢REST风格使用Ribbon;如果喜欢社区版的面向接口风格使用Feign.

    Feign 本质上也是实现了 Ribbon,只不过后者是在调用方式上,为了满足一些开发者习惯的接口调用习惯!

    下面我们关闭springcloud-consumer-dept-80 这个服务消费方,换用springcloud-consumer-dept-feign(端口还是80) 来代替:(依然可以正常访问,就是调用方式相比于Ribbon变化了)

    在这里插入图片描述

    展开全文
  • iis负载均衡iis负载均衡iis负载均衡
  • 负载均衡算法

    万次阅读 2019-10-10 17:11:02
    负载均衡算法 负载均衡算法说明 负载均衡介绍 负载均衡,英文名称为Load Balance,指由多台服务器以对称的方式组成一个服务器集合,每台服务器都具有等价的地位,都可以单独对外提供服务而无须其他服务器的辅助...

    负载均衡算法

    负载均衡算法说明
    • 负载均衡介绍
    • 负载均衡,英文名称为Load Balance,指由多台服务器以对称的方式组成一个服务器集合,每台服务器都具有等价的地位,都可以单独对外提供服务而无须其他服务器的辅助。
    • 通过某种负载分担技术,将外部发送过来的请求均匀分配到对称结构中的某一台服务器上,而接收到请求的服务器独立地回应客户的请求。
    • 负载均衡能够平均分配客户请求到服务器阵列,借此提供快速获取重要数据,解决大量并发访问服务问题,这种集群技术可以用最小的投资获得接近于大型主机的性能。
    • 负载均衡方式

    软件负载硬件负载

    • 软件负载均衡
    • 常见的负载均衡软件有:nginx,LVS,HAproxy
    • 资料:

    这三大软件负载均衡器优缺点:http://www.ha97.com/5646.html
    这三大软件负载均衡器的对比:http://www.21yunwei.com/archives/5824

    • 硬件负载均衡
    • 常见的负载均硬件件有:Array,F5
    • 负载均衡算法

    随机算法,加权轮询,一致性hash,最小活跃数算法

    负载均衡算法模拟
    • 数据支持
    • 在这里插入图片描述
    (1) 随机算法
    1、简单随机算法
    • 在这里插入图片描述

    这个简单随机算法使用与每天机器的性能差不多的时候,实际上,生产中可能某些机器的性能更高一点,它可以处理更多的情况,所以,我们可以对每台服务器设置一个权重。

    2、加权随机算法——V1
    • 在这里插入图片描述

    这个V1版本的加权随机算法的思路比较简单,每个服务器按它所对应的的权重进行复制。
    这种实现方法在遇到权重之和特别大的时候就会比较消耗内存,因为需要对ip地址进行复制,权重之和越大那么上文中的ips就需要越多的内存。

    3、加权随机算法——V2

    下面,介绍另一种实现思路。
    假设有一组服务器servers=[A,B,C],对应的权重weights=[5,3,2],权重总和为10。
    (1)现在把这些权重平铺在一维坐标上,那么就会有[0,5]区间属于服务器A,[5,8]区间属于服务器B,[8,10]区间属于服务器C。
    (2)接下来通过随机数生成一个范围在[0,10]之间的随机数,然后计算该随机数落在哪个区间上即可。

    • 在这里插入图片描述
    (2) 轮询算法
    1、简单轮询算法
    • 在这里插入图片描述

    这种简单轮询算法,很公平,每台服务器轮流来进行服务,但是有的机器性能好,所以能者多劳,和随机算法一样,所以,我们可以对每台服务器设置一个权重。

    2、加权轮询算法
    • 在这里插入图片描述

    加权轮询算法:
    思想:

    1. 例如有服务器servers=[A,B,C],对应权重weights=[2,5,1],总权重为8。
    2. 我们可以理解为有8台服务器,2台A,5台B,1台C,一次调用过来的时候,需
    3. 要按顺序访问,如有10次调用,调用顺序为AABBBBBCAA。

    步骤:

    1. 因为调用次数会越来越大,而服务器是固定,需要将调用次数“缩小”,取余
    2. 将权重值平铺在一维坐标值上:[0,2]为A,[2,7]为B,[7,8]为C
    3. 接下来获取该次是第几次请求,需要对总权重做取余运算,获取offset

    这种算法有一个缺点:一台服务器的权重特别大的时候,他需要连续的处理请求,但是实际上我们想达到的效果是,对于100次请求,只要有有100*8/50=16次就够了,这16次不一定要连续的访问,比如假设我们有三台服务器servers=[A,B,C],对应权重weights=[2,5,1],总权重为7,那么上述这算法的结果是AAAAABC,那么如果能够是这么一个结果呢:AABACAA,把B和C平均插入到5个A中间,这样是比较均衡的。

    3、平滑加权轮询算法

    那么就引出了平滑加权轮询
    思路:

    1. 每个服务器对应两个权重,分别为weight和currentWeight。其中weight是固定的,currentWeight会动态调整,初始值为0
    2. 当有新的请求进来时,遍历服务器列表,让它的currentWeight加上自身权重,遍历完成后,找到最大的currentWeight。
    3. 并将最大的currentWeight减去权重总和,然后返回相应的服务器即可。

    假设:
    测试数据:

    WEIGHT_LIST.put(“A”, 5);
    WEIGHT_LIST.put(“B”, 1);
    WEIGHT_LIST.put(“C”, 1);

    运算过程如下:

    次数当前currentWeight数组 (currentWeight+=weight)选择结果max(currentWeight)减去权重总和后的currentWeight数组 (max(currentWeight)-=sum(weight))
    1[5,1,1]A[-2,1,1]
    2[3,2,2]A[-4,2,2]
    3[1,3,3]B[1,-4,3]
    4[6,-3,4]A[-1,-3,4]
    5[4,-2,5]C[4,-2,-2]
    6[9,-1,-1]A[2,-1,-1]
    7[7,0,0]A[0,0,0]
    8[5,1,1]A[-2,1,1]

    如表所示,经过平滑行处理后,得到的服务器序列为[A,A,B,A,C,A,A],相比之前的序列[A,A,A,A,A,B,C],分布性要好一些。初始情况下currentWeight=[0,0,0] ,在第7个请求处理完后,currentWeight再次变回[0,0,0]。
    你会惊讶的发现在第8次的时候,当前currentWeight数组又变回了[5,1,1] !!!

    • 具体代码实现如下图:
    • 在这里插入图片描述
    (3) 一致性哈希算法

    服务器集群接收到一次请求调用时,可以根据请求的信息,比如客户端的ip地址,或请求路径与参数等信息进行哈希,可以得出一个哈希值,特点是对于相同的ip地址,或请求路径和请求参数哈希出来的值是一样,只要能再增加一个算法,能够把这个哈希值映射成一个服务端ip的地址,就可以使相同的请求落到同一服务器上。

    因为客户端发起的请求情况是无穷大的,所以对于哈希值也是无穷大的,所以不能把所有的哈希值都进行映射到服务器ip上,所以这里需要用到哈希环。如下图:

    • 在这里插入图片描述

    上面的情况是比较均匀,如果出现ip4服务器宕机了,那就是这样的了:

    • 在这里插入图片描述

    会发现ip3和ip1直接的范围是比较大的,会有更多的请求落到ip1上,这是不公平的,解决这个问题需要加入虚拟节点:

    • 在这里插入图片描述

    其中ip2-1,ip3-1就是虚拟结点,并不能处理节点,而是等同于对应的ip2和ip3服务器。
    实际上,这只是处理这种不均衡性的一种思路,实际上就算哈希环本身是均衡的,你也可以增加更多的虚拟节点来使这个环更加平衡,比如:

    • 在这里插入图片描述

    这个彩环也是公平的,并且只有ip1,ip2,ip3,ip4是实际的服务器ip,其他的都是虚拟ip。
    那么我们怎么实现呢?

    1. 对于我们的服务器ip地址,我们肯定是知道共有多少个,需要多少个虚拟节点也是我们自己控制,虚拟节点多则流量越均衡,另外哈希算法也是很关键的,哈希算法越散列流量也将越均衡。
    2. 这种环,可以使用TreeMap来存储;当一次请求过来,获取该请求的hash值,根据hash值从TreeMap中,拿大于该hash值的子树。
    3. 再从得到的子树中,拿第一个元素即可。
    • 具体代码实现:
    • 在这里插入图片描述
    (4) 最小活跃数算法

    前面几种方法主要目标是使服务端分配到的调用次数尽量均衡,但是实际情况是这样吗?
    调用次数相同,服务器的负载就均衡吗?
    当然不是,这里还要考虑每次调用的时间,而最小活跃数算法则是解决这种问题的。

    活跃调用数越小,表明该服务提供者效率越高,单位时间内可处理更多的请求。此时应优先将请求分配给该服
    务提供者。在具体实现中,每个服务提供者对应一个活跃数。初始情况下,所有服务提供者活跃数均为0。每
    收到一个请求,活跃数加1,完成请求后则将活跃数减1。在服务运行一段时间后,性能好的服务提供者处理请
    求的速度更快,因此活跃数下降的也越快,此时这样的服务提供者能够优先获取到新的服务请求、这就是最小
    活跃数负载均衡算法的基本思想。除了最小活跃数,最小活跃数算法在实现上还引入了权重值。所以准确的来
    说,最小活跃数算法是基于加权最小活跃数算法实现的。举个例子说明一下,在-一个服务提供者集群中,有两
    个性能优异的服务提供者。某一时刻它们的活跃数相同,则会根据它们的权重去分配请求,权重越大,获取到
    新请求的概率就越大。如果两个服务提供者权重相同,此时随机选择一个即可。

    实现:
    因为活跃数是需要服务器请求处理相关逻辑配合的,- -次调用开始时活跃数+1,结束是活跃数-1, 所以这里就
    不对这部分逻辑进行模拟了,直接使用一个map来进行模拟。

    • 具体代码实现:
    //最小活跃算法
    public class LeastActive {
        private static String getServer() {
            //找出当前活跃数最小的服务器
            Optional<Integer> minValue = ServerIps.ACTIVITY_LIST.values().stream().min(Comparator.naturalOrder());
            if (minValue.isPresent()) {
                List<String> minActivityIps = new ArrayList<>();
                ServerIps.ACTIVITY_LIST.forEach((ip, activity) -> {
                    if (activity.equals(minValue.get())) {
                        minActivityIps.add(ip);
                    }
                });
                //最小活跃数的ip有多个,则根据权重来选,权重大的优先
                if (minActivityIps.size() > 1) {
                    //过滤出对应的ip和权重
                    Map<String, Integer> weightList = new LinkedHashMap<>();
                    ServerIps.WEIGHT_LIST.forEach((ip, weight) -> {
                        if (minActivityIps.contains(ip)) {
                            weightList.put(ip, ServerIps.WEIGHT_LIST.get(ip));
                        }
                    });
                    int totalWeight = 0;
                    boolean sameWeight = true;
                    Object[] weights = weightList.values().toArray();
                    //计算出总的权重,判断所有权重是否一样
                    for (int i = 0; i < weights.length; i++) {
                        Integer weight = (Integer) weights[i];
                        totalWeight += weight;
                        if (sameWeight && i > 0 && !weight.equals(weights[i - 1])) {
                            sameWeight = false;
                        }
                    }
                    //生成一个在[0,totalWeight]区间内的随机数
                    java.util.Random random = new java.util.Random();
                    int randomPos = random.nextInt(totalWeight);
                    if (!sameWeight) {
                        for (String ip : weightList.keySet()) {
                            Integer weight = weightList.get(ip);
                            if (randomPos < weight) {
                                return ip;
                            }
                            randomPos = randomPos - weight;
                        }
                    }
                    //如果所有权重都一样,就使用随机算法
                    randomPos = random.nextInt(weightList.size());
                    return (String) weightList.keySet().toArray()[randomPos];
                } else {
                    return minActivityIps.get(0);
                }
            } else {
                java.util.Random random = new java.util.Random();
                int randomPos = random.nextInt(ServerIps.WEIGHT_LIST.size());
                return (String) ServerIps.WEIGHT_LIST.keySet().toArray()[randomPos];
            }
        }
        public static void main(String[] args) {
            for (int i=0; i<10; i++){
                System.out.println(getServer());
            }
        }
    }
    

    负载均衡总结:

    • 在这里插入图片描述
    • 参考资料:http://dubbo.apache.org/zh-cn/docs/source_code_guide/loadbalance.html
    展开全文
  • 负载均衡(汇总)

    万次阅读 2019-09-02 15:44:46
    一分钟了解负载均衡的一切 什么是负载均衡 负载均衡(Load Balance)是分布式系统架构设计中必须考虑的因素之一,它通常是指,将请求/数据【均匀】分摊到多个操作单元上执行,负载均衡的关键在于【均匀】。 ...

    微信搜索:“二十同学” 公众号,欢迎关注一条不一样的成长之路

    一分钟了解负载均衡的一切

    什么是负载均衡

    负载均衡(Load Balance)是分布式系统架构设计中必须考虑的因素之一,它通常是指,将请求/数据【均匀】分摊到多个操作单元上执行,负载均衡的关键在于【均匀】。

     

    常见的负载均衡方案


    常见互联网分布式架构如上,分为客户端层、反向代理nginx层、站点层、服务层、数据层。可以看到,每一个下游都有多个上游调用,只需要做到,每一个上游都均匀访问每一个下游,就能实现“将请求/数据【均匀】分摊到多个操作单元上执行”。

     

    【客户端层->反向代理层】的负载均衡


    【客户端层】到【反向代理层】的负载均衡,是通过“DNS轮询”实现的:DNS-server对于一个域名配置了多个解析ip,每次DNS解析请求来访问DNS-server,会轮询返回这些ip,保证每个ip的解析概率是相同的。这些ip就是nginx的外网ip,以做到每台nginx的请求分配也是均衡的。

     

    【反向代理层->站点层】的负载均衡


    【反向代理层】到【站点层】的负载均衡,是通过“nginx”实现的。通过修改nginx.conf,可以实现多种负载均衡策略:

    1)请求轮询:和DNS轮询类似,请求依次路由到各个web-server

    2)最少连接路由:哪个web-server的连接少,路由到哪个web-server

    3)ip哈希:按照访问用户的ip哈希值来路由web-server,只要用户的ip分布是均匀的,请求理论上也是均匀的,ip哈希均衡方法可以做到,同一个用户的请求固定落到同一台web-server上,此策略适合有状态服务,例如session(58沈剑备注:可以这么做,但强烈不建议这么做,站点层无状态是分布式架构设计的基本原则之一,session最好放到数据层存储)

    4)…

     

    【站点层->服务层】的负载均衡


    【站点层】到【服务层】的负载均衡,是通过“服务连接池”实现的。

    上游连接池会建立与下游服务多个连接,每次请求会“随机”选取连接来访问下游服务。

    【数据层】的负载均衡

    在数据量很大的情况下,由于数据层(db,cache)涉及数据的水平切分,所以数据层的负载均衡更为复杂一些,它分为“数据的均衡”,与“请求的均衡”。

    数据的均衡是指:水平切分后的每个服务(db,cache),数据量是差不多的。

    请求的均衡是指:水平切分后的每个服务(db,cache),请求量是差不多的。

    业内常见的水平切分方式有这么几种:

    一、按照range水平切分


    每一个数据服务,存储一定范围的数据,上图为例:

    user0服务,存储uid范围1-1kw

    user1服务,存储uid范围1kw-2kw

    这个方案的好处是:

    (1)规则简单,service只需判断一下uid范围就能路由到对应的存储服务

    (2)数据均衡性较好

    (3)比较容易扩展,可以随时加一个uid[2kw,3kw]的数据服务

    不足是:

    (1)请求的负载不一定均衡,一般来说,新注册的用户会比老用户更活跃,大range的服务请求压力会更大

     

    二、按照id哈希水平切分


    每一个数据服务,存储某个key值hash后的部分数据,上图为例:

    user0服务,存储偶数uid数据

    user1服务,存储奇数uid数据

    这个方案的好处是:

    (1)规则简单,service只需对uid进行hash能路由到对应的存储服务

    (2)数据均衡性较好

    (3)请求均匀性较好

    不足是:

    (1)不容易扩展,扩展一个数据服务,hash方法改变时候,可能需要进行数据迁移

     

    总结

    负载均衡(Load Balance)是分布式系统架构设计中必须考虑的因素之一,它通常是指,将请求/数据【均匀】分摊到多个操作单元上执行,负载均衡的关键在于【均匀】。

    (1)【客户端层】到【反向代理层】的负载均衡,是通过“DNS轮询”实现的

    (2)【反向代理层】到【站点层】的负载均衡,是通过“nginx”实现的

    (3)【站点层】到【服务层】的负载均衡,是通过“服务连接池”实现的

    (4)【数据层】的负载均衡,要考虑“数据的均衡”与“请求的均衡”两个点,常见的方式有“按照范围水平切分”与“hash水平切分”

     

    lvs为何不能完全替代DNS轮询

    对于接入层负载均衡技术,部分同学持这样的观点:

    1)nginx前端加入lvs和keepalived可以替代“DNS轮询”

    2)F5能搞定接入层高可用、扩展性、负载均衡,可以替代“DNS轮询”

    “DNS轮询”究竟是不是过时的技术,是不是可以被其他方案替代???”

    一、问题域

    nginx、lvs、keepalived、f5、DNS轮询,每每提到这些技术,往往讨论的是接入层的这样几个问题:

    1)可用性:任何一台机器挂了,服务受不受影响

    2)扩展性:能否通过增加机器,扩充系统的性能

    3)反向代理+负载均衡:请求是否均匀分摊到后端的操作单元执行

     

    二、上面那些名词都是干嘛的

    由于每个技术人的背景和知识域不同,上面那些名词缩写(运维的同学再熟悉不过了),还是花1分钟简单说明一下:

    1)nginx:一个高性能的web-server和实施反向代理的软件

    2)lvs:Linux Virtual Server,使用集群技术,实现在linux操作系统层面的一个高性能、高可用、负载均衡服务器

    3)keepalived:一款用来检测服务状态存活性的软件,常用来做高可用

    4)f5:一个高性能、高可用、负载均衡的硬件设备(听上去和lvs功能差不多?)

    5)DNS轮询:通过在DNS-server上对一个域名设置多个ip解析,来扩充web-server性能及实施负载均衡的技术

     

    三、接入层技术演进

    【裸奔时代(0)单机架构】


    裸奔时代的架构图如上:

    1)浏览器通过DNS-server,域名解析到ip

    2)浏览器通过ip访问web-server

    缺点

    1)非高可用,web-server挂了整个系统就挂了

    2)扩展性差,当吞吐量达到web-server上限时,无法扩容

    注:单机不涉及负载均衡的问题

     

    【简易扩容方案(1)DNS轮询】

    假设tomcat的吞吐量是1000次每秒,当系统总吞吐量达到3000时,如何扩容是首先要解决的问题,DNS轮询是一个很容易想到的方案:


    此时的架构图如上:

    1)多部署几份web-server,1个tomcat抗1000,部署3个tomcat就能抗3000

    2)在DNS-server层面,域名每次解析到不同的ip

    优点

    1)零成本:在DNS-server上多配几个ip即可,功能也不收费

    2)部署简单:多部署几个web-server即可,原系统架构不需要做任何改造

    3)负载均衡:变成了多机,但负载基本是均衡的

    缺点

    1)非高可用:DNS-server只负责域名解析ip,这个ip对应的服务是否可用,DNS-server是不保证的,假设有一个web-server挂了,部分服务会受到影响

    2)扩容非实时:DNS解析有一个生效周期

    3)暴露了太多的外网ip

     

    【简易扩容方案(2)nginx】

    tomcat的性能较差,但nginx作为反向代理的性能就强多了,假设线上跑到1w,就比tomcat高了10倍,可以利用这个特性来做扩容:


    此时的架构图如上:

    1)站点层与浏览器层之间加入了一个反向代理层,利用高性能的nginx来做反向代理

    2)nginx将http请求分发给后端多个web-server

    优点

    1)DNS-server不需要动

    2)负载均衡:通过nginx来保证

    3)只暴露一个外网ip,nginx->tomcat之间使用内网访问

    4)扩容实时:nginx内部可控,随时增加web-server随时实时扩容

    5)能够保证站点层的可用性:任何一台tomcat挂了,nginx可以将流量迁移到其他tomcat

    缺点

    1)时延增加+架构更复杂了:中间多加了一个反向代理层

    2)反向代理层成了单点,非高可用:tomcat挂了不影响服务,nginx挂了怎么办?

     

    【高可用方案(3)keepalived】

    为了解决高可用的问题,keepalived出场了:


    此时:

    1)做两台nginx组成一个集群,分别部署上keepalived,设置成相同的虚IP,保证nginx的高可用

    2)当一台nginx挂了,keepalived能够探测到,并将流量自动迁移到另一台nginx上,整个过程对调用方透明


    优点

    1)解决了高可用的问题

    缺点

    1)资源利用率只有50%

    2)nginx仍然是接入单点,如果接入吞吐量超过的nginx的性能上限怎么办,例如qps达到了50000咧?

     

    【scale up扩容方案(4)lvs/f5】

    nginx毕竟是软件,性能比tomcat好,但总有个上限,超出了上限,还是扛不住。

    lvs就不一样了,它实施在操作系统层面;f5的性能又更好了,它实施在硬件层面;它们性能比nginx好很多,例如每秒可以抗10w,这样可以利用他们来扩容,常见的架构图如下:


    此时:

    1)如果通过nginx可以扩展多个tomcat一样,可以通过lvs来扩展多个nginx

    2)通过keepalived+VIP的方案可以保证可用性

    99.9999%的公司到这一步基本就能解决接入层高可用、扩展性、负载均衡的问题。

     

    这就完美了嘛?还有潜在问题么?

    好吧,不管是使用lvs还是f5,这些都是scale up的方案,根本上,lvs/f5还是会有性能上限,假设每秒能处理10w的请求,一天也只能处理80亿的请求(10w秒吞吐量*8w秒),那万一系统的日PV超过80亿怎么办呢?(好吧,没几个公司要考虑这个问题)

     

    【scale out扩容方案(5)DNS轮询】

    如之前文章所述,水平扩展,才是解决性能问题的根本方案,能够通过加机器扩充性能的方案才具备最好的扩展性。

    facebook,google,baidu的PV是不是超过80亿呢,它们的域名只对应一个ip么,终点又是起点,还是得通过DNS轮询来进行扩容


    此时:

    1)通过DNS轮询来线性扩展入口lvs层的性能

    2)通过keepalived来保证高可用

    3)通过lvs来扩展多个nginx

    4)通过nginx来做负载均衡,业务七层路由

     

    四、结论

    聊了这么多,稍微做一个简要的总结:

    1)接入层架构要考虑的问题域为:高可用、扩展性、反向代理+扩展均衡

    2)nginx、keepalived、lvs、f5可以很好的解决高可用、扩展性、反向代理+扩展均衡的问题

    3)水平扩展scale out是解决扩展性问题的根本方案,DNS轮询是不能完全被nginx/lvs/f5所替代的

     

    末了,上一篇文章有同学留言问58到家采用什么方案,58到家目前部署在阿里云上,前端购买了SLB服务(可以先粗暴的认为是一个lvs+keepalived的高可用负载均衡服务),后端是nginx+tomcat。

     

    五、挖坑

    接入层讲了这么多,下一章,准备讲讲服务层“异构服务的负载均”(牛逼的机器应该分配更多的流量,如何做到?)。

     

    如何实施异构服务器的负载均衡及过载保护?

    “负载均衡是指,将请求/数据【均匀】分摊到多个操作单元上执行,负载均衡的关键在于【均匀】”。

    然而,后端的service有可能部署在硬件条件不同的服务器上

    1)如果对标最低配的服务器“均匀”分摊负载,高配的服务器的利用率不足;

    2)如果对标最高配的服务器“均匀”分摊负载,低配的服务器可能会扛不住;

    能否根据异构服务器的处理能力来动态、自适应进行负载均衡及过载保护,是本文要讨论的问题。

     

    一、service层的负载均衡通常是怎么做的


    service层的负载均衡,一般是通过service连接池来实现的,调用方连接池会建立与下游服务多个连接,每次请求“随机”获取连接,来保证service访问的均衡性。

    负载均衡、故障转移、超时处理等细节也都是通过调用方连接池来实现的。

    这个调用方连接池能否实现,根据service的处理能力,动态+自适应的进行负载调度呢?

     

    二、通过“静态权重”标识service的处理能力


    调用方通过连接池组件访问下游service,通常采用“随机”的方式返回连接,以保证下游service访问的均衡性。

     

    要打破这个随机性,最容易想到的方法,只要为每个下游service设置一个“权重”,代表service的处理能力,来调整访问到每个service的概率,例如:

    假设service-ip1,service-ip2,service-ip3的处理能力相同,可以设置weight1=1,weight2=1,weight3=1,这样三个service连接被获取到的概率分别就是1/3,1/3,1/3,能够保证均衡访问。

     

    假设service-ip1的处理能力是service-ip2,service-ip3的处理能力的2倍,可以设置weight1=2,weight2=1,weight3=1,这样三个service连接被获取到的概率分别就是2/4,1/4,1/4,能够保证处理能力强的service分别到等比的流量,不至于资源浪费。

     

    使用nginx做反向代理与负载均衡,就有类似的机制。

    这个方案的优点是:简单,能够快速的实现异构服务器的负载均衡。

    缺点也很明显:这个权重是固定的,无法自适应动态调整,而很多时候,服务器的处理能力是很难用一个固定的数值量化。

     

    三、通过“动态权重”标识service的处理能力

    提问:通过什么来标识一个service的处理能力呢?

    回答:其实一个service能不能处理得过来,能不能响应得过来,应该由调用方说了算。调用服务,快速处理了,处理能力跟得上;调用服务,处理超时了,处理能力很有可能跟不上了。

     

    动态权重设计

    1)用一个动态权重来标识每个service的处理能力,默认初始处理能力相同,即分配给每个service的概率相等;

    2)每当service成功处理一个请求,认为service处理能力足够,权重动态+1

    3)每当service超时处理一个请求,认为service处理能力可能要跟不上了,权重动态-10(权重下降会更快)

    4)为了方便权重的处理,可以把权重的范围限定为[0, 100],把权重的初始值设为60分

    举例说明:

    假设service-ip1,service-ip2,service-ip3的动态权重初始值weight1=weight2=weight3=60,刚开始时,请求分配给这3台service的概率分别是60/180,60/180,60/180,即负载是均衡的。

    随着时间的推移,处理能力强的service成功处理的请求越来越多,处理能力弱的service偶尔有超时,随着动态权重的增减,权重可能变化成了weight1=100,weight2=60,weight3=40,那么此时,请求分配给这3台service的概率分别是100/200,60/200,40/200,即处理能力强的service会被分配到更多的流量。

     

    四、过载保护

    提问:什么是过载保护?

    互联网软件架构设计中所指的过载保护,是指当系统负载超过一个service的处理能力时,如果service不进行自我保护,可能导致对外呈现处理能力为0,且不能自动恢复的现象。而service的过载保护,是指即使系统负载超过一个service的处理能力,service让能保证对外提供有损的稳定服务。

    提问:如何进行过载保护?

    回答:最简易的方式,服务端设定一个负载阈值,超过这个阈值的请求压过来,全部抛弃。这个方式不是特别优雅。

     

    五、如何借助“动态权重”来实施过载保护

    动态权重是用来标识每个service的处理能力的一个值,它是RPC-client客户端连接池层面的一个东东。服务端处理超时,客户端RPC-client连接池都能够知道,这里只要实施一些策略,就能够对“疑似过载”的服务器进行降压,而不用服务器“抛弃请求”这么粗暴的实施过载保护。

    应该实施一些什么样的策略呢,例如:

    1)如果某一个service的连接上,连续3个请求都超时,即连续-10分三次,客户端就可以认为,服务器慢慢的要处理不过来了,得给这个service缓一小口气,于是设定策略:接下来的若干时间内,例如1秒(或者接下来的若干个请求),请求不再分配给这个service;

    2)如果某一个service的动态权重,降为了0(像连续10个请求超时,中间休息了3次还超时),客户端就可以认为,服务器完全处理不过来了,得给这个service喘一大口气,于是设定策略:接下来的若干时间内,例如1分钟(为什么是1分钟,根据经验,此时service一般在发生fullGC,差不多1分钟能回过神来),请求不再分配给这个service;

    3)可以有更复杂的保护策略…

    这样的话,不但能借助“动态权重”来实施动态自适应的异构服务器负载均衡,还能在客户端层面更优雅的实施过载保护,在某个下游service快要响应不过来的时候,给其喘息的机会。

    需要注意的是:要防止客户端的过载保护引起service的雪崩,如果“整体负载”已经超过了“service集群”的处理能力,怎么转移请求也是处理不过来的,还得通过抛弃请求来实施自我保护。

    六、总结

    1)service的负载均衡、故障转移、超时处理通常是RPC-client连接池层面来实施的

    2)异构服务器负载均衡,最简单的方式是静态权重法,缺点是无法自适应动态调整

    3)动态权重法,可以动态的根据service的处理能力来分配负载,需要有连接池层面的微小改动

    4)过载保护,是在负载过高时,service为了保护自己,保证一定处理能力的一种自救方法

    5)动态权重法,还可以用做service的过载保护

     

    单点系统架构的可用性与性能优化

    一、需求缘起

    明明架构要求高可用,为何系统中还会存在单点?

    回答:单点master的设计,会大大简化系统设计,何况有时候避免不了单点

     

    在哪些场景中会存在单点?先来看一下一个典型互联网高可用架构。


    典型互联网高可用架构:

    (1)客户端层,这一层是浏览器或者APP,第一步先访问DNS-server,由域名拿到nginx的外网IP

    (2)负载均衡层,nginx是整个服务端的入口,负责反向代理与负载均衡工作

    (3)站点层,web-server层,典型的是tomcat或者apache

    (4)服务层,service层,典型的是dubbo或者thrift等提供RPC调用的后端服务

    (5)数据层,包含cache和db,典型的是主从复制读写分离的db架构

    在这个互联网架构中,站点层、服务层、数据库的从库都可以通过冗余的方式来保证高可用,但至少

    (1)nginx层是一个潜在的单点

    (2)数据库写库master也是一个潜在的单点

     

    再举一个GFS(Google File System)架构的例子。


    GFS的系统架构里主要有这么几种角色:

    (1)client,就是发起文件读写的调用端

    (2)master,这是一个单点服务,它有全局事业,掌握文件元信息

    (3)chunk-server,实际存储文件额服务器

    这个系统里,master也是一个单点的服务,Map-reduce系统里也有类似的全局协调的master单点角色。

     

    系统架构设计中,像nginx,db-master,gfs-master这样的单点服务,会存在什么问题,有什么方案来优化呢,这是本文要讨论的问题。

     

    二、单点架构存在的问题

    单点系统一般来说存在两个很大的问题:

    (1)非高可用:既然是单点,master一旦发生故障,服务就会受到影响

    (2)性能瓶颈:既然是单点,不具备良好的扩展性,服务性能总有一个上限,这个单点的性能上限往往就是整个系统的性能上限

    接下来,就看看有什么优化手段可以优化上面提到的两个问题

    三、shadow-master解决单点高可用问题

    shadow-master是一种很常见的解决单点高可用问题的技术方案。

    “影子master”,顾名思义,服务正常时,它只是单点master的一个影子,在master出现故障时,shadow-master会自动变成master,继续提供服务。

    shadow-master它能够解决高可用的问题,并且故障的转移是自动的,不需要人工介入,但不足是它使服务资源的利用率降为了50%,业内经常使用keepalived+vip的方式实现这类单点的高可用

     


    以GFS的master为例,master正常时:

    (1)client会连接正常的master,shadow-master不对外提供服务

    (2)master与shadow-master之间有一种存活探测机制

    (3)master与shadow-master有相同的虚IP(virtual-IP)

     


    当发现master异常时:

    shadow-master会自动顶上成为master,虚IP机制可以保证这个过程对调用方是透明的

     

    除了GFS与MapReduce系统中的主控master,nginx亦可用类似的方式保证高可用,数据库的主库master(主库)亦可用类似的方式来保证高可用,只是细节上有些地方要注意:


    传统的一主多从,读写分离的db架构,只能保证读库的高可用,是无法保证写库的高可用的,要想保证写库的高可用,也可以使用上述的shadow-master机制:


    (1)两个主库设置相互同步的双主模式

    (2)平时只有一个主库提供服务,言下之意,shadow-master不会往master同步数据

    (3)异常时,虚IP漂移到另一个主库,shadow-master变成主库继续提供服务

    需要说明的是,由于数据库的特殊性,数据同步需要时延,如果数据还没有同步完成,流量就切到了shadow-master,可能引起小部分数据的不一致。

     

    四、减少与单点的交互,是存在单点的系统优化的核心方向

    既然知道单点存在性能上限,单点的性能(例如GFS中的master)有可能成为系统的瓶颈,那么,减少与单点的交互,便成了存在单点的系统优化的核心方向。

    怎么来减少与单点的交互,这里提两种常见的方法。

    批量写

    批量写是一种常见的提升单点性能的方式。

    例如一个利用数据库写单点生成做“ID生成器”的例子:


    (1)业务方需要ID

    (2)利用数据库写单点的auto increament id来生成和返回ID

    这是一个很常见的例子,很多公司也就是这么生成ID的,它利用了数据库写单点的特性,方便快捷,无额外开发成本,是一个非常帅气的方案。

    潜在的问题是:生成ID的并发上限,取决于单点数据库的写性能上限。

    如何提升性能呢?批量写

     


    (1)中间加一个服务,每次从数据库拿出100个id

    (2)业务方需要ID

    (3)服务直接返回100个id中的1个,100个分配完,再访问数据库

    这样一来,每分配100个才会写数据库一次,分配id的性能可以认为提升了100倍。

     

    客户端缓存

    客户端缓存也是一种降低与单点交互次数,提升系统整体性能的方法。

    还是以GFS文件系统为例:


    (1)GFS的调用客户端client要访问shenjian.txt,先查询本地缓存,miss了

    (2)client访问master问说文件在哪里,master告诉client在chunk3上

    (3)client把shenjian.txt存放在chunk3上记录到本地的缓存,然后进行文件的读写操作

    (4)未来client要访问文件,从本地缓存中查找到对应的记录,就不用再请求master了,可以直接访问chunk-server。如果文件发生了转移,chunk3返回client说“文件不在我这儿了”,client再访问master,询问文件所在的服务器。

     

    根据经验,这类缓存的命中非常非常高,可能在99.9%以上(因为文件的自动迁移是小概率事件),这样与master的交互次数就降低了1000倍。

     

    五、水平扩展是提升单点系统性能的好方案

    无论怎么批量写,客户端缓存,单点毕竟是单机,还是有性能上限的。

    想方设法水平扩展,消除系统单点,理论上才能够无限的提升系统系统。

    以nginx为例,如何来进行水平扩展呢?


    第一步的DNS解析,只能返回一个nginx外网IP么?答案显然是否定的,“DNS轮询”技术支持DNS-server返回不同的nginx外网IP,这样就能实现nginx负载均衡层的水平扩展。

     


    DNS-server部分,一个域名可以配置多个IP,每次DNS解析请求,轮询返回不同的IP,就能实现nginx的水平扩展,扩充负载均衡层的整体性能。

     

    数据库单点写库也是同样的道理,在数据量很大的情况下,可以通过水平拆分,来提升写入性能。

     

    遗憾的是,并不是所有的业务场景都可以水平拆分,例如秒杀业务,商品的条数可能不多,数据库的数据量不大,就不能通过水平拆分来提升秒杀系统的整体写性能(总不能一个库100条记录吧?)。

     

    六、总结

    今天的话题就讨论到这里,内容很多,占用大家宝贵的时间深表内疚,估计大部分都记不住,至少记住这几个点吧:

    (1)单点系统存在的问题:可用性问题,性能瓶颈问题

    (2)shadow-master是一种常见的解决单点系统可用性问题的方案

    (3)减少与单点的交互,是存在单点的系统优化的核心方向,常见方法有批量写,客户端缓存

    (4)水平扩展也是提升单点系统性能的好方案

    集群信息管理,架构设计中最容易遗漏的一环

    • 是什么

    • 什么场景,为什么会用到,存在什么问题

    • 常见方案及痛点

    • 不同阶段公司,不同实现方案

    一、啥是集群?

    互联网典型分层架构如下:

    • web-server层

    • service层

    • db层与cache层

     

    为了保证高可用,每一个站点、服务、数据库、缓存都会冗余多个实例,组成一个分布式的系统,集群则是一个分布式的物理形态。

     

    额,好拗口,通俗的说,集群就是一堆机器,上面部署了提供相似功能的站点,服务,数据库,或者缓存。

    如上图:

    • web集群,由web.1和web.2两个实例组成

    • service集群,由service.1/service.2/service.3三个实例组成

    • db集群,由mysql-M/mysql-S1/mysql-S2三个实例组成

    • cache集群,由cache-M/cache-S两个实例组成

     

    与“集群”相对应的是“单机”。

    画外音:关于高可用架构,详见文章《究竟啥才是互联网架构“高可用”》。

    画外音:缓存如果没有高可用要求,可能是单机架构,而不是集群。

     

    二、集群信息

    什么是集群信息?

    一个集群,会包含若干信息(额,这tm算什么解释),例如:

    • 集群名称

    • IP列表

    • 二进制目录

    • 配置目录

    • 日志目录

    • 负责人列表

    画外音:集群IP列表不建议直接使用IP,而建议使用内网域名,详见文章《小小的IP,大大的耦合》。

     

    什么时候会用到集群信息呢?

    很多场景,特别是线上操作,都会使用到各种集群信息,例如:

    • 自动化上线

    • 监控

    • 日志清理

    • 二进制与配置的备份

    • 下游的调用(额,这个最典型)

     

    这些场景,分别都是如何读取集群信息的?

    一般来说,早期会把集群信息写在配置文件里。

     

    例如,自动化上线,有一个配置文件,deploy.user.service.config,其内容是:

    name : user.service

    ip.list : ip1, ip2, ip3

    bin.path : /user.service/bin/

    ftp.path : ftp://192.168.0.1/USER_2_0_1_3/user.exe

     

    自动化上线的过程,则是:

    • 把可执行文件从ftp拉下来

    • 读取集群IP列表

    • 读取二进制应该部署的目录

    • 把二进制部署到线上

    • 逐台重启

    画外音:啥,还没有实现自动化脚本部署?还处在运维ssh到线上,手动执行命令,逐台机器人肉部署的刀耕火种阶段?赶紧照着这个方案,做自动化改造吧。

    又例如,web-X调用下游的user服务,又有一个配置文件,web-X.config,其内容配置了:

    service.name : user.service

    service.ip.list : ip1, ip2, ip3

    service.port : 8080

    web-X调用user服务的过程,则是:

    • web-X启动

    • web-X读取user服务集群的IP列表与端口

    • web-X初始化user服务连接池

    • web-X拿取user服务的连接,通过RPC接口调用user服务

    日志清理,服务监控,二进制备份的过程,也都与上述类似。

    三、存在什么问题?

    上述业务场景,对于集群信息的使用,有两个最大的特点

    • 每个应用场景,所需集群信息都不一样(A场景需要集群abc信息,B场景需要集群def信息)

    • 每个应用场景,集群信息都写在“自己”的配置文件里

    一句话总结:集群信息管理分散化。

    这里最大的问题,是耦合,当集群的信息发生变化的时候,有非常多的配置需要修改:

    • deploy.user.service.config

    • clean.log.user.service.config

    • backup.bin.user.service.config

    • monitor.config

    • web-X.config

    这些配置里,user服务集群的信息都需要修改:

    • 随着研发、测试、运维人员的流动,很多配置放在哪里,逐步就被遗忘了

    • 随着时间的推移,一些配置就被改漏了

    • 逐渐的,莫名其妙的问题出现了

    画外音:ca,谁痛谁知道

    如何解决上述耦合的问题呢?

    一句话回答:集群信息管理集中化。

    四、如何集中化管理集群信息

    如何集中化管理集群配置信息,不同发展阶段的公司,实现的方式不一样。

     

    早期方案

    通过全局配置文件,实现集群信息集中管理,举例global.config如下:

    [user.service]

    ip.list : ip1, ip2, ip3

    port : 8080

    bin.path : /user.service/bin/

    log.path : /user.service/log/

    conf.path : /user.service/conf/

    ftp.path :ftp://192.168.0.1/USER_2_0_1_3/user.exe

    owner.list : shenjian, zhangsan, lisi

     

    [passport.web]

    ip.list : ip11, ip22, ip33

    port : 80

    bin.path : /passport.web/bin/

    log.path : /passport.web/log/

    conf.path : /passport.web/conf/

    ftp.path :ftp://192.168.0.1/PST_1_2_3_4/passport.jar

    owner.list : shenjian, zui, shuaiqi

     

    集中维护集群信息之后:

    • 任何需要读取集群信息的场景,都从global.config里读取

    • 任何集群信息的修改,只需要修改global.config一处

    • global.config会部署到任何一台线上机器,维护和管理也很方便

    画外音:额,当然,信息太多的话,global.config也要垂直拆分

     

    中期方案

    随着公司业务的发展,随着技术团队的扩充,随着技术体系的完善,通过集群信息管理服务,来维护集群信息的诉求原来越强烈。

    画外音:慢慢的,配置太多了,通过global.config来修改配置太容易出错了

    如上图,建立集群信息管理服务

    • info.db :存储集群信息

    • info.cache :缓存集群信息

    • info.service :提供集群信息访问的RPC接口,以及HTTP接口

    • info.web :集群信息维护后台

     

    服务的核心接口是:

    Info InfoService::getInfo(String ClusterName);

    Bool InfoService::setInfo(String ClusterName, String key, String value);

     

    然后,统一通过服务来获取与修改集群信息:

    • 所有需要获取集群信息的场景,都通过info.service提供的接口来读取集群信息

    • 所有需要修改集群信息的场景,都通过info.web来操作

     

    长期方案

    集群信息服务可以解决大部分的耦合问题,但仍然有一个不足:集群信息变更时,无法反向实时通知关注方,集群信息发生了改变。更长远的,要引入配置中心来解决。

    配置中心的细节,网上的分析很多,之前也撰文写过,细节就不再本文展开。

     

    五、总结

    集群信息管理,是架构设计中非常容易遗漏的一环,但又是非常基础,非常重要的基础设施,一定要在早期规划好:

    • 传统的方式,分散化管理集群信息,容易导致耦合

    • 集中管理集群信息,有全局配置,信息服务,配置中心三个阶段

    展开全文
  • 首先我们先介绍一下什么是负载均衡:负载平衡(Loadbalancing)是一种计算机网络技术,用来在多个计算机(计算机集群)、网络连接、CPU、磁盘驱动器或其他资源中分配负载,以达到最佳化资源使用、最大化吞吐率、最小...
  • 高并发解决方案之一 ——负载均衡

    万次阅读 多人点赞 2018-04-15 21:52:15
    1.什么是负载均衡?当一台服务器的性能达到极限时,我们可以使用服务器集群来提高网站的整体性能。那么,在服务器集群中,需要有一台服务器充当调度者的角色,用户的所有请求都会首先由它接收,调度者再根据每台...
  • 0.负载均衡 负载均衡 建立在现有网络结构之上,它提供了一种廉价有效透明的方法扩展网络设备和服务器的带宽、增加吞吐量、加强网络数据处理能力、提高网络的灵活性和可用性。 负载均衡,英文名称为Load Balance,...
  • nginx一般可以用于七层的负载均衡,这篇文章将介绍一些负载均衡的基本知识以及使用nginx进行负载均衡的简单的例子。 四层负载均衡 vs 七层负载均衡 经常会说七层负载均衡还是四层负载均衡,其实根据ISO的OSI网络模型...
  • 动静分离二、Nginx 的安装三、 Nginx 的常用命令和配置文件四、 Nginx 配置实例 1 反向代理五、 Nginx 配置实例 2 负载均衡六、 Nginx 配置实例 3 动静分离七、 Nginx 的高可用集群 前言 一、nginx简介...
  • 负载均衡不只是为了计算单元的负载达到均衡状态,他依据分配算法目标,有的基于负载考虑,有的基于性能(吞吐量、响应时间)考虑,有的基于业务考虑。 DNS 负载均衡 DNS 是最简单也是最常见的负载均衡方式,一般...
  • 客户端与弹簧云负载均衡器的负载均衡
  • (三 Ribbon 什么是负载均衡?spring cloud如何实现负载均衡)手摸手带你一起搭建 Spring cloud 微服务 理论+实践+解析 配套例程资源
  • 对于等价负载均衡来说,所有的IGP路由协议都支持等价负载均衡,所谓等价负载均衡是指同一种路由协议到达同一个目的地址(子网掩码位数也必须相同)的开销相同,此时会自动形成等价负载均衡。而非等价负载均衡只有IGP...
  • 相关配置基于:轮循负载均衡 首先关闭防火墙service iptables stop 加权负载均衡 nginx配置,找到自己nginx安装目录下的nginx.conf文件,我默认安装在 /usr/local/nginx/ 目录vim /usr/local/nginx/conf/nginx.conf ...
  • DNS负载均衡与NGINX负载均衡策略

    万次阅读 2017-11-23 23:00:17
    一般常见的负载均衡有两种:①客户端与反向代理服务器之间的DNS负载均衡②反向代理服务器与应用服务器之间的负载均衡(这种负载均衡有很多,可以是weblogic的负载均衡,可以是Apache+Tomcat负载均衡,也可以是nginx...
  • 负载均衡解决方案 负载均衡解决方案 负载均衡解决方案
  • 使用Nginx实现负载均衡

    万次阅读 多人点赞 2018-08-28 17:48:52
    负载均衡的作用 负载均衡:分摊到多个操作单元上进行执行,和它的英文名称很匹配。就是我们需要一个调度者,保证所有后端服务器都将性能充分发挥,从而保持服务器集群的整体性能最优,这就是负载均衡负载均衡这...
  • F5负载均衡

    2018-12-11 12:56:59
    F5负载均衡实施方案,详细介绍了关于F5负载均衡的相关应用

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 489,763
精华内容 195,905
关键字:

负载均衡