ribbon作为客户端均衡器,在使用http调用服务端集群时,使用一定的策略帮助客户端选择一个服务端实例,进行真正的调用,达到客户端负载均衡的目的。

使用示例1:

maven中添加合适版本的依赖

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

添加Controller接口

@Autowired
private LoadBalancerClient loadBalancerClient;

@GetMapping("/allOrders/1")
public Object getOrders1() {
    // order-service表示服务端服务名,选择一个服务
    ServiceInstance serviceInstance = loadBalancerClient.choose("order-service");
    // 根据选择出来的服务实例调用
    String url = String.format("http://%s:%s/orders", serviceInstance.getHost(), serviceInstance.getPort());
    return restTemplate.getForObject(url, String.class);
}

在配置文件中配置order-service服务端所有实例

order-service.ribbon.listOfServers=\
  localhost:8001,\
  localhost:8002

服务端order-service提供/orders接口实现

@Value("${server.port}")
private int port;
@Value("${spring.application.name}")
private String appName;

@GetMapping("/orders")
public Object getAllOrders() {
    String result = "all orders list from : " + appName + ":" + port;
    System.out.println(result);
    return result;
}

调用客户端接口http://localhost:8888/allOrders/1可得到调用了不同服务端的结果。
image.png
image.png

使用示例2:

通过注解的方式实现,在示例1的配置基础上只需要稍微改动代码

// 带负载均衡拦截器的RestTemplate
@LoadBalanced
@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
    return builder.build();
}

@Autowired
private RestTemplate restTemplate;

@GetMapping("/allOrders/2")
public Object getOrders() {
    // 自动负载均衡
    return restTemplate.getForObject("http://order-service/orders", String.class);
}

同样,在配置文件中配置order-service服务端所有实例

order-service.ribbon.listOfServers=\
  localhost:8001,\
  localhost:8002

ribbon忽略https配置

@Configuration
public class RibbonClientSpecificationConfig {
    // 该bean会被注入到org.springframework.cloud.netflix.ribbon.RibbonAutoConfiguration#configurations字段
    // 使用时被加载
    @Bean
    public RibbonClientSpecification ribbonClientSpecification() {
        RibbonClientSpecification ribbonClientSpecification = new RibbonClientSpecification();
        ribbonClientSpecification.setConfiguration(new Class[]{RibbonConfig.class});
        ribbonClientSpecification.setName("default."+RibbonConfig.class.getName());
        return ribbonClientSpecification;
    }

}
// 使用ribbon是才会加载
public class RibbonConfig {
    private OkHttpClient httpClient;
    @Bean
    public OkHttpClient client(OkHttpClientFactory httpClientFactory,
                               ConnectionPool connectionPool, IClientConfig config) {
        RibbonProperties ribbon = RibbonProperties.from(config);
        // 忽略https验证逻辑
        this.httpClient = httpClientFactory.createBuilder(true)
            .connectTimeout(ribbon.connectTimeout(), TimeUnit.MILLISECONDS)
            .readTimeout(ribbon.readTimeout(), TimeUnit.MILLISECONDS)
            .followRedirects(ribbon.isFollowRedirects())
            .connectionPool(connectionPool)
            .build();
        return this.httpClient;
    }

    @PreDestroy
    public void destroy() {
        if (httpClient != null) {
            httpClient.dispatcher().executorService().shutdown();
            httpClient.connectionPool().evictAll();
        }
    }
}

具体https相关参见