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

对以下两种服务器进行忽略:
(1)在默认情况下,这台服务器如果3次连接失败,这台服务器就会被设置为“短路”状态。短路状态将持续30秒,如果再次连接失败,短路的持续时间就会几何级地增加。
(2)并发数过高的服务器。如果一个服务器的并发连接数过高,配置了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 #修改负载均衡算法

 

posted @ 2020-04-05 11:29  邓维-java  阅读(178)  评论(0编辑  收藏  举报