Spring Cloud 微服务(11) --- Ribbon(一)
负载均衡与 Ribbon

通常所说的负载均衡,一般来说都是在服务器端使用 Ngnix 或 F5 做 Server 的负载均衡策略,在 Ribbon 中提到的负载均衡,一般来说是指的客户端负载均衡,即 ServiceA 调用 ServiceB,有多个 ServiceB 的情况下,由 ServiceA 选择调用哪个 ServiceB。

负载均衡与 Ribbon

负载均衡(Load Balance),是一种利用特定方式,将流量分摊到多个操作单元上的手段,它对系统吞吐量、系统处理能力有着质的提升。最常见的负载均衡分类方式有:软负载、硬负载,对应 Ngnix、F5;集中式负载均衡、进程内负载均衡。集中式负载均衡是指位于网络和服务提供者之间,并负责把忘了请求转发到各个提供单位,代表产品有 Ngnix、F5;进程负载均衡是指从一个实例库选取一个实例进行流量导入,在微服务范畴,实例库一般是存储在 Eureka、Consul、Zookeeper 等注册中心,此时的负载均衡器类似 Ribbon 的 IPC(进程间通信)组件,因此进程内负载均衡也叫做客户端负载均衡。

Ribbon 是一个客户端负载均衡器,赋予了应用一些支配 HTTP 与 TCP 行为的能力,由此可以得知,这里的客户端负载均衡也是进程内负载均衡的一周。 Ribbon 在 SpringCloud 生态内的不可缺少的组件,没有了 Ribbon,服务就不能横向扩展。Feign、Zuul 已经集成了 Ribbon。


示例

Eureka Server 不再赘述,可以直接使用 spring-cloud-eureka-server-simple

Consumer

源码:https://gitee.com/laiyy0728/spring-cloud/tree/master/spring-cloud-ribbon/spring-cloud-ribbon-consumer

yml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
spring:
application:
name: spring-cloud-ribbon-consumer

server:
port: 9999

eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka
instance:
prefer-ip-address: true
instance-id: ${spring.application.name}:${server.port}

配置类:

1
2
3
4
5
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}

@LoadBalanced:对 RestTemplate 启动负载均衡

Consumer Controller

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@RestController
public class ConsumerController {

private final RestTemplate restTemplate;

@Autowired
public ConsumerController(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}

@GetMapping(value = "/check")
public String checkRibbonProvider(){
return restTemplate.getForObject("http://spring-cloud-ribbon-provider/check", String.class);
}

}

provider

源码:https://gitee.com/laiyy0728/spring-cloud/tree/master/spring-cloud-ribbon/spring-cloud-ribbon-provider

pom 依赖:

1
2
3
4
5
6
7
8
9
10
11
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
</dependencies>

配置文件:

1
2
3
4
5
6
7
8
9
10
11
spring:
application:
name: spring-cloud-ribbon-provider

eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka
instance:
prefer-ip-address: true
instance-id: ${spring.application.name}:${server.port}

ProviderContr

1
2
3
4
5
6
7
8
9
10
11
@RestController
public class ProviderController {

@Value("${server.port}")
private int port;

@GetMapping(value = "/check")
public String providerPort(){
return "Provider Port: " + port;
}
}

验证

分别启动 Eureka Server、Consumer、Provider,其中,Provider 以 mvn 形式启动,绑定不同的端口号:

1
2
mvn spring-boot:run -Dserver.port=8080
mvn spring-boot:run -Dserver.port=8081

postman 访问 Consumer
第一次请求
第二次请求

可以看到,Provider 两次返回值不一样,验证了负载均衡成功。


负载均衡策略

Ribbon 中提供了 七种 负载均衡策略

策略类命名描述
RandomRule随机策略随机选择 Server
RoundRobinRule轮询策略按照顺序循环选择 Server
RetryRule重试策略在一个配置时间段内,当选择的 Server 不成功,则一直尝试选择一个可用的 Server
BestAvailableRule最低并发策略逐个考察 Server,如果 Server 的断路器被打开,则忽略,在不被忽略的 Server 中选择并发连接最低的 Server
AvailabilityFilteringRule可用过滤测试过滤掉一直连接失败,并被标记未 circuit tripped(即不可用) 的 Server,过滤掉高并发的 Server
ResponseTimeWeightedRule响应时间加权策略根据 Server 的响应时间分配权重,响应时间越长,权重越低,被选择到的几率就越低
ZoneAvoidanceRule区域权衡策略综合判断 Server 所在区域的性能和 Server 的可用性轮询选择 Server,并判定一个 AWS Zone 的运行性能是否可用,剔除不可用的 Zone 中的所有 Server

Ribbon 默认的负载均衡策略是 轮询策略

设置负载均衡策略

设置全局负载均衡

创建一个声明式配置,即可实现全局负载均衡配置:

1
2
3
4
5
6
7
8
9
10
11
@Configuration
public class RibbonConfig {
/**
* 全局负载均衡配置:随机策略
*/
@Bean
public IRule ribbonRule(){
return new RandomRule();
}

}

重启 Consumer,访问测试

基于注解的配置

空注解

声明一个空注解,用于使用注解配置 Ribbon 负载均衡

1
2
public @interface RibbonAnnotation {
}

负载均衡配置类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Configuration
@RibbonAnnotation
public class RibbonAnnoConfig {

private final IClientConfig clientConfig;

@Autowired(required = false)
public RibbonAnnoConfig(IClientConfig clientConfig) {
this.clientConfig = clientConfig;
}

@Bean
public IRule ribbonRule(IClientConfig clientConfig){
return new RandomRule();
}
}

启动类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@SpringBootApplication
@EnableDiscoveryClient

@RibbonClient(name = "spring-cloud-ribbon-provider", configuration = RibbonAnnoConfig.class)
@ComponentScan(excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, value = RibbonAnnotation.class)})
public class SpringCloudRibbonConsumerApplication {

public static void main(String[] args) {
SpringApplication.run(SpringCloudRibbonConsumerApplication.class, args);
}

@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}

}

@RibbonClient:针对 spring-cloud-ribbon-provider 服务,使用负载均衡,配置类是 configuration 标注的类。
@ComponentScan:让 Spring 不去扫描被 @RibbonAnnotation 类标记的配置类,因为我们的配置对单个服务生效,不能应用于全局,如果不排除,启动就会报错

如果需要对多个服务进行配置,可以使用 @RibbonClients 注解

1
2
3
@RibbonClients(value = {
@RibbonClient(name = "spring-cloud-ribbon-provider", configuration = RibbonAnnoConfig.class)
})

重启 Consumer,验证基于注解的负载均衡是否成功

基于配置文件的负载均衡策略

语法:

1
2
3
{instance-id}: # instance-id 即被调用服务名称
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule


Ribbon 配置

源码:https://gitee.com/laiyy0728/spring-cloud/tree/master/spring-cloud-ribbon/spring-cloud-ribbon-config

超时与重试

HTTP 请求难免会出现请求超时,此时对调用进行时限的控制以及在时限之后的重试尤为重要。对于超时重试的配置如下:

1
2
3
4
5
6
7
{instance-id}: # instance-id 指的是被调用者的服务名称
ribbon:
ConnectTimeout: 30000 # 链接超时时间
ReadTimeout: 30000 # 读超时时间
MaxAutoRetries: 1 # 对第一次请求的服务的重试次数
MaxAutoRetriesNextServer: 1 # 要重试的下一个服务的最大数量(不包括第一个服务)
OkToRetryOnAllOperations: true # 是否对 连接超时、读超时、写超时 都进行重试

Ribbon 饥饿加载

Ribbon 在进行负载均衡时,并不是启动时就加载上线文,而是在实际的请求发送时,才去请求上下文信息,获取被调用者的 ip、端口,这种方式在网络环境较差时,往往会使得第一次引起超时,导致调用失败。此时需要指定 Ribbon 客户端,进行饥饿加载,即:在启动时就加载好上下文。

1
2
3
4
ribbon:
eager-load:
enabled: true
clients: spring-cloid-ribbon-provider

此时启动 consumer,会看到控制打印信息如下:

1
2
3
Client: spring-cloid-ribbon-provider instantiated a LoadBalancer: DynamicServerListLoadBalancer:{NFLoadBalancer:name=spring-cloid-ribbon-provider,current list of Servers=[],Load balancer stats=Zone stats: {},Server stats: []}ServerList:null
Using serverListUpdater PollingServerListUpdater
DynamicServerListLoadBalancer for client spring-cloid-ribbon-provider initialized: DynamicServerListLoadBalancer:{NFLoadBalancer:name=spring-cloid-ribbon-provider,current list of Servers=[],Load balancer stats=Zone stats: {},Server stats: []}ServerList:org.springframework.cloud.netflix.ribbon.eureka.DomainExtractingServerList@79e7188e

可以看到启动时就加载了 spring-cloid-ribbon-provider,并绑定了LoadBalancer

Ribbon 常用配置

配置项说明
{instance-id}:ribbon.NFLoadBalancerClassName指负载均衡器类路径
{instance-id}:ribbon:NFLoadBalancerRuleClassName指定负载均衡算法类路径
{instance-id}:ribbom:NFLoadBalancerPingClassName指定检测服务存活的类路径
{instance-id}:ribbon:NIWSServerListClassName指定获取服务列表的实现类路径
{instance-id}:ribbon:NIWSServerListFilterClassName指定服务的 Filter 实现类路径

Ribbon 脱离 Eureka

默认情况下,Ribbon 客户端会从 Eureka Server 读取服务注册信息列表,达到动态负载均衡的功能。如果 Eureka 是一个提供多人使用的公共注册中心(如 SpringCloud 中文社区公益 Eureka:http://eureka.springcloud.cn),此时极易产生服务侵入问题,此时就不能从 Eureka 中读取服务列表,而应该在 Ribbon 客户端自行制定源服务地址

1
2
3
4
5
6
7
ribbon:
eureka:
enabled: false # Ribbon 脱离 Eureka 使用

{instance-id}:
ribbon:
listOfServers: http://localhost:8888 # 制定源服务地址

-------------本文结束 感谢您的阅读-------------
0%