Ribbon工作原理

之前我们在使用RestTemplate进行服务交互的时候,在其注入的bean上添加了@LoadBalanced注解,这样它就默认是使用Ribbon进行负载均衡处理。

 

但是RestTemplate是Spring提供的,Bean跟Ribbon客户端负载均衡又有什么关系呢?

下面我们就来深入地研究Ribbon是如何结合RestTemplate实现客户端服务调用的负载均衡的。

既然RestTemplate是使用了@LoadBalanced注解才让其实现Ribbon的负载均衡的,那么我们就从这个注解开始着手研究。

按住“Ctrl”键并单击@LoadBalanced注解查看源码,我们发现这个注解里面没有什么特殊的内容,但是从源码的注释可以知道该注解是标记在RestTemplateWebClient Bean上的,从而配置为LoadBalancerClient。

 

 

 接着观察LoadBalancerClient的源码,可以发现它是一个定义了负载均衡方法的接口,如程序清单12-2所示。

除了上面源码中定义负载均衡的几种方法外,LoadBalancerClient还继承了ServiceInstance- Chooser接口中的chooser方法,如程序清单12-3所示。

 

 通过查看这几个功能方法的注释可以得知,choose方法是通过serviceId(服务ID)从负载均衡器中挑选出对应的服务实例的;

execute方法是使用从负载均衡器中挑选出来的服务来处理请求的;

reconstructURI方法表示为服务实例创建一个host:port的URI实例。

 

 从上图中可以看到,RibbonLoadBalancerClient是LoadBalancerClient的实现类,单击查看它的源码可知它是执行客户端负载均衡处理功能的子类。

 

RibbonLoadBalancerClient重写的choose功能方法中,内部通过getServer方法根据serviceId获取到服务,而从getServer方法中可以发现其是通过ILoadBalancer接口来实现的,如程序清单12-4所示。

 

 

ILoadBalancer是一个接口,所以它只定义了实现负载均衡的方法,如程序清单12-5所示。

 

 

 ILoadBalancer接口的实现类是AbstractLoadBalancer,但是它是一个抽象类,所以服务的获取、选择以及添加等操作主要在其子类BaseLoadBalancer和DynamicServerListLoadBalancer中实现。

 

ILoadBalancer接口的实现类是AbstractLoadBalancer,但是它是一个抽象类,所以服务的获取、选择以及添加等操作主要在其子类BaseLoadBalancer和DynamicServerListLoadBalancer中实现。这两个子类中还定义了负载均衡的客户端配置IClientConfig、获取服务的负载均衡策略IRule、通过IPing接口进行ping测试来判断服务是否可用以及从Eureka服务列表中获取服务列表Server集合对象等,这里就不再列出其源码。

 

通过上面的描述,我们知道负载均衡进行服务的添加、服务的获取、服务的选择等操作主要是通过LoadBalancerClient的子类RibbonLoadBalancerClient实现的,那么为什么我们在RestTemplate注入的Bean上添加@LoadBalanced注解就可以加载RibbonLoadBalancerClient进行负载均衡呢?这是因为Ribbon有一个自动配置类RibbonAutoConfiguration,而RibbonAutoConfiguration加载前会加载LoadBalancerAutoConfiguration配置类,在LoadBalancer- AutoConfiguration中有一个被@LoadBalanced修饰的RestTemplate集合,在进行初始化的时候使用RestTemplateCustomizer给每一个RestTemplate都添加了LoadBalancerInterceptor拦截器。

 

LoadBalancerAutoConfiguration部分源码如程序清单12-6所示。

 

LoadBalancerInterceptor 拦截器(其源码如程序清单12-7所示)负责拦截请求,并把请求交给LoadBalancerClient负载均衡类处理,因此RestTemplate就实现了负载均衡的功能。

posted @ 2022-12-14 14:30  cnetsa  阅读(118)  评论(0编辑  收藏  举报