SpringCloud 使用 Ribbon 实现客户端负载均衡

SpringCloud 在 2020.0.1 版本之前,服务的消费者在引入 spring-cloud-starter-netflix-eureka-client 的依赖后(该依赖内置了 Ribbon 依赖),就可以使用 Ribbon 客户端负载均衡了。Ribbon 支持 10 种客户端负载均衡策略,使用起来很方便。

本篇博客基于上篇博客的 Demo 进行简单改造,服务消费者调用服务提供者的接口,采用Ribbon 进行客户端负载均衡,总体过程非常简单。在本篇博客的最后会提供 Demo 源代码的下载。


一、搭建工程

与上一篇博客的 Demo 基本相同,采用 Maven 搭建 springcloud_ribbon 父工程,下面包含 5 个子工程:

  • 1 个 Eureka 注册中心
  • 1 个 Consumer 服务消费者
  • 3 个 Provider 服务提供者

搭建后的效果如下图所示:

image

对于 springcloud_ribbon 父工程 pom 文件内容如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.jobs</groupId>
    <artifactId>springcloud_ribbon</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>eureka_app</module>
        <module>provider_app1</module>
        <module>provider_app2</module>
        <module>provider_app3</module>
        <module>consumer_app</module>
    </modules>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <!--spring boot-->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.12.RELEASE</version>
    </parent>

    <!--Spring Cloud-->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Hoxton.SR12</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
</project>

注意:这里使用 SpringBoot 的版本是 2.3.12.RELEASE ,使用的 SpringCloud 版本是 Hoxton.SR12

有关【Eureka 注册中心】和【服务提供者】的搭建过程,这里就省略了,跟上篇博客一模一样。


二、服务消费者搭建

本篇博客的服务消费者搭建的结果如下所示:

image

在 pom 文件中引入 spring-cloud-starter-netflix-eureka-client 的依赖,如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>springcloud_ribbon</artifactId>
        <groupId>com.jobs</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>consumer_app</artifactId>

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

        <!--eureka-client-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
    </dependencies>
</project>

查看 spring-cloud-starter-netflix-eureka-client 下所包含的 jar 包结构,可以发现其包含了 ribbon 的 jar 包依赖。

image

下面列出 application.yml 的内容,跟上一篇博客完全一样。

server:
  port: 8100

eureka:
  instance:
    # 配置主机名
    hostname: consumer-service
    # 显示 ip 地址,代替显示主机名
    prefer-ip-address: true
    # 所注册服务实例名称的显示形式
    instance-id: ${eureka.instance.hostname}:${server.port}
    # 每隔 3 秒发一次心跳包
    lease-renewal-interval-in-seconds: 3
    # 如果 15 秒没有发送心跳包,就让 eureka 把自己从服务列表中移除
    lease-expiration-duration-in-seconds: 15
  client:
    service-url:
      # 将当前 springboot 服务注册到 eureka 中
      defaultZone: http://eureka-server:8761/eureka
    # 是否将自己的路径注册到 eureka 上
    register-with-eureka: true
    # 是否需要从 eureka 中抓取路径
    fetch-registry: true

# consumer 使用的 application 名称
spring:
  application:
    name: consumer-App

只需要在 RestTemplate 的 Bean 对象上增加 @LoadBalanced 注解,即可实现 ribbon 客户端负载均衡的默认策略:轮询。

package com.jobs.consumer.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 RestTemplateConfig {

    @LoadBalanced
    @Bean
    public RestTemplate restTemplate() {

        return new RestTemplate();
    }
}

然后使用 RestTemplate 调用服务提供者的接口时,使用服务提供者的 application 名称,从注册中心获取服务提供者集群的所有服务地址,自动在本地通过负载均衡的算法,决定要调用那一个服务地址。

需要注意的是:服务提供者的名称最好从 Eureka 注册中心界面中复制,这么不容易出错。

下面列出服务消费者调用服务提供者接口的代码

package com.jobs.consumer.controller;

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

import java.util.Map;

@RequestMapping("/consumer")
@RestController
public class ConsumerController {

    @Autowired
    private RestTemplate restTemplate;

    @RequestMapping("/getdata/{id}")
    public Map GetData(@PathVariable("id") int id) {

        //使用服务在 eureka 上注册的 application 名称代替 ip 和端口号
        String url = "http://PROVIDER-APP/provider/getdata/" + id;
        Map result = restTemplate.getForObject(url, Map.class);
        return result;
    }
}

注意:上面采用 PROVIDER-APP 代替了服务提供者的 ip 和 端口,PROVIDER-APP 是从注册中心界面中复制过来的。

到此为止,服务的消费者采用轮询的客户端负载均衡方式,调用服务提供者接口的代码示例,已经搭建完毕,可以进行测试验证。


三、使用其它负载均衡策略

只需要通过 2 个步骤即可实现:

首先需要定义一个配置类,提供一个方法用于将系统内置的负载均衡算法对象加载到 Spring 容器中。

package com.jobs.consumer.config;

import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class LoadBalanceRule {

    @Bean
    public IRule rule(){
        /*
            需要注意:SpringCloud 在 2010.0.1 版本之前,集成了 Ribbon。
            在 2010.0.1 版本之后,使用 LoadBalance 替代了 Ribbon。

            当前使用的 SpringCloud 版本为 Hoxton.SR12 ,可以使用 Ribbon。

            Ribbon 提供了 10 种客户端负载均衡策略,
            如果不配置的话,默认采用轮询策略

            常用的有 7 种,如下所示:
            随机 :RandomRule
            轮询 :RoundRobinRule
            最小并发:BestAvailableRule
            可用性过滤:AvailabilityFilteringRule
            最小响应时间:WeightedResponseTimeRule
            失败后轮询重试:RetryRule
            性能可用性:ZoneAvoidanceRule
         */

        //此处采用的负载均衡策略为随机
        return new RandomRule();
    }
}

然后在服务消费者的 SpringBoot 启动类上,@RibbonClient 或 @RibbonClients 注解,针对不同的服务提供者,配置不同的客户端负载均衡策略。由于本 Demo 只有一个 PROVIDER-APP 服务提供者,因此使用 @RibbonClient 进行配置。

package com.jobs.consumer;

import com.jobs.consumer.config.LoadBalanceRule;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.ribbon.RibbonClient;

/*
在这里可以通过 @RibbonClient 和 @RibbonClients 两个注解,
针对不同的服务提供者,配置不同的客户端负载均衡策略。
本 Demo 只有一个 PROVIDER-APP 服务提供者,因此只配置了一个服务,配置为随机策略。
如果针对具体的服务提供者,不配置负载均衡策略的话,默认采用轮询策略。
*/
@RibbonClient(name = "PROVIDER-APP",configuration = LoadBalanceRule.class)
@SpringBootApplication
public class ConsumerApp {
    public static void main(String[] args) {
        SpringApplication.run(ConsumerApp.class,args);
    }
}

经过以上配置后,重启消费者程序后,再调用 PROVIDER-APP 所提供的接口时,采用的就是随机的客户端负载均衡策略。



OK,到此为止,有关 SpringCloud 使用 Ribbon 实现客户端负载均衡的实现方式,已经介绍完毕。

本篇博客的源代码下载地址为:https://files.cnblogs.com/files/blogs/699532/springcloud_ribbon.zip

posted @ 2022-08-31 13:46  乔京飞  阅读(10929)  评论(0编辑  收藏  举报