什么是Spring Cloud Ribbon
Spring cloud ribbon 是一个基于 HTTP 和 TCP 的客户端负载均衡工具,它基于Netflix Ribbon 实现。通过Spring Cloud 的封装,可以轻松的将面向服务的REST模块请求自动转换为客户端负载均衡的服务调用。
Spring Cloud Ribbon 存在于每一个Spring Cloud 构建的微服务和基础设施中。微服务间的调用,API网关的请求转发等内容,实际上都是通过 Ribbon 来实现的,包括后续要介绍的 Feign,它也是基于Ribbon实现的工具。
一、客户端负载均衡
负载均衡在系统架构中是一个非常重要,并且不得不去实施的内容。因为负载均衡是对系统的高可用、网络压力的缓解和处理能力扩容的重要手段之一。
通常说的负载均衡都指的是服务端负载均衡,其中分为硬件负载均衡和软件负载均衡。
硬件负载均衡主要是通过在服务器节点之间安装专门用于负载均衡的设备,比如F5等;(小梵阿里云slb是硬件负载均衡)
软件负载均衡则是通过在服务器上安装一些具有负载均衡功能或模块的软件来完成请求分发工作,比如Nginx等。(中证报项目用过Nginx负载均衡)
硬件负载均衡的设备或是软件负载均衡的软件模块都会维护一个下挂可用的服务端清单,通过心跳监测来剔除故障的服务端节点以保证清单中都是可以正常访问的服务端节点。当客户端发送请求到负载均衡设备的时候,该设备按某种算法(比如线性轮询、按权重负载、按流量负载等)从维护的可用服务端清单中取出一台服务端的地址,然后进行转发。
客户端的负载均衡和服务端的负载均衡最大的不同点在于服务清单所存储的位置。
在客户端负载均衡中,所有客户端节点都维护着自己要访问的服务端清单,而这些服务端的清单来自于服务注册中心,在客户端负载均衡中也需要心跳去维护服务端清单的健康性,这个步骤需要与服务注册中心配合完成。
通过 Spring Cloud Ribbon 的封装,在微服务架构中使用客户端负载均衡调用非常简单,需要如下两步:
1.服务提供者只需要启动多个服务实例并注册到一个注册中心或是多个相关联的服务注册中心。
2.服务消费者直接通过调用被 @LoadBalanced 注解修饰过的 RestTemplate 来实现面向服务的接口调用。
二、RestTemplate 详解
1、GET请求
两种:
getForEntity:
RestTemplate restTemplate = new RestTemplate ();
ResponseEntity<String> responseEntity = restTemplate.getForEntity("http://HELLO-SERVICE/index?name={1}",String.class,"didi");
String body = responseEntity.getBody();
getForObject:
RestTemplate restTemplate = new RestTemplate ();
String body = restTemplate .getForObject(url, String.class);
2、POST请求
三种:
postForEntity:
使用方法和 getForEntity 函数类似
postForObject :
使用方法和 getForObject 函数类似
postForLocation:
使用方法和上述类似
3、PUT请求、DELETE请求
put 、delete 作为方法名,使用方法和上述类似。
以上都有三种重载:
getForObject(String url, Class responseType, Object… uriVariables)
getForObject(String url, Class responseType, Map<String, ?> uriVariables)
getForObject(URI url, Class responseType)
三、源码分析
Ribbon通过LoadBalacerInerceptor拦截器对RestTemplate的请求进行拦截,并利用SpringCloud的负载均衡器LoadBalancerClient将以逻辑服务名为host的URI转换成具体的服务实例地址的过程。
负载均衡器
虽然Spring Cloud 中定义了LoadBalancerClient作为负载均衡器的通用接口,并且针对Ribbon实现了RibbonLoadBalancerClient,但是它在具体实现客户端负载均衡时,是通过Ribbon的ILoadBalancer接口实现的。
负载均衡策略
Ribbon中实现了非常多的选择策略。
IRule接口的实现:
四、配置详解
1、自动化配置
引入依赖后,能自动化构建以下接口:
IClientConfig:Ribbon的客户端配置
IRule:Ribbon的负载均衡策略,该策略能够在多区域环境下选出最佳区域的实例进行访问。
IPing:Ribbon的实例检查策略,该检查策略是一个特殊的实现,实际上它并不会检查实例是否可用,而是始终返回true,默认认为所有服务实例都是可用的。
ServerList:服务实例清单的维护机制
ServerListFilter:服务实例清单过滤机制,该策略能够优先过滤出与请求调用方处于同区域的服务实例。
ILoadBalancer:负载均衡器,它具备了区域感知的能力。
上面这些自动化配置内容仅在没有引入Spring Cloud Eureka等服务治理框架时如此,在同时引入Eureka和Ribbon依赖时,自动化配置会有一些不同。
针对一些个性化需求,也可以替换上面的默认实现。只需要在Spring Boot应用中创建对应的实现实例就能覆盖这些默认的配置实现。
@Configuration
public class MyRibbonCconfiguration{
@Bean
public IPing ribbonPing(IClientConfig config){
return new PingUrl();
}
}
也可以通过使用@RibbonClient注解来实现更细粒度的客户端配置
@Configuration
@RibbonClient(name="hello-service",configuration=HelloServiceConfiguration.class)
public class RibbonConfiguration{
}
2、Camden版本对RibbonClient配置的优化
在Camden版本中,Sping Cloud Ribbon对RibbonClient定义个性化配置的方法做了进一步优化。可以直接通过.ribbon.=的形式进行配置。
hello-service.ribbon.NFLoadBalancePingClassName=com.netflix.loadbalancer.PingUrl
3、参数配置
Ribbon的参数配置通常有两种方式:全局配置以及指定客户端配置。
全局配置方式只需ribbon.=格式进行配置即可。
其中,代表了Ribbon客户端配置的参数名,则代表了对应参数的值。比如。
我们可以向下面这样全局配置Ribbon创建连接的超时时间:
ribbon.ConnetcTimeout=250
指定客户端的配置方式采用.ribbon.=的格式进行配置。
hello-service.ribbon.listOfServers=localhost:8001,localhost:8002,localhost:8003
4、与Eureka结合
当在Spring Cloud的应用中同时引入Spring Cloud Ribbon和Spring Cloud Eureka依赖时,会触发Eureka中实现的对Ribbon的自动化配置。
服务清单列表由Eureka的服务治理机制来进行维护。
由于Spring Cloud Ribbon默认实现了区域亲和策略,所以,可以通过Eureka实例的元数据配置来实现区域化的实例配置方案。比如,可以将处于不同机房的实例配置成不同区域值,以作为跨区域的容错机制实现。只需要在服务实例的元数据中增加zone参数来指定自己所在的区域:
eureka.instance.metadataMap.zone=shanghai
在Spring Cloud Ribbon与Spring Cloud Enreka结合的工程中,我们也可以通过参数配置的方式来禁用Eureka对Ribbon服务实例的维护实现。在配置中加如下参数,对于服务实例的维护就又回到了.ribbon.listOfServers参数配置的方式来实现了。
ribbon.eureka.enabled=false
五、重试机制
由于Spring Cloud Eureka实现的服务治理机制强调了CAP原理中的AP,即可用性与可靠性,它与ZooKeeper这类强调CP(一致性、可靠性)的服务治理框架最大的区别就是,Eureka为了实现更高的服务可用性,牺牲了一定的一致性,在极端情况下它宁愿接受故障实例也不要丢掉“健康”实例。
由于Spring Cloud Eureka在可用性与一致性上的取舍,我们还是希望能够增强对这类问题的容错。所以,我们在实现服务调用的时候通常会加入一些重试机制。
Spring Cloud整合了Spring Retry来增强RestTemplate的重试能力
可以在配置文件中增加如下内容:
spring.cloud.loadbalancer.retry.enabled=true
hystrix.command.default.execution.isolation.thread.timeoutInMillseconds=10000
hello-service.ribbon.ConnetTimeout=250
hello-service.ribbon.ReadTimeout=1000
hello-service.ribbion.OkToRetryOnAllOperations=true
hello-service.ribbon.MaxAuto.RetriesNextServer=2
hello-service.ribbon.MaxAutoRetries=1
spring.cloud.loadbalancer.retry.enabled:该参数用来开启重试机制,它默认是关闭的。
hystrix.command.default.execution.isolation.thread.timeoutInMillseconds:断路器的超时时间需要大于Ribbon的超时时间,不然不会触发重试。
hello-service.ribbon.ConnectTimeout:请求连接的超时时间。
hello-service.ribbon.ReadTimeout:请求处理的超时时间。
hello-service.ribbon.OkToRetryOnAllOperations:对所有操作请求都进行重试。
hello-service.ribbon.MaxAutoRetriesNextServer:切换实例的重试次数。
hello-service.ribbon.MaxAutoRetries:对当前实例的重试次数。
当访问到故障请求的时候,它会载尝试访问一次当前实例次数(次数由MaxAutoRetries配置),如果不行,就换一个实例进行访问,如果还不行,再换一次实例访问(更换次数由MaxAutoRetriesNextServer配置),如果依然不行,返回失败信息。