springcloud 服务间通讯方式 Ribbon

查看Ribbon :https://blog.csdn.net/qq_32534855/article/details/84111188

1.Eureka服务发现

product 启动了两个实例

2.RestTemplate

RestTemplate

参考:https://blog.csdn.net/madmk/article/details/76431486

1 RestTemplate restTemplate = new RestTemplate(); 2 String response = restTemplate.getForObject("http://localhost:9001/msg",String.class); 3 log.info("response={}",response);

这种方式,调用很简单,但是访问地址写死,不方便,所以这种方式很少用。

并且,当服务启动多个时,很难做到调用多个服务实例。

3.LoadBalancerClient + RestTemplate

1我们通过loadBalancerClient根据应用名获取url 2 3 4 @Autowired 5 LoadBalancerClient loadBalancerClient; 6 7 /** 8 * LoadBalancerClient + RestTemplate方式 9 * 10 * @return 11 */ 12 @GetMapping("/msg2") 13 public String helloMsg2() { 14 RestTemplate restTemplate = new RestTemplate(); 15 16 ServiceInstance instance = loadBalancerClient.choose("product"); 17 String storesUri = String.format("http://%s:%s", instance.getHost(), instance.getPort()); 18 19 String response = restTemplate.getForObject(storesUri + "/msg", String.class); 20 log.info("response={}", response); 21 22 return response; 23 }

4.@LoadBalanced注解 

添加RestTemplateConfig 配置文件,重点在方式上添加**@LoadBalanced**注解

1@Configuration 2public class RestTemplateConfig { 3 4 @Bean 5 @LoadBalanced 6 public RestTemplate restTemplate(){ 7 return new RestTemplate(); 8 } 9}

使用

1 @Autowired 2 private RestTemplate restTemplate; 3 4 /** 5 * LoadBalancerClient + RestTemplate方式 6 * 7 * @return 8 */ 9 @GetMapping("/msg3") 10 public String helloMsg3() { 11 12 //通过应用名+访问地址 13 String response = restTemplate.getForObject("http://product/msg", String.class); 14 log.info("response={}", response); 15 16 return response; 17 }

5.Ribbon实现客户端负载均衡原理

5.1主要概念

  • 服务发现 :根据服务名字,把该服务下所以实力查询出来
  • 服务选择规则:根据服务选择规则,选择出一条有效服务
  • 服务监听:检测失效的服务,高效剔除

5.2主要组件

  • ServerList
  • IRule
  • ServerListFilter

流程:通过ServerList获取可用服务列表,然后通过ServerListFilter过滤掉一部分服务,最后通过IRule选择出一个最终目标结果。

5.3源码分析

5.3.1类间关系

5.3.2 获取可用服务列表

  ServiceInstance instance = loadBalancerClient.choose("product");

我们按住CTRL跟进到choose方法里面

1 public ServiceInstance choose(String serviceId) { 2 return this.choose(serviceId, (Object)null); 3 } 4 5 public ServiceInstance choose(String serviceId, Object hint) { 6 Server server = this.getServer(this.getLoadBalancer(serviceId), hint); 7 return server == null ? null : new RibbonLoadBalancerClient.RibbonServer(serviceId, server, this.isSecure(server, serviceId), this.serverIntrospector(serviceId).getMetadata(server)); 8 }

然后跟进CTRL this.getLoadBalancer(serviceId) 跟进得到的方法是

1 protected ILoadBalancer getLoadBalancer(String serviceId) { 2 return this.clientFactory.getLoadBalancer(serviceId); 3 } 4 5我们现在查看ILoadBalancer 6 7public interface ILoadBalancer { 8 void addServers(List<Server> var1); 9 10 Server chooseServer(Object var1); 11 12 void markServerDown(Server var1); 13 14 /** @deprecated */ 15 @Deprecated 16 List<Server> getServerList(boolean var1); 17 18 List<Server> getReachableServers(); 19 20 List<Server> getAllServers(); 21} 22 23我们猜测gelAllServers是获取所有可用服务列表的集合,现在我们查看一下其实现方法BaseLoadBalancer打一个断点查看一下 24 25 public List<Server> getAllServers() { 26 return Collections.unmodifiableList(this.allServerList); 27 } 28 29结果

这个刚好就是我们选择的PRODUCT的两个服务,就此我们可以判断,gelAllServers是根据服务名称获取服务列表的方法。

现在我们获取到服务列表了,下一步就应该根据规则选择一个服务进行返回。

5.3.3选择一个服务

现在跟进 this.getServer方法

1 protected Server getServer(ILoadBalancer loadBalancer, Object hint) { 2 return loadBalancer == null ? null : loadBalancer.chooseServer(hint != null ? hint : "default"); 3 }

然后跟进chooseServer方法

1 public Server chooseServer(Object key) { 2 if (this.counter == null) { 3 this.counter = this.createCounter(); 4 } 5 6 this.counter.increment(); 7 if (this.rule == null) { 8 return null; 9 } else { 10 try { 11 return this.rule.choose(key); 12 } catch (Exception var3) { 13 logger.warn("LoadBalancer [{}]: Error choosing server for key {}", new Object[]{this.name, key, var3}); 14 return null; 15 } 16 } 17 } 18 19我们可以看见Server svr = this.rule.choose(key); 这个方法,这个就是根据规则选择一个服务 20 21我们查看一下规则rule 22 23 protected IRule rule;

构造函数

1 this.rule = DEFAULT_RULE; 2 3 private static final IRule DEFAULT_RULE = new RoundRobinRule();

通过名字我们可以看出来,负责均衡的方法规则是轮询的方式。

查看测试结果

第一次

第二次

第三次

我们跟进choose方法

1 public Server choose(Object key) { 2 ILoadBalancer lb = this.getLoadBalancer(); 3 Optional<Server> server = this.getPredicate().chooseRoundRobinAfterFiltering(lb.getAllServers(), key); 4 return server.isPresent() ? (Server)server.get() : null; 5 }

debug看到

lb变量里面的

我们可以看见所有服务列表,跟校验规则

然后根据

  Optional<Server> server = this.getPredicate().chooseRoundRobinAfterFiltering(lb.getAllServers(), key);

返回一个服务对象

5.4 修改规则

需要在application.yml

1product: #访问服务名称 2 ribbon: 3 NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

规则在IRule的实现类里面可以选择,也可以自定义

本文同步分享在 博客“DencyCheng”(CSDN)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )