SpringCloud Ribbon(负载均衡)

1.负载均衡LB

全称Load Balance,将用户的请求平摊到多个服务器上,从而达到系统的HA。
1)集中式LB

在服务消费者和服务提供者之间使用独立的LB设施,如硬件,由该设施负责把访问请求通过某种策略转发至服务提供方。
2)进程内LB

将LB逻辑继承到服务消费者,消费者从服务注册中心获知有哪些地址可用,然后从这些地址中选择一个合适的来使用。Ribbon属于进程内LB。

2.Ribbon定义

只使用restTemplate问题是服务的地址是写死的,不利于维护,没有进行负载均衡。而Ribbon基于NetFlix Ribbon实现的一套客户端负载均衡的工具。但它可以结合RestTemplate进行服务之间的调用。

3.项目实战

3.1基础环境搭建

源代码:https://github.com/zhongyushi-git/cloud-ribbon-demo.git

说明:由于Eureka2.0已停止维护,故这里使用consul作为服务注册中心,使用RestTemplate进入服务的调用,使用Ribbon进行服务的负载均衡。

1)创建一个maven工程名为cloud-ribbon-demo,删除src目录

2)在pom中导入依赖,对SpringBoot和SpringCloud版本进行锁定

   <properties>
        <spring.boot.version>2.2.2.RELEASE</spring.boot.version>
        <spring.cloud.version>Hoxton.SR1</spring.cloud.version>
    </properties>

    <!--  依赖管理,父工程锁定版本-->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring.boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring.cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

3.2搭建服务提供者

1)新建maven子模块(cloud-provider8001),导入依赖

     <dependencies>
        <!--web-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-consul-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
    </dependencies>

2)新建启动类ProviderMain8001并添加注解

package com.zys.cloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@SpringBootApplication
@EnableDiscoveryClient
public class ProviderMain8001 {
    public static void main(String[] args) {
        SpringApplication.run(ProviderMain8001.class, args);
    }
}

3)配置application.yml

server:
  port: 8001

spring:
  application:
    name: cloud-consul-provider
  cloud:
    consul:
      host: localhost
      port: 8500
      discovery:
        service-name: ${spring.application.name}

4)新建controller接口

package com.zys.cloud.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/user")
public class UserController {

    @Value("${server.port}")
    private String port;

    @GetMapping("/get")
    public String get() {
        return "我是服务提供者,端口:" + port;
    }
}

5)启动服务,可看到已注册到consul。

6)根据服务提供者ProviderMain8001,再分别创建ProviderMain8002和ProviderMain8003.

3.3搭建服务消费者

1)新建maven子模块(cloud-consumer80),导入依赖

     <dependencies>
        <!--web-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-consul-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
    </dependencies>

2)新建启动类ConsumerMain80并添加注解

package com.zys.cloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@SpringBootApplication
@EnableDiscoveryClient
public class ConsumerMain80 {
    public static void main(String[] args) {
        SpringApplication.run(ConsumerMain80.class, args);
    }
}

3)配置application.yml

server:
  port: 80

spring:
  application:
    name: cloud-consul-consumer
  cloud:
    consul:
      host: localhost
      port: 8500
      discovery:
        service-name: ${spring.application.name}

4)创建配置类,注入RestTemplate

package com.zys.cloud.config;

import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class ConfigBean {

    @Bean
    @LoadBalanced
    public RestTemplate getRestTemplate() {
        return new RestTemplate();
    }
}

要在方法上加@LoadBalanced,否则在服务调用时会报错。添加注解后,在服务调用时,就会根据其负载均衡策略进行服务的负载转发和请求。

5)新建controller接口

package com.zys.cloud.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
@RequestMapping("/consumer")
public class UserController {
private final String BASE_URL = "http://cloud-consul-provider";

@Autowired
private RestTemplate restTemplate;

@GetMapping("/get")
public String addUser() {
return restTemplate.getForObject(BASE_URL + "/user/get", String.class);
}

}

在设置请求路径时,http后面是cloud-consul-provider,这就指定了要调用的服务的名字。这样方便维护,又达到了负载均衡的效果。

5)启动服务,可看到已注册到consul。访问http://localhost/consumer/get,第一次调用的是端口为8001的服务,刷新一次调用的是8002服务,再刷新一次调用的是8003服务,依次轮询。原因是其按默认的轮询策略进行负载的。

6)负载分析。虽然全文都在说Ribbon,但却没有引入其依赖,又能达到效果,这是为何?原因是在引入引入consul时就其已引入了Ribbon,就无需再次引入。

4.Ribbon负载均衡策略

4.1负载策略说明

Ribbon的核心组件是IRule,它的作用就是根据特定的算法从服务列表中选择一个要访问的服务。下面是Ribbon中定义的几种策略:

策略 描述
RandomRule 随机
RoundRobinRule 轮询,按照顺序选择server,是Ribbon默认的策略
RetryRule 重试,在一个配置时间段内,当选择server不成功,则一直尝试选择一个可用的server
BestAvailableRule 最低并发,逐个考察server,如果server断路器打开,则忽略,再选择其中并发链接最低的server
AvailabilityFilteringRule 可用过滤,过滤掉一直失败并被标记为circuit tripped的server,过滤掉那些高并发链接的server
ResponseTimeWeightedRule 响应时间加权重,根据server的响应时间分配权重,响应时间越长,权重越低,被选择到的概率也就越低。
ZoneAvoidanceRule 区域权重,综合判断server所在区域的性能和server的可用性,轮询选择server并且判断一个AWS Zone的运行性能是否可用,剔除不可用的Zone中的所有server

4.2切换默认的策略

有时需要切换默认策略时,也很简单,在服务消费者中进行配置即可。

假设要把轮询策略改为随机策略,步骤如下:

1)在配置类中注入RandomRule

    @Bean
    public IRule RandomRule(){
        return new RandomRule();
    }

截图如下:

2)重启服务消费者,进行测试,发现已是随机调用各个服务。

posted @ 2021-08-05 18:34  钟小嘿  阅读(273)  评论(0编辑  收藏  举报