Ribbon几乎存在于每一个Spring cloud构建的微服务和基础设施中,因为微服务之间的调用,API网关的请求转发等内容实际上都是通过Ribbon来实现的,是一个客户端负载均衡的工具类框架。
通过Spring Cloud Ribbon的封装,在微服务架构中使用客户端负载均衡调用很简单,只需要两个步骤:
1、服务提供者只需要启动多个服务实例并注册到注册中心
2、服务消费者直接通过调用被@LoadBalanced注解修饰过的RestTemplate来实现面向服务的接口调用
在《Spring cloud Eureka服务治理 (1)》中使用了RestTemplate实现了最简单的服务访问,下面介绍一下RestTemplate针对几种不同请求类型和参数类型的服务调用实现;
GET请求
在 RestTemplate 中, 对 GET 请求可以通过如下两个方法进行调用实现。
(1)getForEntity
该方法返回的是 ResponseEntity, 该对象是 Spring 对 HTTP 请求响应的封装, 其中主要存储了 HTTP 的几个重要元素, 比如 HTTP 请求状态 码的枚举对象 HttpStatus (也就是我们常说的 404、 500 这些错误码)、 在它的父类 httpEntity 中还存储着 HTTP 请求的头信息对象 HttpHeaders 以及泛型类型的请求体 对象。 比如下面的例子, 就是访问 USER-SERVER 服务的/user 请求, 同时最后一个参数 didi 会替换 url 中的{ 1} 占位符, 而返回的 ResponseEntity 对象中的 body 内容类型 会根据第二个参数转换为 String 类型
Res七Template restTemplate = new RestTemplate();
ResponseEntity<String> responseEntity = restTemplate.getForEntity("http://USER SERVICE/user?name= {1}", String.class, "didi");
String body = responseEntity. getBody();
还有三种不同的重载方法:
getForEntity(String url, Class responseType, Object... urlVariables):
getForEntity(String url, Class responseType, Map urlVariables): map中以键值对的方法存放参数
getForEntity(URI url, Class responseType)
(2)getForObject
getForObject (String url, Class responseType, Object... urlVariables):
getForObject(String url, Class responseType, Map urlVariables)
getForObject(URI url, Class responseType)
RestTemplale restTemplate = new RestTemplate();
String result = restTemplate.getForObject(uri, String.class);
POST请求:
RestTemplate restTemplate = new RestTemplate();
User user = new User("didi", 30);
ResponseEntity<String> responseEntity =
restTemplate.postForEntity("http://USER-SERVICE/user", user, String.class);
String body = responseEntity.getBody();
postForEntity函数也实现了三种不同的重载方法:
postForEntity(String url, Object request, Class responseType, Object... uriVariables)
postForEntity(String url, Object request, Class responseType, Map uriVariables)
postForEntity(URI url, Object request, Class responseType)
postForObject 函数。 该方法也跟getForObject 的类型类似, 它的作 用是简化postForEntity的后续处理
RestTemplate restTemplate = new RestTemplate();
User user = new User("didi", 20);
String postResult = restTempla七e.postForObject("http://USER-SERVICE/user", user,
String.class);
postForObjec七函数也实现了三种 不同的重载方法:
• postForObject(String url, Object request, Class responseType, Object... uriVariables)
• postForObject(String url, Object request, Class responseType, Map uriVariables)
• postForObject(URI url, Object request, Class responseType)
User user = new User("didi", 40);
URI responseURI = restTemplate.postForLocation("http://USER-SERVICE/user", user);
postForLocation函数也实现了三种不同的重载方法:
postForLocation(Stringurl, Object request, Object...urlVariables)
postForLocation(String url, Object request, Map urlVariables)
postForLocation(URI url, Object request)
PUT请求:
RestTemplate restTemplate = new RestTemplate ();
Long id = 100011;
User user = new User("didi", 40);
restTemplate.put("http://USER-SERVICE/user/{l}", user, id);
put函数也实现 了三种不同的重载方法:
• put(String url, Object request, Object... urlVariables)
• put(String url, Object request, Map urlVariables)
• put(URI url, Object request)
DELETE请求:
RestTemplate restTemplate = new RestTemplate();
Long id= 10001L;
restTemplate.delete("http://USER-SERVICE/user/{1)", id);
delete函数也实现了三种不同的重载方法:
• delete(String url, Object ... urlVariables)
• delete(String url, Map urlVariables)
• delete(URI url)
Spring cloud Ribbon自动化配置:
IclientConfig:Ribbon的客户端配置
IRule:Ribbon的负载均衡策略
IPing:Ribbon的实例检查策略
ServiceList<Server>:服务实例清单的维护机制
ServerListFilter<Server>:服务实例清单过滤机制
ILoadBalancer:负载均衡器
自定义负载均衡策略:
两种方式,
第一,代码方式:
新建一个类,加上@Configration注解,并且包含一个返回IRule的Bean:
@Configuration
public class RibbonRuleConfiguration {
@Bean
public IRule ruleStyle(){
// return new BestAvailableRule(); //选择一个最小的并发请求的server
// return new WeightedResponseTimeRule(); //根据相应时间分配一个weight,相应时间越长,weight越小,被选中的可能性越低。
// return new RetryRule(); //对选定的负载均衡策略机上重试机制。
// return new RoundRobinRule(); //roundRobin方式轮询选择server
// return new RandomRule(); //随机选择一个server
// return new ZoneAvoidanceRule(); //复合判断server所在区域的性能和server的可用性选择server
return new RandomRule();
}
}
上面是使用了随机策略,
然后再application上加注解@RibbonClients,表示对调用的所有服务使用这个策略。
@EnableDiscoveryClient
@SpringBootApplication
@RibbonClients(defaultConfiguration = RibbonRuleConfiguration.class)
public class RibbonApplication {
@Bean
@LoadBalanced
RestTemplate restTemplate(){
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(RibbonApplication.class, args);
}
}
如果想要指定单个服务的策略:
@RibbonClient(name="server-hi",configuration = RibbonRuleConfiguation.class)
上面就是只对server-hi使用了此策略。
但是使用上诉的方式,如果调用的服务太多,那么就会有很多configuration类,application中也很臃肿,所以还有一种配置文件方式:
helloservice-1.ribbon.NFLoadBalancerRuleClassNam=com.netflix.loadbalancer.RandomRule
helloservice-1 是服务名,等号后面就是负载均衡策略。
重试机制:
Eureka为了更高的服务可用性,牺牲了一定的一致性,在极端情况下,宁愿接受故障实例,也不要丢掉实例,当服务注册中心的网络发生故障断开时, 由于所有 的服务实例无法维持续约心跳, 在强调AP的服务治理中将会把所有服务实例都剔除掉, 而Eureka则会因为超过85%的实例丢失心跳而会触发保护机制,注册中心将会保留此时的 所有节点, 以实现服务间依然可以进行互相调用。
以之前的服务helloservice-1为例,可以在配置文件中增加以下内容:
helloservice-1.ribbon.ConnectTimeOut=250
#请求连接的超时时间
helloservice-1.ribbon.ReadTimeOut=1000
#请求处理的超时时间
helloservice-1.ribbon.OkToRetryOnAllOperations=true
#对所有服务都进行重试
helloservice-1.ribbon.MaxAutoRetriesNextServer=2
#切换实例重试的次数
helloservice-1.ribbon.MaxAutoRetries=1
#单个实例重试的次数