ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

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

2022-08-27 20:00:49  阅读:250  来源: 互联网

标签:服务提供者 SpringCloud LoadBalance springframework eureka import org cloud 客户端


SpringCloud 从 2020.0.1 版本开始,从 Eureka 中移除了 Ribbon 组件,使用 LoadBalance 组件来代替 Ribbon 实现客户端负载均衡。LoadBalance 组件相对于 Ribbon 来说,仅支持两种负载均衡策略:【轮询策略】和【随机策略】,估计后续会增加更多的负载均衡算法策略吧,从我个人的使用经验来说,其实 Ribbon 的负载均衡功能挺好用的。

本篇博客以目前最新版本的 SpringCloud 2021.0.3 版本为例,通过代码的方式来介绍使用 LoadBalance 组件实现客户端负载均衡的用法,在本篇博客的最后会提供源代码的下载。


一、搭建工程

采用 Maven 搭建 springcloud_loadbalance 父工程,下面包含 5 个子工程:

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

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

image

对于 springcloud_loadbalance 父工程 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_loadbalance</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.6.11</version>
        <relativePath/>
    </parent>

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

二、注册中心搭建

在本篇博客的 Demo 中,仅搭建一个 Eureka 注册中心就能够满足使用了。

image

首先在 pom 文件中引入 spring-cloud-starter-netflix-eureka-server 的依赖。

<?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_loadbalance</artifactId>
        <groupId>com.jobs</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>eureka_app</artifactId>

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

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

然后在启动来上,添加 @EnableEurekaServer 注解

package com.jobs.server;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

// 启用EurekaServer
@EnableEurekaServer
@SpringBootApplication
public class EurekaApp {
    public static void main(String[] args) {
        SpringApplication.run(EurekaApp.class,args);
    }
}

然后配置 Eureka 的 application 的 yml 文件。需要注意的是:需要将 Eureka 的 hostname 在本机的 hosts 文件中建立与本机 ip 的映射关系,因为后续在配置服务消费者和服务提供者的注册中心地址时,使用 Eureka 的 hostname 比较方便一些。

# eureka 的默认端口是 8761,这里使用默认端口
server:
  port: 8761

eureka:
  instance:
    # 配置主机名,请在【hosts】文件中进行ip映射配置,
    # 因为后续的服务消费者和服务提供者需要使用这里的 hostname 配置其注册的 eureka 地址
    hostname: eureka-server
  client:
    service-url:
      # 该 eureka 注册中心对外提供的注册地址
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka
    # 是否将自己的路径注册到 eureka 上,单个 eureka 不需要把自己注册的自己上
    register-with-eureka: false
    # 是否需要从 eureka 中抓取路径,单个 eureka 不需要把自己从自己上获取服务的 url 地址
    fetch-registry: false
  server:
    # 关闭 eureka 自我保护,当注册的服务未及时发送心跳时,自动移除服务
    enable-self-preservation: false
    # eureka 检查服务是否存在的时间间隔(毫秒)
    eviction-interval-timer-in-ms: 5000

# 单个 eureka 节点,因为不需要注册到自己身上,所以下面不需要配置
spring:
  application:
    name: eureka-server

三、服务提供者搭建

本篇博客使用的服务提供者代码,跟上一篇博客的代码基本相同,只不过搭建了 3 个服务提供者,在接口返回的 json 结果中增加了 provider 字段,内容是服务提供者的 application 名称和配置的端口,用于验证负载均衡的调用效果,这里以 provider-app1 为例进行介绍。

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_loadbalance</artifactId>
        <groupId>com.jobs</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>provider_app1</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>

编写 provider-app1 的 application.yml 配置文件

server:
  port: 8201

eureka:
  instance:
    # 配置主机名
    hostname: provider-service1
    # 显示 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

# provider 集群需要使用相同的 application 名称
spring:
  application:
    name: provider-App

需要注意的是:本篇博客使用 3 个服务提供者搭建集群,因此 3 个服务提供者必须使用相同的 application 名称,这里统一配置为 provider-app ,最后列出服务提供者所提供的接口内容:

package com.jobs.provider.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

@RequestMapping("/provider")
@RestController
public class ProviderController {

    @Autowired
    private Environment env;

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

        //获取当前服务提供者的 hostname 和 port
        String providerName = env.getProperty("eureka.instance.hostname")
                + ":" + env.getProperty("server.port");

        Map result = new HashMap();
        result.put("status", 0);
        result.put("msg", "success");
        result.put("provider", providerName);
        result.put("get_id_value", id);
        result.put("version", UUID.randomUUID().toString());

        return result;
    }
}

四、服务消费者搭建

这里是本篇博客介绍的重点,因为 SpringCloud 使用 LoadBalance 实现负载均衡,就是在服务消费者这里实现的。

image

首先需要引入 spring-cloud-starter-netflix-eureka-client 的依赖,其 pom 文件跟服务提供者相同,这里不再列出。

这里先列出服务消费者的 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

# SpringCloud 从 2020.0.1 版本之后,客户端负载均衡抛弃了 ribbon
# 采用 SpringCloud LoadBalancer 默认使用的是轮询负载均衡算法
# 要想使用随机算法,也很简单,本篇博客的 demo 也就介绍,您也可以查看官网
# https://docs.spring.io/spring-cloud-commons/docs/current/reference/html/#spring-cloud-loadbalancer

SpringCloud 的 LoadBalance 仅支持 2 种负载均衡策略:轮询(默认)和随机,后续应该会支持更多,先介绍随机策略的使用吧。

只需要在 RestTemplate 的 Bean 对象上增加 @LoadBalanced 注解即可,其实上一篇博客的 demo 就已经使用了。

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;

/*
    SpringCloud 从 2020.0.1 版本开始,从 eureka 中移除了 ribbon
    使用 SpringCloud LoadBalance 替代 ribbon 进行客户端负载均衡
    目前 SpringCloud LoadBalance 仅支持两种负载均衡策略:【轮询策略】和【随机策略】
*/

@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 是从注册中心界面中复制过来的。

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


五、采用随机负载均衡策略

服务的消费者如果想采用随机的负载均衡策略,非常简单,可以参考以下官网地址:

https://docs.spring.io/spring-cloud-commons/docs/current/reference/html/#spring-cloud-loadbalancer

需要通过以下两个步骤即可实现:

首先需要定义随机的算法对象,并通过 @Bean 将其加载到 Spring 容器中,具体如下:

package com.jobs.consumer.config;

import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.loadbalancer.core.RandomLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ReactorLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.core.env.Environment;

public class RandomLoadBalancerConfig {

    @Bean
    ReactorLoadBalancer<ServiceInstance> randomLoadBalancer(
            Environment environment, LoadBalancerClientFactory loadBalancerClientFactory) {

        String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
        return new RandomLoadBalancer(loadBalancerClientFactory
                .getLazyProvider(name, ServiceInstanceListSupplier.class), name);
    }
}

然后在 RestTemplate 配置类上方,使用 @LoadBalancerClient 或 @LoadBalancerClients 注解,针对具体服务配置具体的客户端负载均衡算法策略,由于本篇博客只有一个服务提供者集群,因此这里使用 @LoadBalancerClient 注解进行演示:

package com.jobs.consumer.config;

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

/*
    SpringCloud 从 2020.0.1 版本开始,从 eureka 中移除了 ribbon
    使用 SpringCloud LoadBalance 替代 ribbon 进行客户端负载均衡
    目前 SpringCloud LoadBalance 仅支持两种负载均衡策略:【轮询策略】和【随机策略】
*/

//使用 @LoadBalancerClient 或 @LoadBalancerClients 注解,针对具体服务配置具体的客户端负载均衡算法策略
@LoadBalancerClient(name = "PROVIDER-APP", configuration = RandomLoadBalancerConfig.class)
@Configuration
public class RestTemplateConfig {

    @LoadBalanced
    @Bean
    public RestTemplate restTemplate() {

        return new RestTemplate();
    }
}

重启消费者程序后,再调用服务消费者 PROVIDER-APP 所提供的接口时,采用的就是随机的客户端负载均衡测量。



OK,到此为止,有关 SpringCloud 在 2020.0.1 版本之后,使用 LoadBalance 代替 Ribbon 实现客户端负载均衡的实现方式,已经介绍完毕。目前官网只支持【轮询】和【随机】两种算法,希望后续能够像 Ribbon 一样支持更多的负载均衡算法。

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

标签:服务提供者,SpringCloud,LoadBalance,springframework,eureka,import,org,cloud,客户端
来源: https://www.cnblogs.com/studyjobs/p/16631328.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有