说明

在之前的 eureka-demo 工程(SpringCloud_Eureka.md有步骤) 中,我们启动了一个 user-service,然后通过 DiscoveryClient 来获取服务实例信息,然后获取 ip 和端口来访问
但是实际环境中,我们往往会开启很多个 user-service 的集群。此时我们获取的服务列表中就会有多个,到底该访问哪一个呢?
一般这种情况下我们就需要编写负载均衡算法,在多个实例列表中进行选择。
不过 Eureka 中已经帮我们集成了负载均衡组件:Ribbon,简单修改代码即可使用。

demo

启动3个 user-service 实例,808180828083,启动方式参考 SpringCloud_Eureka.md 中启动多个 eureka-service
SpringCloud_Ribbon - 图1
Eureka 监控面板
SpringCloud_Ribbon - 图2
接下来,消费者会拉取到两个user-service的实例,需要利用负载均衡算法,从中选择一个。
因为Eureka中已经集成了Ribbon,所以我们无需引入新的依赖。直接修改代码:
user-consumer 的启动类中,RestTemplate的配置方法上添加@LoadBalanced注解:

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

修改 user-consumer 中的UserController 中的调用方法,不再手动获取 ip 和端口,而是直接通过服务名称调用

  1. package com.it.learn.controller;
  2. import com.it.learn.pojo.User;
  3. import org.springframework.beans.factory.annotation.Autowired;
  4. import org.springframework.web.bind.annotation.PathVariable;
  5. import org.springframework.web.bind.annotation.RequestMapping;
  6. import org.springframework.web.bind.annotation.RestController;
  7. import org.springframework.web.client.RestTemplate;
  8. @RestController
  9. @RequestMapping("consumer")
  10. public class UserController {
  11. // 发送基于http协议的远程过程调用(2个服务器相互调用)
  12. @Autowired
  13. private RestTemplate restTemplate;
  14. @RequestMapping("/{id}")
  15. public User findUserById(@PathVariable("id") Long id){
  16. String url = "http://user-service/user/" + id;
  17. // 查询
  18. User user = restTemplate.getForObject(url, User.class);
  19. return user;
  20. }
  21. }

访问页面 http://localhost:8080/consumer/5,查看结果
SpringCloud_Ribbon - 图3
可以双击 shift 键找到 RibbonLoadBalancerClient 类,在此位置打断点,查看 user-consumer 是否是轮询的方式调用 user-service
SpringCloud_Ribbon - 图4

请求链路分析

SpringCloud_Ribbon - 图5
流程:

  • 1)用户发送请求到consumer-service
  • 2)consumer-service根据服务id(user-service)去eureka拉取服务列表
  • 3)eureka返回服务列表信息到consumer-service,consumer缓存服务列表,这样下次请求就无需拉取了
  • 4)利用Ribbon的负载均衡策略,从列表中选择一个服务
  • 5)向选中的服务发送请求

demo
ribbon-demo