ribbon负载均衡详解

ribbon负载均衡详解,第1张

服务端负载均衡:在客户端和服务端中间使用代理,lvs  和 nginx。

硬件负载均衡的设备或是软件负载均衡的软件模块都会维护一个下挂可用的服务端清单,通过心跳检测来剔除故障的服务端节点以保证清单中都是可以正常访问的服务端节点。当客户端发送请求到负载均衡设备的时候,该设备按某种算法(比如线性轮询、按权重负载、按流量负载等)从维护的可用服务端清单中取出一台服务端端地址,然后进行转发。

客户端负载均衡:根据自己的情况做负载。Ribbon。

客户端负载均衡和服务端负载均衡最大的区别在于 服务端地址列表的存储位置,以及负载算法在哪里。

2、Spring Cloud的负载均衡机制的实现

Spring Cloud Ribbon是一个基于HTTP和TCP的客户端负载均衡工具,它基于Netflix Ribbon实现。通过Spring Cloud的封装,可以让我们轻松地将面向服务的REST模版请求自动转换成客户端负载均衡的服务调用。Ribbon实现客户端的负载均衡,负载均衡器提供很多对http和tcp的行为控制。Spring cloud Feign已经集成Ribbon,所以注解@FeignClient的类,默认实现了ribbon的功能。

Ribbon主要包括如下功能

1.支持通过DNS和IP和服务端通信

2.可以根据算法从多个服务中选取一个服务进行访问

3.通过将客户端和服务器分成几个区域(zone)来建立客户端和服务器之间的关系。客户端尽量访问和自己在相同区域(zone)的服务,减少服务的延迟

4.保留服务器的统计信息,ribbon可以实现用于避免高延迟或频繁访问故障的服务器

5.保留区域(zone)的统计数据,ribbon可以实现避免可能访问失效的区域(zone)

Ribbon负载均衡主要是通过LoadBalancerClient类实现的,而LoadBalancerClient又将具体处理委托给ILoadBalancer处理;

每个服务都有一个ILoadBalancer,ILoadBalancer里面有该服务列表。

每个服务 Map<服务名,ILoadBalancer>

ILoadBalancer通过配置IRule、IPing等信息,并通过ServerList获取服务器注册列表的信息,默认以每10s的频率想服务列表中每个服务实例发送ping请求,检测服务实例是否存活,最后使用负责均衡策略对ServerListFilter过滤得到最终可用的服务实例列表进行处理,然后交给服务调用器进行调用;

ILoadBalance也是一个接口,提供了3个具体实现,分别是DynamicServerListLoadBalancer、ZoneAwareLoadBalancer和NoOpLoadBalancer;

DynamicServerListLoadBalancer继承自ILoadBalancer基础实现BaseLoadBalancer,在基础的负载均衡功能上增加了运行期间对服务实例动态更新和过滤的功能;

NoOpLoadBalancer没有操作的实现;

ZoneAwareLoadBalancer(ILoadBalancer的默认的实现类是:ZoneAwareLoadBalancer。)则是继承DynamicServerListLoadBalancer,在此基础上增加防止跨区域访问的问题;

首先它会剔除符合这些规则的Zone区域:所属实例数位零的Zone区域;Zone区域内实例等平均负载小于零,或者实例故障率(断路器断开次数/实例数)大于等于阀值(默认为0.99999)。

然后根据Zone区域等实例平均负载计算出最差的Zone区域,这里的最差指的是实例平均负载最高的Zone区域。

如果在上面的过程中没有符合剔除要求的区域,同时实例最大平均负载小于阀值(默认为20%),就直接返回所有Zone区域为可用区域。否则,从最坏Zone区域集合中随机选择一个,将它从可用Zone区域集合中剔除。

 ▪️当获得的可用Zone区域集合不为空,并且个数小于Zone区域总数,就随机选择一个Zone区域。

▪️在确定了某个Zone区域后,则获取了对应Zone区域的服务均衡器,并调用chooseServer来选择具体的服务实例,而在chooseServer中将使用IRule接口的choose函数来选择具体的服务实例。在这里,IRule接口的实现会使用ZoneAvoidanceRule来挑选出具体的服务实例。

服务列表就是客户端负载均衡所使用的(同一注册中心集群)各服务的服务实例列表。Ribbon在实现上支持以下几种服务列表方式

静态服务器列表:通过Ribbon的BaseLoadBalancer所提供的setServerList()方法,初始化时直接进行动态设置指定;

基于配置的服务器列表:需要在项目配置文件中通过<服务名称>.ribbon.listOfServers进行设置。(如user-service.ribbon.listOfServers=http://127.0.0.1:8082,http://127.0.0.1:8083)

基于服务发现的服务器列表:同时使用Ribbon和Eureka时,默认使用该方式,在应用启动时Ribbon就会从Eureka服务器中获取所有注册服务的列表数据,并保持同步。

该组件会对原始服务列表使用一定策略进行过滤返回有效可用的服务器列表给客户端负载均衡器使用。常用服务列表过滤器如下:ZoneAffinityServerListFilter:基于区域感知的方式,实现对服务实例的过滤,仅返回与本身所处区域一直的服务提供者实例列表;ServerListSubsetFilter:该过滤器继承自ZoneAffinityServerListFilter,在进行区域感知过滤后,仅返回一个固定大小的服务列表。默认将返回20个服务实例,可以通过ribbon.ServerListSubsetFilter.size进行设置;

ZonePreferenceServerListFilter:使用Eureka和Ribbon时默认的过滤器。实现通过配置或者Eureka所属区域来过滤出同区域的服务实例列表。

它实现了通过配置或者Eureka实例元数据的所属区域(Zone)来过滤出同区域的服务实例。如下面的源码所示,它的实现非常简单,首先通过父类ZoneAffinityServerListFilter的过滤器来获得“区域感知”的服务实例列表,然后遍历这个结果,取出根据消费者配置预设的区域Zone来进行过滤,如果过滤掉结果是空就直接返回父类获取的结果,如果不为空就返回通过消费者配置的Zone过滤后的结果。

用来检测一个微服务实例是否存活是否有响应,Ribbon通过该组件来判断所持有的服务实例列表中各服务可用情况,如果检测到某服务实例不存在/一定时间未响应,则会从持有服务列表中及时移除。

PingUrl:通过定期访问指定的URL判断;

PingConstant:不做任何处理,只返回一个固定值,用来表示该服务是否可用,默认值为true;

NoOpPing:不做任何处理,直接返回true,表示该服务器可用,默认策略;

DummyPing:直接返回true,但实现了initWithNiwsConfig方法;

NIWSDiscoverPing:根据DiscoveryEnabledServer中InstanceInfo的InstanceStatus属性判断,如果该属性的值为InstanceStatus.UP,则表示服务器可用;

作用就是选择一个最终服务实例地址作为负载均衡处理结果。Ribbon提供的选择策略有随机 (Random)、轮询 (RoundRobin)、一致性哈希 (ConsistentHash)、哈希 (Hash)、加权(Weighted)。

IRule负载均衡策略:通过实现该接口定义自己的负载均衡策略。它的choose方法就是从一堆服务器列表中按规则选出一个服务器。

默认实现:

ZoneAvoidanceRule(区域权衡策略):复合判断Server所在区域的性能和Server的可用性,轮询选择服务器。

其他规则:

BestAvailableRule(最低并发策略):会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务。逐个找服务,如果断路器打开,则忽略。

RoundRobinRule(轮询策略):以简单轮询选择一个服务器。按顺序循环选择一个server。

RandomRule(随机策略):随机选择一个服务器。

AvailabilityFilteringRule(可用过滤策略):会先过滤掉多次访问故障而处于断路器跳闸状态的服务和过滤并发的连接数量超过阀值得服务,然后对剩余的服务列表安装轮询策略进行访问。

WeightedResponseTimeRule(响应时间加权策略):据平均响应时间计算所有的服务的权重,响应时间越快服务权重越大,容易被选中的概率就越高。刚启动时,如果统计信息不中,则使用RoundRobinRule(轮询)策略,等统计的信息足够了会自动的切换到WeightedResponseTimeRule。响应时间长,权重低,被选择的概率低。反之,同样道理。此策略综合了各种因素(网络,磁盘,IO等),这些因素直接影响响应时间。

RetryRule(重试策略):先按照RoundRobinRule(轮询)的策略获取服务,如果获取的服务失败则在指定的时间会进行重试,进行获取可用的服务。如多次获取某个服务失败,就不会再次获取该服务。主要是在一个时间段内,如果选择一个服务不成功,就继续找可用的服务,直到超时。

1. <clientName>:这是调用ribbon的客户端名称,如果此值为没有配置,则此条属性会作用到所有的客户端。

2. <nameSpace>:默认值为 “ribbon”

3. <propertyName>:所有的可用的属性都在com.netflix.client.conf.CommonClientConfigKey。

<clientName>.<nameSpace>.NFLoadBalancerClassName=xx

<clientName>.<nameSpace>.NFLoadBalancerRuleClassName=xx

<clientName>.<nameSpace>.NFLoadBalancerPingClassName=xx

<clientName>.<nameSpace>.NIWSServerListClassName=xx

<clientName>.<nameSpace>.NIWSServerListFilterClassName=xx

com.netflix.client.config.IClientConfig:Ribbon的客户端配置,默认采用com.netflix.client.config.DefaultClientConfigImpl实现。

com.netflix.loadbalancer.IRule:Ribbon的负载均衡策略,默认采用com.netflix.loadbalancer.ZoneAvoidanceRule实现,该策略能够在多区域环境下选出最佳区域的实例进行访问。

com.netflix.loadbalancer.IPing:Ribbon的实例检查策略,默认采用com.netflix.loadbalancer.NoOpPing实现,该检查策略是一个特殊的实现,实际上它并不会检查实例是否可用,而是始终返回true,默认认为所有服务实例都是可用的。

com.netflix.loadbalancer.ServerList:服务实例清单的维护机制,默认采用com.netflix.loadbalancer.ConfigurationBasedServerList实现。

com.netflix.loadbalancer.ServerListFilter:服务实例清单过滤机制,默认采org.springframework.cloud.netflix.ribbon.ZonePreferenceServerListFilter,该策略能够优先过滤出与请求方处于同区域的服务实例。

com.netflix.loadbalancer.ILoadBalancer:负载均衡器,默认采用com.netflix.loadbalancer.ZoneAwareLoadBalancer实现,它具备了区域感知的能力。

上面的配置是在项目中没有引入spring Cloud Eureka,如果引入了Eureka和Ribbon依赖时,自动化配置会有一些不同。

通过自动化配置的实现,可以轻松的实现客户端的负载均衡。同时,针对一些个性化需求,我们可以方便的替换上面的这些默认实现,只需要在springboot应用中创建对应的实现实例就能覆盖这些默认的配置实现。

@Configuration

public class MyRibbonConfiguration {

    @Bean

    public IRule ribbonRule(){

        return new RandomRule()

    }

}

这样就会使用P使用了RandomRule实例替代了默认的com.netflix.loadbalancer.ZoneAvoidanceRule。

也可以使用@RibbonClient注解实现更细粒度的客户端配置

对于Ribbon的参数通常有二种方式:全局配置以及指定客户端配置

全局配置的方式很简单

只需要使用ribbon.<key>=<value>格式进行配置即可。其中,<key>代表了Ribbon客户端配置的参数名,<value>则代表了对应参数的值。比如,我们可以想下面这样配置Ribbon的超时时间

ribbon.ConnectTimeout=250

ribbon.ServerListRefreshInterval=2000   ribbon获取服务定时时间

全局配置可以作为默认值进行设置,当指定客户端配置了相应的key的值时,将覆盖全局配置的内容

指定客户端的配置方式

<client>.ribbon.<key>=<value>的格式进行配置.<client>表示服务名,比如没有服务治理框架的时候(如Eureka),我们需要指定实例清单,可以指定服务名来做详细的配置,

user-service.ribbon.listOfServers=localhost:8080,localhost:8081,localhost:8082

对于Ribbon参数的key以及value类型的定义,可以通过查看com.netflix.client.config.CommonClientConfigKey类。

当在spring Cloud的应用同时引入Spring cloud Ribbon和Spring Cloud Eureka依赖时,会触发Eureka中实现的对Ribbon的自动化配置。这时的serverList的维护机制实现将被com.netflix.niws.loadbalancer.DiscoveryEnabledNIWSServerList的实例所覆盖,该实现会讲服务清单列表交给Eureka的服务治理机制来进行维护。IPing的实现将被com.netflix.niws.loadbalancer.NIWSDiscoveryPing的实例所覆盖,该实例也将实例接口的任务交给了服务治理框架来进行维护。默认情况下,用于获取实例请求的ServerList接口实现将采用Spring Cloud Eureka中封装的org.springframework.cloud.netflix.ribbon.eureka.DomainExtractingServerList,其目的是为了让实例维护策略更加通用,所以将使用物理元数据来进行负载均衡,而不是使用原生的AWS AMI元数据。在与Spring cloud Eureka结合使用的时候,不需要再去指定类似的user-service.ribbon.listOfServers的参数来指定具体的服务实例清单,因为Eureka将会为我们维护所有服务的实例清单,而对于Ribbon的参数配置,我们依然可以采用之前的两种配置方式来实现。

此外,由于spring Cloud Ribbon默认实现了区域亲和策略,所以,可以通过Eureka实例的元数据配置来实现区域化的实例配置方案。比如可以将不同机房的实例配置成不同的区域值,作为跨区域的容器机制实现。而实现也非常简单,只需要服务实例的元数据中增加zone参数来指定自己所在的区域,比如:

eureka.instance.metadataMap.zone=shanghai

在Spring Cloud Ribbon与Spring Cloud Eureka结合的工程中,我们可以通过参数禁用Eureka对Ribbon服务实例的维护实现。这时又需要自己去维护服务实例列表了。

ribbon.eureka.enabled=false.

由于Spring Cloud Eureka实现的服务治理机制强调了cap原理的ap机制(即可用性和可靠性),与zookeeper这类强调cp(一致性,可靠性)服务质量框架最大的区别就是,Eureka为了实现更高的服务可用性,牺牲了一定的一致性,在极端情况下宁愿接受故障实例也不要丢弃"健康"实例。

比如说,当服务注册中心的网络发生故障断开时候,由于所有的服务实例无法维护续约心跳,在强调ap的服务治理中将会把所有服务实例剔除掉,而Eureka则会因为超过85%的实例丢失心跳而触发保护机制,注册中心将会保留此时的所有节点,以实现服务间依然可以进行互相调用的场景,即使其中有部分故障节点,但这样做可以继续保障大多数服务的正常消费。

在Camden版本,整合了spring retry来增强RestTemplate的重试能力,对于我们开发者来说,只需要简单配置,即可完成重试策略。

spring.cloud.loadbalancer.retry.enabled=true

hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=10000

user-service.ribbon.ConnectTimeout=250

user-service.ribbon.ReadTimeout=1000

user-service.ribbon.OkToRetryOnAllOperations=true

user-service.ribbon.MaxAutoRetriesNextServer=2

user-service.ribbon.maxAutoRetries=1

spring.cloud.loadbalancer.retry.enabled:该参数用来开启重试机制,它默认是关闭的。

hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds:断路器的超时时间需要大于Ribbon的超时时间,不然不会触发重试。

user-service.ribbon.ConnectTimeout:请求连接超时时间。

user-service.ribbon.ReadTimeout:请求处理的超时时间

user-service.ribbon.OkToRetryOnAllOperations:对所有操作请求都进行重试。

user-service.ribbon.MaxAutoRetriesNextServer:切换实例的重试次数。

user-service.ribbon.maxAutoRetries:对当前实例的重试次数。

根据以上配置,当访问到故障请求的时候,它会再尝试访问一次当前实例(次数由maxAutoRetries配置),如果不行,就换一个实例进行访问,如果还是不行,再换一个实例访问(更换次数由MaxAutoRetriesNextServer配置),如果依然不行,返回失败

项目启动的时候会自动的为我们加载LoadBalancerAutoConfiguration自动配置类,该自动配置类初始化条件是要求classpath必须要有RestTemplate这个类,必须要有LoadBalancerClient实现类。

LoadBalancerAutoConfiguration为我们干了二件事,第一件是创建了LoadBalancerInterceptor拦截器bean,用于实现对客户端发起请求时进行拦截,以实现客户端负载均衡。创建了一个

RestTemplateCustomizer的bean,用于给RestTemplate增加LoadBalancerInterceptor拦截器。

每次请求的时候都会执行org.springframework.cloud.client.loadbalancer.LoadBalancerInterceptor的intercept方法,而LoadBalancerInterceptor具有LoadBalancerClient(客户端负载客户端)实例的一个引用,

在拦截器中通过方法获取服务名的请求url(比如http://user-service/user),及服务名(比如user-service),然后调用负载均衡客户端的execute方法。

执行负载客户端RibbonLoadBalancerClient(LoadBalancerClient的实现)的execute方法,得到ILoadBalancer(负载均衡器)的实现ZoneAwareLoadBalancer,并且通过调用其chooseServer方法获得服务列表中的一个实例,比如说user-service列表注册到eureka中一个实例。然后向其中的一个具体实例发起请求,得到结果。

Ribbon详解 

https://www.jianshu.com/p/1bd66db5dc46

Spring cloud系列六 Ribbon的功能概述、主要组件和属性文件配置  

https://blog.csdn.net/hry2015/article/details/78357990

Ribbon的ZoneAwareLoadBalancer  

https://blog.csdn.net/chengqiuming/article/details/81209131

Ribbon的实际使用

https://www.jianshu.com/p/f86af82fa782

本人有道云笔记中记录的参考文章

文档:04_ribbon 负载均衡.note

链接:http://note.youdao.com/noteshare?id=74e2434f21c3e96fb106be44fd8ed0b9&sub=2516B0E6DFEE4786B26D9528AF522928

【负载均衡架构部分转自】 58沈剑 [架构师之路]( https://mp.weixin.qq.com/s

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

常见的负载均衡方案:

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

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

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

上游连接池会建立与下游服务多个连接,每次请求会“随机”选取连接来访问下游服务。(也即是rpc框架实现的)

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

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

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

(1)按照range水平切分

(2)按照id哈希水平切分

[图片上传中...(-6b2508-1561902875888-0)]

常见的负载均衡系统包括 3 种:DNS 负载均衡、硬件负载均衡和软件负载均衡。

硬件负载均衡是通过单独的硬件设备来实现负载均衡功能,这类设备和路由器、交换机类似,可以理解为一个用于负载均衡的基础网络设备。比如业界非常出名的F5

缺点:

(1)价格实在非常昂贵

(2)扩展性不强

软件负载均衡通过负载均衡软件来实现负载均衡功能,常见的有 Nginx 和 LVS。

nginx和F5: https://blog.csdn.net/chabale/article/details/8956717

nginx和lvs比较: https://blog.51cto.com/hzcto/2086691

lvs: https://www.cnblogs.com/liwei0526vip/p/6370103.html

ELB: https://aws.amazon.com/cn/elasticloadbalancing/

SLB: https://help.aliyun.com/product/27537.html

题目:日活跃用户 1000 万的论坛的负载均衡集群,该如何设计呢?

(1)评估流量

1000万DAU,换算成秒级(一天12小时),平均约等于232。

考虑每个用户操作次数,假定10,换算成平均QPS=2320。

考虑峰值是均值倍数,假定5,换算成峰值QPS=11600。

考虑静态资源、图片资源、服务拆分等,流量放大效应,假定10,QPS 10=116000。

(2)容量规划

考虑高可用、异地多活,QPS 2=232000。

考虑未来半年增长,QPS*1.5=348000。

(3)方案设计

可以用三级导流:

第一级,DNS,确定机房,以目前量级,可以不考虑。

第二级,确定集群,扩展优先,则选Haproxy/LVS,稳定优先则选F5。

第三级,Nginx+KeepAlived,确定实例。

(4)架构图

接入层技术:

缺点:

优点:

缺点:

优点:

缺点:

缺点:

nginx毕竟是软件,性能比tomcat好,但总有个上限,超出了上限,还是扛不住。lvs就不一样了,它实施在操作系统层面;f5的性能又更好了,它实施在硬件层面;它们性能比nginx好很多,例如每秒可以抗10w,这样可以利用他们来扩容。

99.9999%的公司到这一步基本就能解决接入层高可用、扩展性、负载均衡的问题。 假设还扛不住的话,就要考虑使用硬件设备f5等。如果还是扛不住,那么只有DNS来扩容了。

水平扩展,才是解决性能问题的根本方案,能够通过加机器扩充性能的方案才具备最好的扩展性。 facebook,google,baidu的PV是不是超过80亿呢,它们的域名只对应一个ip么,终点又是起点,还是得通过DNS轮询来进行扩容:

比如购买了阿里云或者aws。那么基本会使用云厂商提供的负载均衡中间件,比如aws(elb)、阿里云(slb)。这个负载均衡软件可以认为是 lvs+keepalived的高可用负载均衡服务

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

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

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

(1)通过“静态权重”标识service的处理能力

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

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

(2)通过“动态权重”标识service的处理能力

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

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

动态权重设计:

例如:

(1)设置一个阈值,超过阈值直接丢弃

(2)借助“动态权重”来实施过载保护

案例策略:

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

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

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

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

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


欢迎分享,转载请注明来源:夏雨云

原文地址:https://www.xiayuyun.com/zonghe/358.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-01-28
下一篇2023-01-28

发表评论

登录后才能评论

评论列表(0条)

    保存