SpringCloud之RPC组件Ribbon

简介

Spring Cloud Ribbon是基于Netflix Ribbon实现的,HTTP和TCP的客户端负载均衡工具。

Spring Cloud Ribbon虽然只是一个工具类框架,但它可以让我们轻松地将面向服务的REST模版请求自动转换成客户端负载均衡的服务调用。它不像服务注册中心、配置中心、API网关那样需要独立部署,但是它几乎存在于每一个Spring Cloud构建的微服务和基础设施中。因为微服务间的调用,API网关的请求转发等内容,实际上都是通过Ribbon来实现的,包括后续我们将要介绍的Feign,它也是基于Ribbon实现的工具。所以,对Spring Cloud Ribbon的理解和使用,对于我们使用Spring Cloud来构建微服务非常重要。

介绍RestTeampale 简单的API

 在Spring Cloud中使用Ribbon的负载均衡,只需如下步骤:

  •   服务提供者只需要启动多个服务实例并注册到一个注册中心或是多个相关联的服务注册中心;
  •   服务消费者直接通过调用被@LoadBalanced注解修饰过的RestTemplate来实现面向服务的接口调用;

GET请求:

  • getForEntity

该方法返回的是ResponseEntity,该对象是Spring对HTTP请求响应的封装,其中主要存储了HTTP的几个重要元素:

  1. HTTP请求状态码的枚举对象HttpStatus;
  2. HTTP请求的头信息对象HttpHeaders ;
  3. 泛型类型的请求体对象;

例子如下,访问user-server服务端/user请求,在url中使用占位符{1},第二个参数指定返回值类型,第三个参数指定传参值:

RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> responseEntity = restTemplate .getForEntity("http://user-server/user?name={1}",String.class,"苦行僧");
String body = responseEntity .getBody();

//如果期望返回body是一个user对象,示例如下:
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<User> responseEntity = restTemplate .getForEntity("http://user-server/user?name={1}",User.class,"苦行僧");
User body = responseEntity .getBody();
  • getForObject

该方法可以理解为对getForEntity的进一步封装,它通过HttpMessageConverterExtractor对HTTP的请求响应体body内容进行对象转换,实现请求直接返回包装好的对象内容。示例 如下:

RestTemplate restTemplate = new RestTemplate();

User user = restTemplate.getForObject(uri, User.class);

POST请求:

  • postForEntity

  • postForObject

  • postForLocation

Ribbon源码分析

RestTemplate,被@LoadBalanced注解修饰后,它的管理就由LoadBalancerClient配置。

LoadBalancerClientorg.springframework.cloud.client.loadbalancer.LoadBalancerClient

ServiceInstanceChooser:org.springframework.cloud.client.loadbalancer.ServiceInstanceChooser

接口方法含义解释如下:

  • ServiceInstance choose(String serviceId):父接口ServiceInstanceChooser的方法,根据传入的服务名serviceId,从负载均衡器中挑选一个对应服务的实例;
  • T execute(String serviceId, ServiceInstance serviceInstance, LoadBalancerRequest request):使用从负载均衡器中挑选出的服务实例来执行请求内容;
  • URI reconstructURI(ServiceInstance instance, URI original):为系统构建一个合适的host:port形式的URI。在分布式系统中,我们使用逻辑上的服务名称作为host来构建URI(替代服务实例的host:port形式)进行请求,比如http://myservice/path/to/service。在该操作的定义中,前者ServiceInstance对象是带有host和port的具体服务实例,而后者URI对象则是使用逻辑服务名定义为host的URI,而返回的URI内容则是通过ServiceInstance的服务实例详情拼接host:port形式的请求地址;

接口关系结构图:

LoadBalancerAutoConfigurationorg.springframework.cloud.client.loadbalancer.LoadBalancerAutoConfiguration

从LoadBalancerAutoConfiguration类上的注解可知,Ribbon实现负载均衡自动化配置需要满足下面两个条件:

  • @ConditionalOnClass(RestTemplate.class):RestTemplate必须存在于当前工程的环境中;
  • @ConditionalOnBean(LoadBalancerClient.class):在Spring的Bean工程中必须有LoadBalancerClient的实现bean;

LoadBalancerAutoConfiguration类主要参与了如下活动:

  1. 创建了一个LoadBalancerInterceptor的Bean,用于实现对客户端发起请求时进行拦截,以实现客户端负载均衡
  2. 创建了一个RestTemplateCustomizer的Bean,用于给RestTemplate增加LoadbalancerInterceptor
  3. 维护了一个被@LoadBalanced注解修饰的RestTemplate对象列表,并在这里进行初始化,通过调用RestTemplateCustomizer的实例来给需要客户端负载均衡的RestTemplate增加LoadBalancerInterceptor拦截器

LoadBalancerInterceptororg.springframework.cloud.client.loadbalancer.LoadBalancerInterceptor

RibbonLoadBalancerClientorg.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient

在execute函数的实现中,第一步做的就是通过getServer根据传入的服务名serviceId去获得具体的服务实例:

通过getServer函数的实现源码,我们可以看到这里获取具体服务实例的时候并没有使用LoadBalancerClient接口中的choose函数,而是使用了ribbon自身的ILoadBalancer接口中定义的chooseServer函数。

在该接口中定义了一个客户端负载均衡器需要的一系列抽象动作:

  • addServers:向负载均衡器中维护的实例列表增加服务实例;
  • chooseServer:通过某种策略,从负载均衡器中挑选出一个具体实例;
  • markServerDwon:用来通知和标识负载均衡器中某个实例已经停止服务,不然负载均衡器在下一次获取服务实例清单前都会认为服务实例均是正常服务的;
  • getReachableServers:获取当前正常服务的实例列表;
  • getAllServers:获取所有已知的服务实例列表,包括正常服务和停止服务的实例;

在该接口定义中涉及到的server对象定义的是一个传统的服务端节点,在该类中存储了服务端节点的一些元数据信息,包括:host,port以及一些部署信息等。 

Ribbon负载均衡器

AbstractLoadBalancercom.netflix.loadbalancer.AbstractLoadBalancer

AbstractLoadBalancer是ILoadBalancer接口的抽象实现。

微服务实例分组枚举类ServerGroup:

         ALL:所有服务实例

        STATUS_UP:正常服务的实例

        STATUS_NOT_UP:停止服务的实例

功能方法有:

        chooseServer():实现负载均衡策略,选择具体实例;

         getServerList(ServerGroup serverGroup):定义了根据分组类型来获取不同的服务实例列表;

         getLoadBalancerStats():定义了获取LoadBalancerStats对象的方法,loadBalancerStats对象被用来存储负载均衡器中各个服务实例当前的属性和统计信息,这些信息非常有用,我们可以利用这些信息来观察负载均衡的运行情况,同时这些信息也是用来制定负载均衡策略的重要依据。

BaseLoadBalancercom.netflix.loadbalancer.BaseLoadBalancer

BaseLoadBalancer类是Ribbon负载均衡器的基础实现类,在该类中定义很多关于均衡负载相关的基础内容:

  1.  定义并维护了两个存储服务实例server对象的列表。一个用于存储所有服务实例的清单,一个用于存储正常服务的实例清单。
  2. 定义了之前我们提到的用来存储负载均衡器各服务实例属性和统计信息的LoadBalancerStats对象。
  3.  定义了检查服务实例是否正常服务的ping对象,在BaseLoadBalancer中默认为null,需要在构造时注入它的具体实现。
  4. 定义了检查服务实例操作的执行策略对象IPingStrategy,在BaseLoadBalancer中默认使用了该类中定义的静态内部类SerialPingStrategy实现。根据源码,我们可以看到该策略采用线性遍历ping服务实例等方式实现检查。该策略在当IPing当实现速度不理想,或是Server列表过大时,可能会影响系统性能,这时候需要通过实现IPingStrategy接口并重写pingServers(IPing ping, Server[] servers)函数去扩展ping的执行策略。

 启动ping任务:在BaseLoadBalancer的默认构造函数中,会直接启动一个用于定时检查server是否健康的任务。该任务默认的执行间隔为:10秒

DynamicServerListLoadBalancercom.netflix.loadbalancer.DynamicServerListLoadBalancer

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值