SpringCloud学习之路(2)——负载均衡 Ribbon

本系列文章用于记录SpringCloud的学习历程,计划会先简单地过一遍各个组件,分别写个小Demo,混个眼熟;然后再去看一下源码,理解原理。

本系列文章导航:


Ribbon简介

Ribbon是Netflix发布的负载均衡器,它有助于控制HTTP和TCP的客户端的行为。 为Ribbon配置服务提供者地址后,Ribbon就可基于某种负载均衡算法,自动地帮助服务消费者去请求。 Ribbon默认为我们提供了很多负载均衡算法,例如轮询、随机等。当然,我们也可为Ribbon实现自定义的负载均衡算法。 在Spring Cloud中,当Ribbon与Eureka配合使用时,Ribbon可自动从Eureka Server获取服务提供者地址列表,并基于负载均衡算法,请求其中一个服务提供者实例。


前期准备

本系列文章所使用的软件版本如下:

  1. SpringBoot (2.1.3.RELEASE)
  2. SpringCloud (Finchley.RELEASE)

项目采用maven构建,相关pom文件如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.1.3.RELEASE</version>
    <relativePath/>
</parent>
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Finchley.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

完成一个Ribbon的Demo,还需要以下这些组件:

  1. 注册中心 Eureka
  2. 多个服务提供者
  3. 一个服务调用者

SpringCloud学习之路(1)——注册中心 Eureka 一文中,我们已经有了这些组件了,具体可以去再过一遍,这里需要做的改造只有将一个服务提供者扩充为多个。


多个服务提供者

在这里我们采用不同的端口来完成多个服务提供者的扩充,可以在idea启动时指定参数:

1
-Dserver.port=xxx

为了区分不同服务提供者,对其服务方法也进行一点改造,具体如下:

1
2
3
4
5
6
7
8
9
10
@RestController
public class ProviderCtl {
    @Value("${server.port}")
    private String port;

    @GetMapping("hello")
    public String sayHello() {
        return "hello from Provider, Port: " + port;
    }
}

改造完成!


服务调用者

负载均衡是在服务调用者这边实现的,在SpringCloud学习之路(1)——注册中心 Eureka中其实已经实现,这里再作一下说明。

在配置 RestTemplate 实例的时候,我们引入了一个注解 @LoadBalanced,这将会在RestTemplate中加入LoadBalancerInterceptor这个拦截器, 把 RestTemplate 配置成一个具有负载均衡能力的客户端:

1
2
3
4
5
6
7
8
@Configuration
public class HttpClient {
    @Bean("restTemplate")
    @LoadBalanced
    public RestTemplate getRestTemplate() {
        return new RestTemplate();
    }
}

多次访问 http://loclahost:22001/hello,可以看到以下结果轮流出现:

1
2
hello from Provider, Port: 21001
hello from Provider, Port: 21002

也可通过 LoadBalancerClient, 来获取选择的服务的一些信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@RestController
public class InvokerCtl {
    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private LoadBalancerClient loadBalancerClient;

    @GetMapping("hello")
    public String sayHello() {
        String url = "http://service-provider1/hello";
        return restTemplate.getForObject(url, String.class);
    }
    @GetMapping("info")
    public String serviceInfo() {
        ServiceInstance choose = loadBalancerClient.choose("service-provider1");
        return "HOST: " + choose.getHost() + " PORT: " + choose.getPort();
    }
}

上面讲到,Ribbon默认为我们提供了很多负载均衡算法,例如轮询、随机等。 而从demo的结果来看,其默认的算法为轮询,如果想要变成其他算法,比如随机,可以修改配置文件:

1
2
3
4
5
# 相应的服务名
service-provider1:
  ribbon:
    # 负载均衡算法
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

重新起服务,可以看到结果变成了随机出现了。

(完)