连载:2-spring-cloud-ribbon

负载均衡Ribbon
【GitHub地址:https://github.com/NullPointer8023/eureka】
前言:笔记承接上篇,上篇主要针对Eureka的Server和Client,如何实现了服务的注册和发现。同时简述了Eureka的实现机制,如何实现Eureka的高可用进行了整合。接下来就要实现如何结合Spring Cloud中Ribbon负载均衡组件实现服务的消费的负载均衡的。
一、什么是RestTemplate
RestTemplate和Ribbon结合作为服务消费者去消费服务,RestTemplate是Spring Resources中一个访问第三方RESTful API接口的网络请求框架。RestTemplate的设计原则和其他Spring Template(JDBC Template等)类似,都是为执行复杂任务提供了一个具有默认行为的简单方法。
RestTemplate支持常见的Http协议的请求方法,所以用它来构建RESTful API。RestTemplate是用来消费REST服务的,所以主要方法都是与REST的HTTP协议的一些方法相连,例如HEAD、GET、POST、PUT、DELETE、OPTIONS等方法,这些方法在RestTemplate类对应的方法为headForHeaders()、getForObject()、postForObject()、put()、delete()等。

二、什么是Ribbon
负载均衡是指将负载均摊到多个执行单元上,常见的负载均衡有两种。
1、独立进程单元,通过负载均衡策略,将请求转发到不同的执行单元上,例如Nginx。
2、将负载均衡逻辑以代码的形式封装到服务消费者的客户端上,服务消费者客户端维护了一份服务提供者的信息,有了信息列表,通过负载均衡策略将请求分摊给多个服务提供者,从而达到负载均衡的目的。

Ribbon是Netflix公司开源的一个负载均衡组件,它属于第二种方式。
在Spring cloud构建的微服务系统中,Ribbon作为服务消费者的负载均衡器,有两种使用方式,一种是和RestTemplate相结合,另一种是和Feign相结合。Feign已经默认继承了Ribbon。

三、如何将Ribbon和RestTemplate结合实现负载均衡
继续沿用上篇笔记中的项目,
Eureka Server:三个实例,端口:peer1:8761、peer2:8762、peer3:8763
Eureka Client:两个实例,端口:eureka-client:8764、eureka-client:8765,注意:两个服务的yml中的服务名相同
新建一个module,名为eureka-ribbon-client,也作为一个服务注册到Eureka Server中,
项目结构:
在这里插入图片描述
配置如下:
1、pom.xml
添加对ribbon的引用
在这里插入图片描述
2、application.yml
在这里插入图片描述

3、Application入口类添加@EnableEurekaClient开启Eureka Client功能
在这里插入图片描述

4、写一个Restful API接口,内部去调用client中的api接口“/hi”,这个过程叫做服务消费。
eureka-client的两个实例,端口为eureka-client:8764、eureka-client:8765。在调用client的接口时,希望轮流访问这两个client的实例,这时需要讲RestTemplate和Ribbon相结合来进行负载均衡。
这时,需要再程序的IoC容器中注入一个restTemplate的bean,并在这个bean上加上@LoadBalanced注解,此时,RestTemplate就结合了Ribbon开启了负载均衡功能。
在这里插入图片描述

5、编写service类,调用client中的“/hi”接口,此处通过client的服务名即可访问
在这里插入图片描述

6、编写controller,通过get方法调用service的方法
在这里插入图片描述


代码准备完毕,启动3个Eureka服务注册和发现集群,启动2个eureka-client实例,启动ribbon,一共6个服务
示例是在本机一个springboot下启动多个module实现,所以选择使用相同的服务名,不同的端口来实现启动多个示例,达到集群的效果。
真正项目实战过程中,需要将服务部署在不同的docker中,服务名相同,端口相同,来实现集群。
Eureka-Server-peer1:
在这里插入图片描述

Eureka-Server-peer2:
在这里插入图片描述

Eureka-Server-peer3:
在这里插入图片描述

Eureka-Client-ribbon:通过ribbon“localhost:8766” 访问client服务,多次访问可以发现负载均衡器起了作用,通过相同的地址访问client提供的API接口,负载均衡器会轮流地请求eureka-client两个实例中
在这里插入图片描述
在这里插入图片描述

此时,完成了restTemplate结合Ribbon实现负载均衡的目的。
gitHub提供了Ribbon脱离RestTemplate使用负载均衡的方式,通过LoadBalancerClient的choose方法也可实现。
【GitHub地址:https://github.com/NullPointer8023/eureka】

四、源码分析
1、首先跟踪【private LoadBalancerClient loadBalancerClient;】了解LoadBalancerClient
LoadBanlancerClient是一个接口类,它继承了ServiceInstanceChooser,LoadBanlancerClient的实现类为RibbonloadBalanceClient。

  • LoadBalancerClient是一个负载均衡的客户端,三种方法,2个execute()用来执行请求,reconstructURI()用于重构Url。
  • ServiceInstanceChooser接口choose()方法,根据serviceId获取ServiceInstance,通过服务名来获取服务实例。
  • RibbonloadBalanceClient是一个非常重要的类,最终的负载均衡的请求处理由它来执行。
    • choose()方法用于选择具体服务实例,getServer()方法用于获取实例,最终交给ILoadBalancer类去选择服务实例。
    • ILoadBalancer接口,子类BaseLoadBalancer。BaseLoadBalancer的实现类为DynamicServerListLoadBalancer。
    • DynamicServerListLoadBalancer类需要配置IClientConfig、IRule、IPing、ServerList、ServerListFilter、ILoadBalancer。
      • IClientConfig 用于配置负载均衡的客户端
      • IRule是用于配置负载均衡的策略,有很多默认的实现类,根据不同算法和逻辑来处理负载均衡的策略。
        在这里插入图片描述
      • IPing用于向Server发送“ping”,来判断该server是否有响应,从而判断该server是否可用。

DynamicServerListLoadBalancer构造函数有一个initWithNiwsConfig()方法,经过一系列初始化,最终调用restOfInit()方法,内部有一个方法updateListOfServers()获取所有ServerList。ServerList是一个接口,其中有一个实现类DiscoveryEnabledNIWSServerList,继续追踪类的方法getInitialListOfServers()会发现eurekaClientProvider.get()来获取EurekaClient。

由此可见,Ribbon的负载均衡是由Eureka Client获取注册的服务列表信息,并根据IRule负载均衡策略去路由,根据IPing判断服务可用性。

2、负载均衡器每隔多久向Eureka获取服务列表信息?
BaseLoadBalancer的构造方法中有一个开启了PingTask任务。setupPingTask有一个变量pingIntervalSeconds【protected int pingIntervalSeconds = 10;】每十秒向Eureka Client发送一次心跳“ping”。
查看PingTask源码new Pinger对象,调用了runPinger()方法。进一步进入源码发现【pingerStrategy.pingServers(ping, allServers);】获取服务的可用性,如果该返回结果与之前相同,则不向EurekaClient获取注册列表,如果不同,则通知ServerStatusChangeListener服务注册列表信息发生改变重新拉取。
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

由此可见,LoadBalancerClient是在初始化时向Eureka获取服务注册列表信息,并且每10秒向EurekaClient发送“ping”,来判断服务的可用性。如果服务的可用性发生了改变或者服务数量以前不一致,则更新或者重新拉取。LoadBalancerClient有了新的服务注册列表,根据IRule的策略来进行负载均衡。

3、为什么restTemplate类上加了一个@LoadBalance注解就可以使用Ribbon的负载均衡呢?
在LoadBalancerAutoConfiguration类中,首先维护了一个被@LoadBalanced修饰的RestTemplate对象的list。在初始化的过程中,通过调用customizer.customize(restTemplate);方法来给RestTemplate增加拦截器LoadBalancerInterceptor。拦截器用于实时拦截,在LoadBalancerInterceptor中实现了负载均衡的方法。

总结:Ribbon的负载均衡主要是通过LoadBalancerClient来实现的,而LoadBalancerClient具体交给了ILoadBalancer来处理,ILoadBalancer通过配置IRule、IPing等向EurekaClient获取注册列表信息,默认每10秒发送一次“ping”,进而进行检查服务可用性,是否需要更新服务列表信息。最后在得到服务注册列表后,根据IRule的策略进行负载均衡。

而RestTemplate加上@LoadBalancer注解后,远程调度时能够负载均衡,主要是维护了一个被@LoadBalancer注解的RestTemplate列表,并给该列表中的RestTemplate对象添加了拦截器。在拦截器方法中,将远程调度方法交给了ribbon的负载均衡器LoadBalancerClient去处理,从而达到负载均衡的目的。

猜你喜欢

转载自blog.csdn.net/zzzbbbjjj/article/details/84104612
今日推荐