Spring Cloud Ribbon:负载均衡的服务调用
Spring Cloud Ribbon:负载均衡的服务调用
1、简介
在微服务架构中,很多服务都会部署多个,其他服务去调用该服务的时候,如何保证负载均衡是个不得不去考虑的问题。负载均衡可以增加系统的可用性和扩展性,当我们使用RestTemplate来调用其他服务时,Ribbon可以很方便的实现负载均衡功能。Spring Cloud Ribbon 是Spring Cloud Netflix 子项目的核心组件之一,主要给服务间调用及API网关转发提供负载均衡的功能, 是基于Netflix Ribbon实现的一套客户端负载均衡的工具(负载均衡 + RestTemplate调用)。
1.1、LB(Load Balance)负载均衡是什么?
简单的说就是将用户的请求平摊的分配到多个服务上,从而达到系统的高可用。
1.2、Ribbon本地负载均衡客户端 VS Nginx服务端负载均衡区别?
- Nginx是服务器负载均衡,客户端的所有请求都会交给Nginx,然后由Nginx实现转发请求,即负载均衡是由服务端实现的。
- Ribbon(进程内LB)是本地负载均衡,在调用微服务接口的时候,会在注册中心上获取注册信息列表之后缓存到JVM本地,从而实现RPC远程调用。
2、RestTemplate的使用
RestTemplate是一个HTTP客户端,使用它我们可以方便的调用HTTP接口,支持GET、POST、PUT、DELETE等方法。
2.1、GET请求方法
<T> T getForObject(String url, Class<T> responseType, Object... uriVariables);
<T> T getForObject(String url, Class<T> responseType, Map<String, ?> uriVariables);
<T> T getForObject(URI url, Class<T> responseType);
<T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Object... uriVariables);
<T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Map<String, ?> uriVariables);
<T> ResponseEntity<T> getForEntity(URI var1, Class<T> responseType);
2.2、getForObject方法
返回对象为响应体中数据转化成的对象,举例如下:
@GetMapping("/{id}")
public CommonResult getUser(@PathVariable Long id) {
return restTemplate.getForObject(userServiceUrl + "/user/{1}", CommonResult.class, id);
}
2.3、getForEntity方法
返回对象为ResponseEntity对象,包含了响应中的一些重要信息,比如响应头、响应状态码、响应体等,举例如下:
@GetMapping("/getEntityByUsername")
public CommonResult getEntityByUsername(@RequestParam String username) {
ResponseEntity<CommonResult> entity = restTemplate.getForEntity(userServiceUrl + "/user/getByUsername?username={1}",
CommonResult.class, username);
if (entity.getStatusCode().isSuccessful()) {
return entity.getBody();
} else {
return new CommonResult("操作失败", 500);
}
}
2.4、POST请求方法
<T> T postForObject(String url, @Nullable Object request, Class<T> responseType, Object... uriVariables);
<T> T postForObject(String url, @Nullable Object request, Class<T> responseType, Map<String, ?> uriVariables);
<T> T postForObject(URI url, @Nullable Object request, Class<T> responseType);
<T> ResponseEntity<T> postForEntity(String url, @Nullable Object request, Class<T> responseType, Object... uriVariables);
<T> ResponseEntity<T> postForEntity(String url, @Nullable Object request, Class<T> responseType, Map<String, ?> uriVariables);
<T> ResponseEntity<T> postForEntity(URI url, @Nullable Object request, Class<T> responseType);
2.5、postForObject示例
@PostMapping("/create")
public CommonResult create(@RequestBody User user) {
return restTemplate.postForObject(userServiceUrl + "/user/create", user, CommonResult.class);
}
2.6、postForEntity示例
@PostMapping("/create")
public CommonResult create(@RequestBody User user) {
return restTemplate.postForEntity(userServiceUrl + "/user/create", user, CommonResult.class).getBody();
}
2.7、PUT请求方法
void put(String url, @Nullable Object request, Object... uriVariables);
void put(String url, @Nullable Object request, Map<String, ?> uriVariables);
void put(URI url, @Nullable Object request);
2.8、PUT请求示例
@PutMapping("/update")
public CommonResult update(@RequestBody User user) {
restTemplate.put(userServiceUrl + "/user/update", user);
return new CommonResult("操作成功",200);
}
2.9、DELETE请求方法
void delete(String url, Object... uriVariables);
void delete(String url, Map<String, ?> uriVariables);
void delete(URI url);
2.10、DELETE请求示例
@DeleteMapping("/delete/{id}")
public CommonResult delete(@PathVariable Long id) {
restTemplate.delete(userServiceUrl + "/user/delete/{1}", null, id);
return new CommonResult("操作成功",200);
}
3、maven依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
<version>2.2.1.RELEASE</version>
<scope>compile</scope>
</dependency>
4、使用@LoadBalanced注解赋予RestTemplate负载均衡的能力
/**
* @Author dw
* @ClassName ApplicationContextConfig
* @Description
* @Date 2020/3/26 15:53
* @Version 1.0
*/
@Configuration
public class ApplicationContextConfig {
@Bean
@LoadBalanced // 使用@LoadBalanced注解赋予RestTemplate负载均衡的能力
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
5、负载均衡算法-轮询算法原理
rest接口第几次请求数 % 服务器集群总量 = 实际调用服务器位置下标,每次重启后rest接口计数从1开始。
获取所有的当前微服务实例:
List<ServiceInstance>instances = discoveryClient.getInstances(“CLOUD-PAYMENT_SERVICE”);
例如:
List[0] instances = 127.0.0.1:8002
List[1] instances = 127.0.0.1:8001
8001 + 8002 组合为集群,他们共两台机器,集群总数为2, 按照轮询算法
- 当请求总数为1时,1 % 2 = 1对应下标为1,则获得127.0.0.1:8001;
- 当请求总数为2时,2 % 2 = 0对应下标为0,则获得127.0.0.1:8002;
- 当请求总数为3时,3 % 2 = 1对应下标为1,则获得127.0.0.1:8001;
- 当请求总数为4时,4 % 2 = 0对应下标为0,则获得127.0.0.1:8002;
6、Ribbon默认的负载均衡的转发规则是轮询,当然也提供了其他的负载均衡规则,如何使用呢?
注意:官方文档提示:自定义的配置类不能放在@ComponentScan所扫描的当前包及子包下。
Ribbon内置的负载规则:
内置负载均衡规则类 |
规则描述 |
RoundRobinRule |
简单轮询服务列表来选择服务器。它是Ribbon默认的负载均衡规则。 |
AvailabilityFilteringRule |
对以下两种服务器进行忽略: |
WeightedResponseTimeRule |
为每一个服务器赋予一个权重值。服务器响应时间越长,这个服务器的权重就越小。这个规则会随机选择服务器,这个权重值会影响服务器的选择。 |
ZoneAvoidanceRule |
以区域可用的服务器为基础进行服务器的选择。使用Zone对服务器进行分类,这个Zone可以理解为一个机房、一个机架等。 |
BestAvailableRule |
忽略那些短路的服务器,并选择并发数较低的服务器。 |
RandomRule |
随机选择一个可用的服务器。 |
Retry |
重试机制的选择逻辑 |
7、Ribbon的常用配置
7.1、全局配置
ribbon:
ConnectTimeout: 1000 #服务请求连接超时时间(毫秒)
ReadTimeout: 3000 #服务请求处理超时时间(毫秒)
OkToRetryOnAllOperations: true #对超时请求启用重试机制
MaxAutoRetriesNextServer: 1 #切换重试实例的最大个数
MaxAutoRetries: 1 # 切换实例后重试最大次数
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule #修改负载均衡算法
7.2、指定服务进行配置
全局配置的区别就是ribbon节点挂在服务名称下面,如下是对ribbon-service调用user-service时的单独配置。
user-service:
ribbon:
ConnectTimeout: 1000 #服务请求连接超时时间(毫秒)
ReadTimeout: 3000 #服务请求处理超时时间(毫秒)
OkToRetryOnAllOperations: true #对超时请求启用重试机制
MaxAutoRetriesNextServer: 1 #切换重试实例的最大个数
MaxAutoRetries: 1 # 切换实例后重试最大次数
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule #修改负载均衡算法