Ribbon粗浅理解

一、Ribbon简介

​ Ribbon是Netflix发布的负载均衡器,有助于控制Http和Tcp的客户端行为。配置Ribbon服务提供者地址后,Ribbon就可以基于某种负载均衡算法,自动地去帮助服务者请求。Ribbon默认提供了几种负载均衡算法。例如轮询、随机等,我们也可以自己定义自己的负载均衡算法。

​ 在SpringCloud中,当Ribbon与Eureka配合使用时,Ribbon可自动从Eureka Server获取服务提供者地址列表,并基于负载均衡算法,请求其中一个服务提供者实例,展示了Ribbon与Eureka配合使用时的架构。

在这里插入图片描述

二、Ribbon的使用

首先需要去搭建一个本地的 Eureka 注册中心具体流程省略:
在这里插入图片描述

其次就是去搭建两个Eureka Client,流程省略:
在这里插入图片描述

让它们注册到本地注册中心当中。

在这里插入图片描述

然后开始负载均衡的配置,因为Eureka Client包当中已经引入Ribbon的相关依赖了,所以不需要新加入Ribbon依赖

在这里插入图片描述

在我们服务调用方也就TRADE-ADMIN中,在Application.class中去添加注解@LoadBlanced,不加就是不使用负载均衡,那么它调用服务后,就可能默认优先在第一个端口,偶尔会切换第二个端口。

在这里插入图片描述

然后用@feign就可以调用我们的服务了,由于这里Ribbon没有配置,Ribbon就会根据它的默认负载均衡算法从我们的服务列表中找到合适的端口去调用服务了

测试结果如下:

TRADE-ADMIN 服务利用feign去远程调用 TRADE-CLIENT 服务,以端口号作为标记,发出请求:

在这里插入图片描述

TRADE-ADMIN 请求第一次的返回:

在这里插入图片描述

TRADE-ADMIN 请求第二次的返回:

在这里插入图片描述

三、Ribbon的负债均衡的策略

什么是负载?

​ 负载是linux机器的一个重要指标,直观的反应了机器的状态。

​ 在UNIX系统当中,系统负载是对当前CPU工作量的度量,被定义为特定时间间隔内运行的队列中的平均线程数。Load average表示机器一段时间内的平均Load,这个值越低越好,负载过高会导致机器无法处理其他请求及,甚至导致死机。

什么是负载均衡?

​ 负载均衡是由多台服务器以对称的方式组成一个服务器集合,每台服务器都具有等价的地位,都可以单独对外供应效力而无须其他服务器的辅助。经过某种负载分管技术,将外部发送来的央求均匀分配到对称结构中的某一台服务器上,而接收到央求的服务器独登时回应客户的央求。均衡负载可以平均分配客户央求到服务器列阵,籍此供应快速获取重要数据,解决很多并发访问效力问题。这种群集技术可以用最少的出资取得接近于大型主机的性能。

负载均衡的策略?

1.轮询

每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器down掉,能自动剔除。

2.指定权重

指定轮询几率,weight和访问比率成正比,用于后端服务器性能不均的情况。

3.IP绑定 (ip hash)

每个请求按访问ip的hash结果分配,这样每个访客固定访问一个后端服务器,可以解决session的问题。

4.fair(第三方)

按后端服务器的响应时间来分配请求,响应时间短的优先分配。

5.url_hash(第三方)

按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器,后端服务器为缓存时比较有效。

Ribbon负载均衡策略

​ 1.RandomRule 随机策略 :随机选择server

原理:通过Random类,随机从可用服务器列表取一个

优势:适用于集群中各个节点提供服务能力等同且无状态的场景。

缺点:不关心服务端负载,服务端处理能力的波动可能造成堵塞

测试使用改策略效果图:

​ 测试准备了注册了三个同名服务,以端口号不同作为标识依据。

​ 配置文件修改 RandomRule策略模式
在这里插入图片描述

​ 第一次调用:

在这里插入图片描述

​ 第二次调用:

在这里插入图片描述

​ 第三次调用:

在这里插入图片描述

​ 从测试结果可以看出,7002端口的服务被读取了两次,而且分配的三个端口当前只被读取了7001,7002,7003端口没有被读到,随机策略模式是随机去读取一个可用服务,可能读取过程中会读取到重复的端口,可能会有一个端口读不到。

​ 2.RoundRobinRule 轮询策略: 从服务端列表里面循环获取

原理:维护一个AtomicInteger变量,和服务器总数求余得到index,取 服务器列表第index的值

优势:适用于集群中各个节点提供服务能力等同且无状态的场景。

缺点:不关心服务端负载,服务端处理能力的波动可能造成堵塞。

测试使用改策略效果图:

​ 测试准备了注册了三个同名提供方服务,以端口号不同作为标识依据。

​ 配置文件修改 RoundRobinRule 策略模式

在这里插入图片描述

第一次调用:

在这里插入图片描述

第二次调用:

在这里插入图片描述

第三次调用:
在这里插入图片描述

3.WeightedResponseTimeRule 响应时间加权重策略**:根据每个服务的响应时间设置权重,响应时间越长,所占权重越少。

​ **原理:**维护一个volatile List类型的权重列表,里面保存了根据当前服务响应时间计算出的权重值,该列表默认每30秒刷新一次。采用轮询来获取服务。

​ **优势:**允许各节点服务能力不相等并且允许波动。

测试使用改策略效果图:

​ 在 服务二 和 服务三 中设置Thread.sleep模拟接口响应时间,

TRADE-CLIENT2

在这里插入图片描述

TRADE-CLENT3

在这里插入图片描述

TRADE-CLENT1不设置线程延时,可以查出每个端口的权重,按逆序排列,可见会多次读取7001端口,但是其实,随着时间权重的叠加,读取的概率也会叠加,效果不是很明显。

​ 4.RetryRule 重试策略: 鉴于IRule可以级联,此RetryRule类允许向现有规则添加重试逻辑。(和负载均衡无关)

​ **原理:**在指定时间(默认500ms)内不断的调用指定路由策略(默认值:RoundRobinRule)获取服务,直到获取成功。

​ **优势:**具体适用场景同指定的路由策略,只是添加了重试功能

测试使用改策略效果图:

​ 测试准备了注册了三个同名提供方服务,以端口号不同作为标识依据。

​ 配置文件修改 RetryRule 策略模式

在这里插入图片描述

测试结果:

在这里插入图片描述

在这里插入图片描述

可以看到这个请求会被重试5秒之后,再返回一个错误页面。然后依据轮询的方式依次访问下一个端口。

5.BestAvailableRule 最低并发策略: 跳过具有“跳闸”断路器的服务器的规则,并选择具有最低并发请求的服务器。

​ **优势:**此规则通常应与ServerListSubsetFilter一起使用,后者对规则可见的服务器设置限制。 这确保了它只需要在少量服务器中找到最小的并发请求。 此外,每个客户端将获得一个随机的服务器列表,避免了大量客户端选择一个具有最低并发请求的服务器并立即被淹没的问题。
没条件测试家里穷,核心CORE:
在这里插入图片描述

6.AvailabilityFilteringRule 可用过滤策略:过滤掉那些因为一直连接失败的被标记为circuit tripped的后端server,并过滤掉那些高并发的的后端server(active connections 超过配置的阈值)

​ **原理:**使用一个AvailabilityPredicate来包含过滤server的逻辑,其实就就是检查status里记录的各个server的运行状态 。

没条件测试家里穷,核心过程:

在这里插入图片描述

7.ZoneAvoidanceRule 区域权重策略: 使用CompositePredicate根据区域和可用性过滤服务器的规则

​ **原理:**通过Predicate链进行判断,最后在所用通过判断的服务器列表中采用轮询策略选择服务器

​ **优势:**服务器分布范围很广,调用方分布范围也很广,可使调用方请求路由到最近的服务器集群

没条件测试家里穷:

在这里插入图片描述

8.自定义:一致性hash策略:对关键值进行hash运算,每次计算的结果一致,再加上其他的条件,使某种请求路由到同一个服务上。

​ **优势:**服务存在大量本地缓存。例如根据token进行hash一致性运算,同一个token每次路由到同一个服务,这个服务可以做一些关于用户权限相关的本地缓存。

​ 实际上,在负载均衡策略的选择上,为了保证我们的服务的稳定性和平衡性等问题,我们会使用随机策略使得每个用户每次访问都会均摊到不同的生产者服务上,使得单个服务器的压力减小,但对于缓存服务器来说,随机取样是一种方式,但是随机取样影响查找的性能。随机获取一台服务器然后将Object存入,应用程序中通过id从缓存服务器查找Object,这种方式是无法第一时间确定其所在的服务器的,需要遍历集群中的所有服务器,然后比对查找出来的对象的id,才能获得查找的Object。数据结构中的哈希表可以解决查找的问题。S集合使用线性列表方式存储,这样每台服务器相对应的都有个编号,对于上面的4台服务器来说,A的编号为0,其余的服务器编号依此类推。这样的话确定了编号,就可以确定选择的服务器。这个线性列表就是一张哈希表,通过公式hash(id)%N(N代表服务器个数)来确定我们的Object注册到哪个服务器,以保证我们每次都可以访问到之前缓存服务器上,但是这个时候问题就来了,通过公式我们可以看出,当我们的服务器数量增加或者减少的话,我们的N就会发生变动,那么我们的计算出来的hash值就会发生变化,导致我们找不到原来的服务器,那么这样他就会重新去请求数据库,假设有大量的请求进来,我们数据库可能承受不住压力而导致崩溃,造成缓存雪崩现象。

​ 为此我们引入了一致性hash的策略,为了解决我们的hash函数计算出来的值受到服务器数量的影响,我们对hash函数进行了改进->hash(id),通过这个哈希函数计算出来的值,通常都是4个字节,也就是32位。所以取值范围就是0~2^32-1,所有的哈希值都会在这个区间内,将这个区间抽象成一个环

在这里插入图片描述

那么我们先将这4个对象映射到我们的换上面

h1 = hash(id);
h2 = hash(id);
h3 = hash(id);
h4 = hash(id);

然后对服务器也进行标识:

c1 = hash(cache1);
c2 = hash(cache2);
c3 = hash(cache3);

在这里插入图片描述

那么如何去确定h 和 c 之间的对应关系呢?我们可以想象一个人沿着环去寻找下一个地点,如果C节点的服务器挂掉,那么对象就会沿着环去寻找下一个节点。这里采用顺时针的方式去寻找

在这里插入图片描述

我们可以看到h1对象被分配到c1节点,h4节点被分配到了c2节点,h2,h3被分配到了c3节点,那么当c2节点崩溃的时候,那么h4就会被分配到c3节点。

在这里插入图片描述

可以看到,c2服务下线,h4服务器就会去重新查询数据库,然后缓存在下一个服务器上面,如图就会寻找下一个节点c3,只会影响c3 服务器 ,并不会对其他服务器造成影响,这和普通的hash算法的表现是不同的,普通hash算法会影响其他缓存服务器上的数据。

那么我们来看增加缓存服务器看看:

增加Cache4,c4节点落在h2和h3之间,此时根据id2进行查找,定位到h2节点,从h2出发寻找对应的c节点,未增加之前找到的是c3节点,增加之后找到的是c4节点,c4节点代表的缓存服务器Cache4并没有Object2数据,那么应用程序从数据库或其他地方获取Object2数据然后重新放入到Cache2中,Cache3中的Object2此时就是无效的。可以看出增加Cache4服务器,只会影响到Cache2和Cache4之间的h节点代表的数据。

增加Cache4服务器后,最终的查找效果如下:

在这里插入图片描述

虚拟节点:

假设当前只有两台缓存服务器,那么我们现在总共有4个对象,那么假设如图分布

在这里插入图片描述

按照逻辑,我们h4,h2,h1都会集中分配在c2服务器上面,只有h3被分配到c1服务器上面,那么这样就会导致我们的服务器分配不均衡。

在这里插入图片描述

如图可见我们c2服务器就会承受很大滴压力,如何解决这种问题呢?

可以采用虚拟节点的方式,给每个c服务器再分配多个虚拟节点,虚拟节点也是随机分配在此区间环上面,那么每个c服务器的虚拟节点都是其本身的克隆节点,但是也是散列分布在这个哈希环当中,目的就是为了将部分节点的压力均分。

在这里插入图片描述

如图可见

h2被分配到c2.1节点,h4被分配到c1.2节点,h1被分配到c2.2节点,h3被分配到c1.1节点,节点的分配变得均衡。当然这不是绝对的,一致性hash只能解决部分不重连数据库的问题。

猜你喜欢

转载自blog.csdn.net/qq_38345235/article/details/115376431