参考博文:https://www.jianshu.com/p/1bd66db5dc46
Ribbon简介
Spring Cloud Ribbon是一个基于HTTP和TCP的客户端负载均衡工具,它基于Netflix Ribbon实现。通过Spring Cloud的封装,可以让我们轻松地将面向服务的REST模版请求自动转换成客户端负载均衡的服务调用。Spring Cloud Ribbon虽然只是一个工具类框架,它不像服务注册中心、配置中心、API网关那样需要独立部署,但是它几乎存在于每一个Spring Cloud构建的微服务和基础设施中。因为微服务间的调用,API网关的请求转发等内容,实际上都是通过Ribbon来实现的,包括后续我们将要介绍的Feign,它也是基于Ribbon实现的工具。所以,对Spring Cloud Ribbon的理解和使用,对于我们使用Spring Cloud来构建微服务非常重要。
客户端负载均衡
负载均衡在系统架构中是一个非常重要,并且是不得不去实施的内容。因为负载均衡是对系统的高可用、网络压力的缓解和处理能力扩容的重要手段之一。我们通常所说的负载均衡都指的是服务端负载均衡,其中分为硬件负载均衡和软件负载均衡。硬件负载均衡主要通过在服务器节点之间按照专门用于负载均衡的设备,比如F5等;而软件负载均衡则是通过在服务器上安装一些用于负载均衡功能或模块等软件来完成请求分发工作,比如Nginx等。不论采用硬件负载均衡还是软件负载均衡,只要是服务端都能以类似下图的架构方式构建起来:
硬件负载均衡的设备或是软件负载均衡的软件模块都会维护一个下挂可用的服务端清单,通过心跳检测来剔除故障的服务端节点以保证清单中都是可以正常访问的服务端节点。当客户端发送请求到负载均衡设备的时候,该设备按某种算法(比如线性轮询、按权重负载、按流量负载等)从维护的可用服务端清单中取出一台服务端端地址,然后进行转发。
而客户端负载均衡和服务端负载均衡最大的不同点在于上面所提到服务清单所存储的位置。在客户端负载均衡中,所有客户端节点都维护着自己要访问的服务端清单,而这些服务端端清单来自于服务注册中心,比如上一章我们介绍的Eureka服务端。同服务端负载均衡的架构类似,在客户端负载均衡中也需要心跳去维护服务端清单的健康性,默认会创建针对各个服务治理框架的Ribbon自动化整合配置,比如
Eureka中的org.springframework.cloud.netflix.ribbon.eureka.RibbonEurekaAutoConfiguration,
Consul中的org.springframework.cloud.consul.discovery.RibbonConsulAutoConfiguration。
在实际使用的时候,我们可以通过查看这两个类的实现,以找到它们的配置详情来帮助我们更好地使用它。
通过Spring Cloud Ribbon的封装,我们在微服务架构中使用客户端负载均衡调用非常简单,只需要如下两步:
(1)服务提供者只需要启动多个服务实例并注册到一个注册中心或是多个相关联的服务注册中心。
(2)服务消费者直接通过调用被@LoadBalanced注解修饰过的RestTemplate来实现面向服务的接口调用。
这样,我们就可以将服务提供者的高可用以及服务消费者的负载均衡调用一起实现了。
前提
RestTemplate非常有用,该对象会使用Ribbon的自动化配置,同时通过配置@LoadBalanced还能够开启客户端负载均衡。
下面将详细介绍RestTemplate针对几种不同请求类型和参数类型的服务调用实现。
一、get请求
在RestTemplate中,对GET请求可以通过如下两个方法进行调用实现。
第一种:getForEntity函数。
该方法返回的是ResponseEntity,该对象是Spring对HTTP请求响应的封装,其中主要存储了HTTP的几个重要元素,比如HTTP请求状态码的枚举对象HttpStatus(也就是我们常说的404、500这些错误码)、在它的父类HttpEntity中还存储着HTTP请求的头信息对象HttpHeaders以及泛型类型的请求体对象。
1、返回String类型的结果:
@GetMapping("/findStringById/{id}")
public String findStringById(@PathVariable Long id) {
ResponseEntity<String> responseEntity = this.restTemplate.getForEntity("http://microservice-provider-user/"+id, String.class);
String body = responseEntity.getBody();
return body;
}
1、返回User类型的结果:
@GetMapping("/findUserById/{id}")
public User findUserById(@PathVariable Long id) {
ResponseEntity<User> responseEntity = this.restTemplate.getForEntity("http://microservice-provider-user/"+id, User.class);
User body = responseEntity.getBody();
return body;
}
第二种:getForObject函数。
getForObject函数。该方法可以理解为对getForEntity的进一步封装,它通过HttpMessageConverterExtractor对HTTP的请求响应体body内容进行对象转换,实现请求直接返回包装好的对象内容。当不需要关注请求响应除body外的其他内容时,该函数就非常好用,可以少一个从Response中获取body的步骤。
//返回User类型
@GetMapping("/user/{id}")
public User findById(@PathVariable Long id) {
return this.restTemplate.getForObject("http://microservice-provider-user/" + id, User.class);
}
//返回String类型
@GetMapping("/user1/{id}")
public String findById1(@PathVariable Long id) {
return this.restTemplate.getForObject("http://microservice-provider-user/" + id, String.class);
}
一、post请求
在RestTemplate中,对POST请求可以通过如下两个方法进行调用实现。
第一种:postForEntity
该方法同GET请求中的getForEntity类似,会在调用后返回ResponseEntity对象,其中T为请求响应的body类型。
@GetMapping(value="/addUser")
public String addUser() {
User user = new User();
user.setId(2l);
user.setName("suxing");
user.setAge(21);
user.setUsername("account2");
user.setBalance(new BigDecimal(500.00));
ResponseEntity<String> responseEntity = this.restTemplate.postForEntity("http://microservice-provider-user/add",user, String.class);
String body = responseEntity.getBody();
return body;
}
第一种:postForObject
该方法也跟getForObject的类型类似,它的作用就是简化postForEntity的后续处理。通过直接将请求响应的body内容包装成对象来返回使用。
@GetMapping(value="/addUser1")
public String addUser1() {
User user = new User();
user.setId(2l);
user.setName("suxing");
user.setAge(21);
user.setUsername("account2");
user.setBalance(new BigDecimal(500.00));
String body = this.restTemplate.postForObject("http://microservice-provider-user/add",user,String.class);
return body;
}
第一种:postForLocation
该方法实现了以POST请求提交资源,并返回新的资源的URI。
@GetMapping(value="/addUser2")
public URI addUser2() {
User user = new User();
user.setId(2l);
user.setName("suxing");
user.setAge(21);
user.setUsername("account2");
user.setBalance(new BigDecimal(500.00));
URI uri = this.restTemplate.postForLocation("http://microservice-provider-user/add",user);
return uri;
}