SpringCloud 使用 LoadBalance 实现客户端负载均衡 您所在的位置:网站首页 ribbon默认负载均衡策略轮询 SpringCloud 使用 LoadBalance 实现客户端负载均衡

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

2023-10-24 17:30| 来源: 网络整理| 查看: 265

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 文件内容如下所示:

4.0.0 com.jobs springcloud_loadbalance pom 1.0-SNAPSHOT eureka_app provider_app1 provider_app2 provider_app3 consumer_app UTF-8 UTF-8 1.8 org.springframework.boot spring-boot-starter-parent 2.6.11 org.springframework.cloud spring-cloud-dependencies 2021.0.3 pom import 二、注册中心搭建

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

image

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

springcloud_loadbalance com.jobs 1.0-SNAPSHOT 4.0.0 eureka_app org.springframework.boot spring-boot-starter-web org.springframework.cloud spring-cloud-starter-netflix-eureka-server

然后在启动来上,添加 @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 的依赖。

springcloud_loadbalance com.jobs 1.0-SNAPSHOT 4.0.0 provider_app1 org.springframework.boot spring-boot-starter-web org.springframework.cloud spring-cloud-starter-netflix-eureka-client

编写 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 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



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

      专题文章
        CopyRight 2018-2019 实验室设备网 版权所有