在微服务实现中,比较重要的一个组建就是负载均衡,主要是同一个服务又多实例时,为了能够将请求分发到不同的实例节点上, 负载均衡是一个比不可少的组件。在spring cloud eureka的实现中,默认使用了ribbon作为服务均衡的实现, 本篇文章主要是以demo的方式优先了解ribbon的一个具体的使用,然后才能更好的从源码角度分析ribbon的工作原理。
微服务准备
在该demo种,将会创建两个简单的服务,提供相同的接口,名称为spring-cloud-eureka-client-a
与spring-cloud-eureka-client-b
服务,这两个服务配置基本一致,不同的时,同在本地运行时,需要修改一下端口的信息。我们为了简便,会在本地运行一个简易的eureka server, 具体demo可以参考spring cloud服务注册之Eureka Server – DEMO
pom.xml
这两个项目都是maven项目,parent
的依赖配置如下:
<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>org.example</groupId> <artifactId>spring-cloud</artifactId> <packaging>pom</packaging> <version>1.0-SNAPSHOT</version> <modules> <module>spring-cloud-eureka-server</module> <module>spring-cloud-eureka-client</module> <module>spring-cloud-eureka-client-a</module> <module>spring-cloud-autoconfigure</module> </modules> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>2.1.12.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Greenwich.SR5</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> </project>
这两个微服务的pom
配置基本一致, 具体pom.xml的配置如下:
<?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>spring-cloud</artifactId> <groupId>org.example</groupId> <version>1.0-SNAPSHOT</version> <relativePath>../pom.xml</relativePath> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>spring-cloud-eureka-client-a</artifactId> <properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-netflix-ribbon</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-autoconfigure</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-context</artifactId> </dependency> <dependency> <groupId>com.netflix.eureka</groupId> <artifactId>eureka-client</artifactId> </dependency> <dependency> <groupId>com.netflix.eureka</groupId> <artifactId>eureka-core</artifactId> </dependency> <dependency> <groupId>com.netflix.ribbon</groupId> <artifactId>ribbon</artifactId> </dependency> <dependency> <groupId>com.netflix.ribbon</groupId> <artifactId>ribbon-core</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-commons</artifactId> </dependency> </dependencies> </project>
spring-cloud-eureka-client-a
application.yaml
yaml
文件配置作为spring服务启动的默认配置文件, 具体配置如下:
spring: cloud: discovery: enabled: true application: name: spring-eureka-client-b main: allow-bean-definition-overriding: true server: port: 8082 management: endpoints: web: exposure: include: prometheus, env,info, health health: show-details: always eureka: client: prefer-ip-address: true service-url: defaultZone: http://localhost:8761/eureka/
spring-cloud-eureka-client-b
application.yaml
spring: cloud: discovery: enabled: true application: name: spring-eureka-client-b main: allow-bean-definition-overriding: true server: port: 8081 management: endpoints: web: exposure: include: prometheus, env,info, health health: show-details: always eureka: client: prefer-ip-address: true service-url: defaultZone: http://localhost:8761/eureka/
Controller
该Controller
在两个服务中为相同的代码,具体就是返回当前的实例信息, 具体代码如下:
package org.spring.learn.eureka.client.controller; import com.netflix.appinfo.ApplicationInfoManager; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.netflix.eureka.EurekaClientConfigBean; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; /** * @author xianglujun * @date 2021/9/15 18:26 * @since */ @RestController public class InfoController { @Autowired private ApplicationInfoManager applicationInfoManager; @GetMapping("/info") public String info() { return applicationInfoManager.getInfo().getId(); } }
Application启动类
启动类则是启动spring cloud的微服务信息, 具体源码如下:
package org.spring.learn.eureka.client; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; @SpringBootApplication @EnableDiscoveryClient public class SpringEurekaClientDemoBApplication { public static void main(String[] args) { SpringApplication.run(SpringEurekaClientDemoBApplication.class, args); } }
负载均衡客户端配置
这里我们通过引入ribbon的方式, 在客户端配置ribbon, 并负载均衡的调用以上的两个服务,具体配置如下:
RestTemplate配置
@Service public class RibbonService { @LoadBalanced @Bean public RestTemplate restTemplate() { return new RestTemplate(); } }
调用远程服务
@RestController public class InfoController { @Autowired private RestTemplate restTemplate; @GetMapping("/info") public String info() { return restTemplate.getForObject("http://SPRING-EUREKA-CLIENT-B/info", String.class); } }
启动服务
@SpringBootApplication @EnableDiscoveryClient public class SpringEurekaClientDemoApplication { public static void main(String[] args) { SpringApplication.run(SpringEurekaClientDemoApplication.class, args); } }
当服务启动完成之后,我们通过调用本地http://localhost:8080/info
查看调用的实例信息, 有如下日志信息:
通过浏览器上输出信息,可以知道服务均衡起到了作用,至此负载均衡的实现demo实现到此完成。