一、Robbin 负载均衡
1.1 Robbin 介绍
在上面的示例中,如果注册了多个 user-service 服务,那么在客户端进行调用的时候如何来选择服务呢?这时就需要客户端来进行负载均衡。而在 SpringCloud 中,一般推荐使用Ribbon 来实现负载均衡。
Robbin 是 Netflix 发布的一个负载均衡器,在 SpringCloud 中,Eureka 一般都是和 Ribbon 一起使用。Eureka 负责服务的注册与发现,而 Ribbon 则提供了客户端负载均衡的功能。
加入 Robbin 负载均衡之后工程架构如下图所示:
1.2 开启负载均衡
1.2.1 启动多个 user-service 实例
启动两个 user-service 实例。分别使用端口:8080,8090。
启动完成之后,查看 Eureka 的监控界面如下所示:
1.2.2 开启负载均衡
1、Ribbon 依赖
在 consumer 项目中增加对 Ribbon 的依赖。
<!--增加对 Ribbon 的依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
但是在 eureka 中已经包含了对 Ribbon 的依赖,所以上面的依赖可以省略。
2、在 consumer 的 RestTemplate 配置方法上添加注解:@LoadBalanced
启动类:
@SpringBootApplication
@EnableDiscoveryClient
public class RibbonConsumerApplication {
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate(new OkHttp3ClientHttpRequestFactory());
}
public static void main(String[] args) {
SpringApplication.run(RibbonConsumerApplication.class, args);
}
}
3、修改 consumer 的服务调用方式。不在指定 ip 地址和端口号,而是根据服务名称来调用
服务。如下所示:
@GetMapping(value="/detail/{id}",produces= MediaType.APPLICATION_JSON_VALUE)
public User customer(@PathVariable("id")String id){
//使用服务名称调用
String serviceurl = "http://user-service/user/"+id;
return template.getForObject(serviceurl, User.class);
}
1.3 负载均衡策略
1.3.1 负载均衡策略介绍
在上面的示例中,使用 Robbin 来负责负载均衡问题,但是并没有去设置如何负载均衡的。那么默认情况下,将使用轮询的策略。
在 robbin 中,负责负载均衡的顶层接口为:com.netflix.loadbalancer.IRule。所有的负载均衡算法都是实现的这个接口。
1、默认负载均衡策略:
- com.netflix.loadbalancer.RoundRobinRule:以轮询的方式进行负载均衡。
2、常用负载均衡策略:
- com.netflix.loadbalancer.RandomRule:随机策略
- com.netflix.loadbalancer.RetryRule:重试策略。
- com.netflix.loadbalancer.WeightedResponseTimeRule:权重策略。会计算每个服务的权重,越高的被调用的可能性越大。
- com.netflix.loadbalancer.BestAvailableRule:最佳策略。遍历所有的服务实例,过滤掉故障实例,并返回请求数最小的实例返回。
- com.netflix.loadbalancer.AvailabilityFilteringRule:可用过滤策略。过滤掉故障和请求数超过阈值的服务实例,再从剩下的实力中轮询调用。
1.3.2 指定负载均衡策略
在 consumer 项目中增加如下配置(application.yml):
server:
port: 8082
spring:
application:
name: user-concumer
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:10114/eureka
instance:
ip-address: 127.0.0.1
prefer-ip-address: true
userservice: # 配置服务的负载均衡
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
1.3 重试机制
如果在系统运行过程中,服务如果挂掉一个,那么 Eureka 并不会马上将失效的服务剔除。那么 consumer 也不会马上获取到最新的服务列表,那么如果这个时候调用了失效的服务就会出现错误。然而这个时候还有正常的服务能够为其提供服务。
所以,springcloud 整合了 Spring Retry 来增强 RestTemplete 的重试能力。当一次服务调用失败后,不会立即抛出异常,而是再次重试另一个服务。具体操作如下:
1、在 consumer 中加入 Retry 的依赖
<!-- 重试依赖 -->
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
2、在 consumer 中加入如下配置
userservice:
ribbon:
# NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
ConnectTimeout: 250 # Ribbon 的连接超时时间
ReadTimeout: 1000 # Ribbon 的数据读取超时时间
OkToRetryOnAllOperations: true # 是否对所有操作都进行重试
MaxAutoRetriesNextServer: 1 # 切换实例的重试次数
MaxAutoRetries: 1 # 对当前实例的重试次数
logging:
level:
root: debug #方便查看调用日志