原文: https://howtodoinjava.com/spring-cloud/spring-boot-ribbon-eureka/
在此 Spring 云教程中,学习在 Spring Boot / Cloud 项目中使用 Netflix Ribbon 使用客户端负载平衡。 学习构建基于微服务的应用程序,这些应用程序使用 Ribbon 作为客户端负载平衡器,并使用 eureka 作为注册表服务。 了解如何在负载均衡器下动态添加微服务的新实例。
1. 传统的服务器端负载均衡
服务器端负载平衡涉及单片应用程序,在这些应用程序中,负载平衡器后面的应用程序实例数量有限。 我们将 war / ear 文件部署到多个服务器实例中,这些实例基本上是已部署了相同应用程序的服务器池,并在其前面放置了负载均衡器。
负载平衡器具有公共 IP 和 DNS。 客户端使用该公共 IP / DNS 发出请求。 负载平衡器决定将内部应用程序服务器请求转发到哪个请求。 它主要使用轮询或粘性会话算法。 我们称其为服务器端负载平衡。
1.1. 微服务架构中的问题
通常,服务器端负载平衡是一项手动工作,我们需要手动将实例添加/删除到负载平衡器才能工作。 因此,理想情况下,我们要失去当今随需应变的可伸缩性,以自动发现和配置何时分拆任何新实例。
另一个问题是制定故障转移策略以为客户提供无缝的体验。 最后,我们需要一个单独的服务器来承载负载均衡器实例,这会对成本和维护产生影响。
2. 客户端负载平衡
为了克服传统负载平衡的问题,客户端负载平衡成为了现实。 它们作为内置组件驻留在应用程序中,并与应用程序捆绑在一起,因此我们不必将它们部署在单独的服务器中。
现在,让我们可视化全局。 在微服务架构中,我们将不得不开发许多微服务,并且每个微服务在生态系统中可能具有多个实例。 为了克服这种复杂性,我们已经有了使用服务发现模式的流行解决方案。 在 SpringBoot 应用程序中,我们在服务发现空间中提供了两个选项,例如 Eureka,Consul,动物园管理员等。
现在,如果一个微服务想要与另一个微服务进行通信,则通常会使用发现客户端来查找服务注册表,并且 Eureka 服务器会将该目标微服务的所有实例返回给调用者服务。 然后,调用者服务负责选择要发送请求的实例。
在这里,客户端负载平衡成为现实,它会自动处理这种情况下的复杂性,并以负载平衡的方式委派给适当的实例。 注意,我们可以指定要使用的负载平衡算法。
3. Netflix Ribbon – 客户端负载平衡器
Spring Cloud 系列的 Netflix Ribbon 提供了这种功能来设置客户端负载平衡以及服务注册表组件。 Spring Boot 具有非常好的配置 Ribbon 客户端负载平衡器的简便方法。 它提供以下功能
- 负载均衡
- 容错能力
- 异步和响应模型中的多种协议(HTTP,TCP,UDP)支持
- 缓存和批处理
要获取 Ribbon 二进制文件,请转到 maven 中心。 这是在 Maven 中添加依赖项的示例:
pom.xml
<dependency>
<groupId>com.netflix.ribbon</groupId>
<artifactId>ribbon</artifactId>
<version>2.2.2</version>
</dependency>
4. Netflix Ribbon 示例
4.1. 技术栈
- Java,Eclipse,Maven 作为开发环境
- Spring-boot 和 Cloud 作为应用程序框架
- Eureka 即服务注册表服务器
- Ribbon 作为客户端负载均衡器
我们将创建以下组件,并查看整个生态系统如何在分布式环境中进行协调。
- 使用 Spring 运行的两个微服务。 一个需要根据业务需求调用另一个
- Eureka 服务注册服务器
- 调用微服务中的 Ribbon 通过服务发现以负载平衡的方式调用其他服务
- 以负载平衡的方式调用服务,而无需发现服务
4.2. 创建后端微服务
我们将使用 Spring boot 创建一个简单的微服务,并将公开简单的 REST 端点。 使用spring-boot-web
和服务发现客户端依赖关系创建一个名为ribbon-server
的简单 Spring Boot 项目,以将其托管在 Web 服务器中,并公开一个 Rest 控制器进行测试。
为此,我们需要转到 https://start.spring.io/ 并提供 Maven 坐标并选择依赖项。 下载包含框架项目的 zip 文件。 然后,一旦解压缩到合适的文件夹中,我们就需要将其导入 eclipse 中。
从 Spring Initializer 生成的项目
4.2.1. 创建 REST 端点
编写一个 Rest 控制器,并如下所示公开一个 Rest 端点。
MyRestController.java
package com.example.ribbonserver;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class MyRestController {
@Autowired
Environment environment;
@GetMapping("/")
public String health() {
return "I am Ok";
}
@GetMapping("/backend")
public String backend() {
System.out.println("Inside MyRestController::backend...");
String serverPort = environment.getProperty("local.server.port");
System.out.println("Port : " + serverPort);
return "Hello form Backend!!! " + " Host : localhost " + " :: Port : " + serverPort;
}
}
4.2.2 启用发现客户端
注册此服务到 eureka,我们需要在应用程序类中添加@EnableDiscoveryClient
。 另外,我们需要在应用程序属性文件中添加以下条目。
RibbonServerApplication.java
package com.example.ribbonserver;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class RibbonServerApplication {
public static void main(String[] args) {
SpringApplication.run(RibbonServerApplication.class, args);
}
}
application.properties
spring.application.name=server
server.port = 9090
eureka.client.serviceUrl.defaultZone= http://${registry.host:localhost}:${registry.port:8761}/eureka/
eureka.client.healthcheck.enabled= true
eureka.instance.leaseRenewalIntervalInSeconds= 1
eureka.instance.leaseExpirationDurationInSeconds= 2
4.3. Eureka 服务注册表服务器
创建服务发现服务器。 这也很容易。 只是我们需要使用 Eureka 服务器作为依赖项来创建上述的 spring boot 项目,并执行以下配置。
4.3.1. Eureka 服务器配置
准备好 Spring Boot 服务并将其导入 Eclipse 后,在 Spring Boot 应用程序类中添加@EnableEurekaServer
注解,并在应用程序属性文件中添加以下配置。
RibbonEurekaServerApplication.java
package com.example.ribboneurekaserver;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer
public class RibbonEurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(RibbonEurekaServerApplication.class, args);
}
}
application.properties
spring.application.name= ${springboot.app.name:eureka-serviceregistry}
server.port = ${server-port:8761}
eureka.instance.hostname= ${springboot.app.name:eureka-serviceregistry}
eureka.client.registerWithEureka= false
eureka.client.fetchRegistry= false
eureka.client.serviceUrl.defaultZone: http://${registry.host:localhost}:${server.port}/eureka/
4.4. 创建另一个微服务
遵循上一节的内容,创建另一个名为ribbon-client
的服务,并增加了权限spring-cloud-starter-netflix-ribbon
。 下载后,将项目导入 eclipse 中并执行以下配置。
4.4.1. 碳带配置
在应用程序类中,添加两个注解@RibbonClient
和@EnableDiscoveryClient
,以启用 Ribbon 和 Eureka 客户端进行服务注册。
RibbonClientApplication.java
package com.example.ribbonclient;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.ribbon.RibbonClient;
@EnableDiscoveryClient
@SpringBootApplication
@RibbonClient(name = "server", configuration = RibbonConfiguration.class)
public class RibbonClientApplication {
public static void main(String[] args) {
SpringApplication.run(RibbonClientApplication.class, args);
}
}
在application.properties
中,我们需要进行以下配置。 在这里server.ribbon.listOfServers
被禁用,我们可以启用它以手动将服务器添加到此负载均衡器。 我们将在“测试”部分中对此进行检查。 其他属性不言自明。
application.properties
spring.application.name=client
server.port=8888
eureka.client.serviceUrl.defaultZone= http://${registry.host:localhost}:${registry.port:8761}/eureka/
eureka.client.healthcheck.enabled= true
eureka.instance.leaseRenewalIntervalInSeconds= 1
eureka.instance.leaseExpirationDurationInSeconds= 2
server.ribbon.eureka.enabled=true
#server.ribbon.listOfServers=localhost:9090,localhost:9091,localhost:9092
server.ribbon.ServerListRefreshInterval=1000
#logging.level.root=TRACE
现在,我们需要为 Ribbon 创建另一个配置类,以提及负载平衡算法和运行状况检查。 现在,我们将使用 Ribbon 所提供的默认值,但是在此类中,我们可以很好地覆盖它们并添加我们的自定义逻辑。
RibbonConfiguration.java
package com.example.ribbonclient;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AvailabilityFilteringRule;
import com.netflix.loadbalancer.IPing;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.PingUrl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
public class RibbonConfiguration {
@Autowired
IClientConfig config;
@Bean
public IPing ribbonPing(IClientConfig config) {
return new PingUrl();
}
@Bean
public IRule ribbonRule(IClientConfig config) {
return new AvailabilityFilteringRule();
}
}
5. 测试应用程序
5.1. 启动组件
执行最终的构建使用命令mvn clean install
,并检查构建是否成功。 如果有任何错误,则需要进行修复。 一旦成功完成所有 Maven 项目的构建,我们将一个接一个地启动服务。
首先是 Eureka,然后是后端微服务,最后是前端微服务。
要启动每个微服务,我们将使用'java -jar -Dserver.port=XXXX target/YYYYY.jar'
命令。
5.2. 部署后端微服务的多个实例
为此,我们需要为此使用不同的端口,以在特定端口中启动服务,我们需要以这种方式传递该端口。
java -jar -Dserver.port=XXXX target/YYYYY.jar
。 我们将在端口 9090、9091 和 9092 端口中创建此服务的 3 个实例。
5.3. 验证 Eureka 服务器
现在,在浏览器中转到http://localhost:8761/
,并检查 eureka 服务器正在运行,并且所有微服务都已注册了所需数量的实例。
5.4. 检查客户端负载平衡是否正常
在前端微服务中,我们使用RestTemplate
调用后端微服务。 使用@LoadBalanced
注解,将剩余温度作为客户端负载平衡器启用。
现在转到浏览器,打开客户端微服务 REST 端点http://localhost:8888/client/frontend
,看看响应来自任何后端实例。
要了解此后端服务器正在返回其运行端口,我们也在客户端微服务响应中也显示了该端口。 尝试刷新此 URL 几次,然后注意到后端服务器的端口不断变化,这意味着客户端负载平衡正在工作。 现在尝试添加更多后端服务器实例,并检查是否也在 eureka 服务器中注册并最终在 Ribbon 中考虑,因为一旦将在 eureka 中注册,Ribbon 也会自动将请求发送到新实例。
5.5. 使用硬编码后端进行测试,而无需发现服务
转到前端微服务application.properties
文件并启用它。
application.properties
server.ribbon.listOfServers=localhost:9090,localhost:9091,localhost:9092
server.ribbon.eureka.enabled=false
现在测试客户端网址。 您将仅从注册的实例获得响应。 现在,如果您在其他端口中启动后端微服务的新实例,Ribbon 将不会向新实例发送请求,除非我们在 Ribbon 中手动注册。
如果您在测试时遇到困难,我也建议您从所有应用程序中删除所有与 eureka 相关的配置,并停止 eureka 服务器。 希望您也不会在测试中遇到任何困难。
6. 总结
因此,我们已经看到了在 SpringBoot 微服务开发中可以轻松地将 Ribbon 和 Eureka 一起使用。 因此,下次如果您需要这种要求,则可以使用这种方法。 如果您对此有任何疑问,请在下面评论。
学习愉快!
参考文献: