一、负载均衡理论介绍
现阶段后台的 负载均衡 主要分为两种:
- 客户端负载均衡
- 服务端负载均衡
(一)客户端负载均衡
优势:稳定性高。
不足:升级成本高。
(二)服务端负载均衡
优势:统一维护,成本低。
不足:一旦故障,影响大。
二、Spring Cloud 整合 Ribbon
注意:这里的 Ribbon 就是典型的客户端负载均衡!!
1、添加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
2、激活 Ribbon 客户端,并配置 RestTemplate,触发负载均衡
/**
* 注解 @RibbonClient: 激活单个 RibbonClient,name 必填,为服务提供方的 ${spring.application.name}
* 注解 @RibbonClients: 激活多个 RibbonClient
*/
({
(name = "spring-cloud-service-provider")
})
public class RibbonClientApplication {
public static void main(String[] args) {
SpringApplication.run(RibbonClientApplication.class, args);
}
/**
* 申明一个RestTemplate
* 注解 @LoadBalanced:触发负载均衡
*/
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
3、配置Ribbon客户端
application.properties
# 应用名
spring.application.name=spring-cloud-ribbon-client
#端口
server.port=8080
#暂时关闭 Eureka 注册(整合 Eureka 时,需要删除这项配置)
eureka.client.enabled=false
management.endpoints.web.exposure.include=*
management.endpoint.health.show-details=always
#服务提供方主机(整合 Eureka 时,需要删除这项配置)
service-provider.host=localhost
#服务提供方端口(整合 Eureka 时,需要删除这项配置)
service-provider.port=9090
#服务提供方应用名
service-provider.name=spring-cloud-service-provider
#配置 ribbon 服务提供方(整合 Eureka 时,需要删除这项配置)
#模式:${serviceId}.ribbon.listOfServers=${serviceUrl},${serviceUrl2},....
spring-cloud-service-provider.ribbon.listOfServers=http://${service-provider.host}:${service-provider.port}
4、验证
@RestController
public class RibbonClientController {
@Value("${service-provider.name}")
private String serviceProviderName;
/**
* 在启动类中申明了该Bean
*/
private RestTemplate restTemplate;
@Autowired
public RibbonClientController(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
@GetMapping("/index")
public String index(){
User user = new User();
user.setId(1L);
user.setName("jack");
/**
* 参数一:URI(serviceProviderName 可以替代 host:port)
* 参数二:请求对象
* 参数三:返回值类型
*/
return restTemplate.postForObject("http://"+ serviceProviderName +"/greeting",
user, String.class);
}
}
注意:以上是 Ribbon 客户端(“spring-cloud-ribbon-client”)直接与 服务提供方(“service-provider”)直接相连。这样带来一个问题就是,客户端与服务端耦合严重,一旦服务端发生变动,那么客户端得改变一大堆的配置。解决办法就是,引入 Eureka 注册中心,客户端和服务端都作为 Eureka 客户端注册到注册中心,客户端通过ServiceId(${spring.application.name})来寻找服务端。也就是我们的第三步:Ribbon 整合 Eureka!
三、Ribbon 整合 Eureka
1、创建并启动 Eureka Server
(1)激活 Eureka 服务端
@EnableEurekaServer
(2)配置 Eureka 服务器
application.properties
#Eureka Server 单机版的服务发现
#应用名
spring.application.name=spring-cloud-eureka-server
#服务端口
server.port=7070
#开启 actuator 端口
management.endpoints.web.exposure.include=*
management.endpoint.health.show-details=always
#不向其他 Eureka 服务器注册(单机版才这么配)
eureka.client.register-with-eureka=false
#不从其他 Eureka 服务器拉取信息(单机版才这么配)
eureka.client.fetch-registry=false
(3)启动 Eureka Server
2、整合 Ribbon 客户端 与 Eureka Server
(1)激活服务发现客户端
在上面,我们在“application.properties”中关闭了 Eureka 注册,在这里,需要这项配置删除。
@EnableDiscoveryClient
(2)配置 Ribbon 客户端,连接 Eureka Server
application.properties
# 应用名
spring.application.name=spring-cloud-ribbon-client
#端口
server.port=8080
management.endpoints.web.exposure.include=*
management.endpoint.health.show-details=always
#连接 Eureka Server
eureka.client.service-url.defaultZone=http://localhost:7070/eureka/
#服务提供方应用名(同时也是 Eureka 服务器中的 ServiceId)
service-provider.name=spring-cloud-service-provider
3、整合 服务提供方 与 Eureka Server
(1)激活服务发现客户端
在上面,我们在“application.properties”中关闭了 Eureka 注册,在这里,需要这项配置删除。
@EnableDiscoveryClient
(2)配置 服务提供方,连接 Eureka Server
application.properties
#服务提供方 应用名
spring.application.name=spring-cloud-service-provider
#端口
server.port=9090
management.endpoints.web.exposure.include=*
management.endpoint.health.show-details=always
#连接 Eureka Server
eureka.client.service-url.defaultZone=http://localhost:7070/eureka/
4、启动多个 服务提供方 实例
通过调整JVM启动参数 --server.port=9091
和 --server.port=9092
,启动多个实例。
5、检测
经测试,Ribbon 客户端依然可以访问到 服务提供方 提供的服务,并且实现了负载均衡。这里依然正常运行的关键在于这里,serviceProviderName
。Ribbon 客户端在 Eureka 服务器 通过该ServiceId
(也就是serviceProviderName),找到该 服务提供方,并转换成host:port
方式来访问服务:
application.properties
:
service-provider.name=spring-cloud-service-provider
@RestController
public class RibbonClientController {
@Value("${service-provider.name}")
private String serviceProviderName;
/**
* 在启动类中申明了该Bean
*/
private RestTemplate restTemplate;
@Autowired
public RibbonClientController(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
@GetMapping("/index")
public String index(){
User user = new User();
user.setId(1L);
user.setName("jack");
/**
* 参数一:URI(serviceProviderName 可以替代 host:port)
* 参数二:请求对象
* 参数三:返回值类型
*/
return restTemplate.postForObject("http://"+ serviceProviderName +"/greeting",
user, String.class);
}
}
四、总结
经过以上整合,Spring Cloud 整合 Eureka,Ribbon的数据模型: