一、前言

上一篇《Spring Cloud 入门 之 Eureka 篇(一)》 介绍了微服务的搭建,服务注册与发现。但在文章中留了一个小尾巴--如何正确使用 Eureka 进行服务发现并调用服务。

本篇文章将介绍如何使用 Ribbon 完成发现服务的调用以及其负载均衡的规则的使用。

二、简单介绍

Spring Cloud Ribbon 是基于 Netflix Ribbon 实现的一套客户端负载均衡工具,其主要功能是提供客户端的软件负载均衡算法,将 Netflix 的中间层服务连接在一起。

其运行原理如下图:

Ribbon 运行时分成 2 个步骤:

  1. 1) 先选择在同一个区域负载较少的 EurekaServer;
  2. 2) 再根据用户指定的策略,在从 EurekaServer 中获取注册列表中的服务信息进行调用。

其中,Ribbon 提供多种负载均衡策略:如轮询、随机、响应时间加权等。

三、实战演练

我们在 order-server 项目的基础上进行修改。不清楚的读者请先转移至 《Spring Cloud 入门 之 Eureka 篇(一)》 进行浏览。

此外,笔者额外的创建 2 个 goods-server 项目,即现在有 3 个 goods-server 项目给 order-server 服务实现客户端的负载均衡调用。

现在的项目列表如下:

服务实例端口描述
common-api-公用的 api,如:实体类
eureka-server9000注册中心(Eureka 服务端)
goods-server8081商品服务(Eureka 客户端)
goods-server-028082商品服务(Eureka 客户端)
goods-server-038083商品服务(Eureka 客户端)
order-server8100订单服务(Eureka 客户端)

在 order-server 项目中:

  1. 添加依赖:
  1. <dependencies>
  2. <!-- common api -->
  3. <dependency>
  4. <groupId>com.extlight.springcloud</groupId>
  5. <artifactId>common-api</artifactId>
  6. <version>${parent-version}</version>
  7. </dependency>
  8. <!-- springmvc -->
  9. <dependency>
  10. <groupId>org.springframework.boot</groupId>
  11. <artifactId>spring-boot-starter-web</artifactId>
  12. </dependency>
  13. <!-- eureka 客户端 -->
  14. <dependency>
  15. <groupId>org.springframework.cloud</groupId>
  16. <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
  17. </dependency>
  18. <!-- ribbon -->
  19. <dependency>
  20. <groupId>org.springframework.cloud</groupId>
  21. <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
  22. </dependency>
  23. </dependencies>

添加加 ribbon 的依赖。

  1. 请求类添加 @LoadBalanced 注解:
  1. @Configuration
  2. public class RestConfiguration {
  3. @Bean
  4. @LoadBalanced
  5. public RestTemplate getRestTemplate() {
  6. return new RestTemplate();
  7. }
  8. }

正如上文介绍的,Ribbon 是客户端负载均衡工具,所以在 getRestTemplate 方法上添加 @LoadBalanced 注解实现负载均衡。

  1. 修改请求地址:
  1. @Service
  2. public class OrderServiceImpl implements OrderService{
  3. @Autowired
  4. private RestTemplate restTemplate;
  5. // @Autowired
  6. // private DiscoveryClient client;
  7. @Override
  8. public void placeOrder(Order order) throws Exception{
  9. // 获取商品服务地址列表
  10. // List<ServiceInstance> list = this.client.getInstances("GOODS");
  11. // String uri = "";
  12. // for (ServiceInstance instance : list) {
  13. // if (instance.getUri() != null && !"".equals(instance.getUri())) {
  14. // uri = instance.getUri().toString();
  15. // break;
  16. // }
  17. // }
  18. //
  19. // Result result = restTemplate.getForObject(new URI(uri + "/goods/goodsInfo/" + order.getGoodsId()), Result.class);
  20. Result result = this.restTemplate.getForObject("http://GOODS/goods/goodsInfo/" + order.getGoodsId(), Result.class);
  21. if (result != null && result.getCode() == 200) {
  22. System.out.println("=====下订单====");
  23. System.out.println(result.getData());
  24. }
  25. }
  26. }

修改 DiscoveryClient 相关代码,使用 GOODS 作为请求商品服务的请求 URL。

完成上边 3 个操作后,启动 3 台 goods-server 服务 和 order-server 服务,通过 Postman 进行测试,运行结果如下:

上图中,通过 6 次请求返回的商品的端口信息可知,Ribbon 默认使用负载均衡的策略是轮询,对服务进行调用。

四、负载均衡策略

# 4.1 策略规则

Ribbon 提供 IRule 接口,该接口定义了如何访问服务的方法,以下是该接口的实现类:

  1. 1) RoundRobinRule:轮询,默认使用的规则;
  2. 2) RandomRule:随机;
  3. 3) AvailabilityFilteringRule:先过滤由于多次访问故障而处于断路器跳闸状态以及并发连接数量超过阀值得服务,然后从剩余服务列表中按照轮询策略进行访问;
  4. 4) WeightedResponseTimeRule:根据平均响应时间计算所有的权重,响应时间越快服务权重越有可能被选中;
  5. 5) RetryRule:先按照 RoundRobinRule 策略获取服务,如果获取服务失败则在指定时间内进行重试,获取可用服务;
  6. 6) BestAvailableRule:先过滤由于多次访问故障而处于断路器跳闸状态的服务,然后选择并发量最小的服务;
  7. 7) ZoneAvoidanceRule:判断 server 所在区域的性能和 server 的可用性来选择服务器。

# 4.2 策略使用

在 order-server 项目中:

  1. @Configuration
  2. public class RestConfiguration {
  3. @Bean
  4. @LoadBalanced
  5. public RestTemplate getRestTemplate() {
  6. return new RestTemplate();
  7. }
  8. @Bean
  9. public IRule testRule() {
  10. return new RandomRule();
  11. }
  12. }

手动创建负载均衡规则对象,本次测试使用的策略是随机。

启动 order-server 项目后再次使用 Postman 测试,运行结果如下:

由图可知,随机策略已生效,负载均衡的策略由轮询变成了随机。

五、案例源码

Ribbon demo 源码