四、使用Ribbon实现客户端侧负载均衡

Ribbon简介

Ribbon是Netflix发布的负载均衡器,它有助于控制HTTP和TCP客户端的行为。为Ribbon配置服务提供者地址列表后,Ribbon就可基于某种负载均衡算法,自动地帮助服务消费者去请求。Ribbon默认为我们提供了很多地负载均衡算法,例如轮询、随机等。当然,我们也可为Ribbon实现自定义地负载均衡算法。
在Spring Cloud中,当Ribbon与Eureka配置使用时,Ribbon可自动从Eureka Server 获取服务提供者地址列表,并基于负载均衡算法,请求其中一个服务提供者实例。如图展示了Ribbon 与 Eureka 配合使用时地大致架构。

为服务消费者整合Ribbon

引入依赖包

1
2
3
4
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>

如果添加了spring-cloud-starter-netflix-eureka-client,该依赖已包含spring-cloud-starter-netflix-ribbon,无须再次引入。

Ribbon自定义配置

使用 Java 代码自定义Ribbon配置

  • Spring Cloud 中,Ribbon的默认配置格式(BeanType beanName: ClassName):
    1. IClientConfig ribbonClientConfig: DefaultClientConfigImpl (Ribbon 的客户端配置,默认采用com.netflix.client.config.DefaultClientConfigImpl 实现)
    2. IRule ribbonRule: ZoneAvoidanceRule (Ribbon 的负载均衡策略, 默认采用com.netflix.loadbalancer.ZoneAvoidanceRule实现,该策略能够在多区域环境下选择最佳区域的实例进行访问)
    3. IPing ribbonPing: DummyPing ( Ribbon 的实例检查策略,默认采用com.netflix.loadbalancer.DummyPing实现,该检查策略是一个特殊的实现,实际上他并不会检查实例是否可用,而是始终返回 true ,默认认为所有服务实例都是可以使用)
    4. ServerList ribbonServerList: ConfigurationBasedServerList ( 服务实例清单的维护机制)
    5. ServerListFilter ribbonServerListFilter: ZonePreferenceServerListFilter ( 服务实例清单过滤机制)
    6. ILoadBalancer ribbonLoadBalancer: ZoneAwareLoadBalancer ( 负载均衡器)
    7. ServerListUpdater ribbonServerListUpdater: PollingServerListUpdater (动态更新服务列表策略)

创建Ribbon配置类

1
2
3
4
5
6
7
8
9
10
11
12
/**
* 该类为Ribbon的配置类
* 注意:该类不应该在主应用程序上下文的@ComponentScan 中。
*/
@Configuration
public class RibbonConfiguration {
@Bean
public IRule ribbonRule() {
// 负载均衡规则,改为随机
return new RandomRule();
}
}

创建一个空类,并在其上添加@Configuration注解和@RibbonClient注解

1
2
3
4
5
6
7
8
9
10
11
/**
* 使用RibbonClient,为特定name的Ribbon Client自定义配置.
* 使用@RibbonClient的configuration属性,指定Ribbon的配置类.
* 可参考的示例:
* http://spring.io/guides/gs/client-side-load-balancing/
* @author 周立
*/
@Configuration
@RibbonClient(name = "microservice-provider-user", configuration = RibbonConfiguration.class)
public class TestConfiguration {
}

必须注意的是,本例中的RibbonConfiguration类不能存放在主应用程序上下文的@ComponentScan 所扫描的包中,否则该类中的配置信息将被所有的@RibbonClient共享。

全局配置:可使用@RibbonClients 注解为所有的Ribbon Client提供默认配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@RibbonClients(defaultConfiguration = DefaultRibbonConfig.class)
public class RibbonClientDefaultConfigurationTestsConfig {
public static class BazServiceList extends ConfigurationBasedServerList {
public BazServiceList(IClientConfig config) {
super.initWithNiwsConfig(config);
}
}
}
@Configuration
class DefaultRibbonConfig {
@Bean
public IRule ribbonRule() {
return new BestAvailableRule();
}
@Bean
public IPing ribbonPing() {
return new PingUrl();
}
@Bean
public ServerList<Server> ribbonServerList(IClientConfig config) {
return new RibbonClientDefaultConfigurationTestsConfig.BazServiceList(config);
}
@Bean
public ServerListSubsetFilter serverListFilter() {
return new ServerListSubsetFilter();
}
}

使用属性自定义Ribbon 配置
从Spring Cloud Camden RELEASE 开始,Ribbon 支持使用属性自定义配置。
支持的属性如下,配置的前缀是.ribbon. 。其中, 是 RibbonClient 的名称,如果省略,则表示全局配置

  • NFLoadBalancerClassName : 配置ILoadBalancer 的实现类。
  • NFLoadBalancerRuleClassName : 配置IRule 的实现类。
  • NFLoadBalancerPingClassName : 配置IPing 的实现类。
  • NIWSServerListClassName : 配置ServerList 的实现类。
  • NIWSServerListFilterClassName : 配置ServerListFilter 的实现类。

示例:

1
2
3
microservice-provider-user:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

脱离Eureka 使用Ribbon

引入依赖

1
2
3
4
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>

配置文件application.yml 相关配置

1
2
3
4
5
6
7
8
server:
port: 8010
spring:
application:
name: microservice-consumer-movie
microservice-provider-user:
ribbon:
listOfServers: localhost:8000,localhost:8001

饥饿加载

Spring Cloud 会为每个名称的 Ribbon Client 维护一个子应用程序上下文,这个上下文默认是懒加载的。指定名称的 Ribbon Client 第一次请求时,对应的上下文才会被加载,因此,首次请求往往会比较慢。从Spring Cloud Dalston 开始,我们可配置饥饿加载。

1
2
3
4
ribbon:
eager-load:
enabled: true
clients: client1, client2

这样,对于名为client1、 client2的Ribbon Client,将在启动时就加载对应的子应用程序上下文,从而提高首次请求的访问速度。