我们来了解一下负载均衡的源码,是怎么实现的,它是怎么实现的,开始我们说了第三种方式只是用了一个注解,实质上是和第二种方式是一模一样的,那么为了方便观察呢,这里使用第二种方式,来查看源码ServiceInstance serviceInstance = this.loadBalancerClient.choose("PRODUCT");这里调用了choose这种方法,我们点进来可以看到他的一个接口/*** Implemented by classes which use a load balancer to choose a server to* send a request to.** @author Ryan Baxter*/
public interface ServiceInstanceChooser {/*** Choose a ServiceInstance from the LoadBalancer for the specified service* @param serviceId the service id to look up the LoadBalancer* @return a ServiceInstance that matches the serviceId*/ServiceInstance choose(String serviceId);
}按进来跳到他的实现,看一下他的实现类public class RibbonLoadBalancerClient implements LoadBalancerClient {可以看到他实现了一个接口,LoadBalancerClient,LoadBalancerClient又继承了一个ServiceInstanceChooser/*** Represents a client side load balancer* @author Spencer Gibb*/
public interface LoadBalancerClient extends ServiceInstanceChooser {注意我们看源码的时候呢,可以这样子来看,比如我已经进入到这个类里面了,你想看他类之间的关系的话,回到我们要观察的方法@Override
public ServiceInstance choose(String serviceId) {Server server = getServer(serviceId);if (server == null) {return null;}return new RibbonServer(serviceId, server, isSecure(server, serviceId),serverIntrospector(serviceId).getMetadata(server));
}我们知道他第一步要把服务列表要给找出来,你看到这个方法protected Server getServer(String serviceId) {return getServer(getLoadBalancer(serviceId));
}然后又继续往下找protected Server getServer(ILoadBalancer loadBalancer) {if (loadBalancer == null) {return null;}return loadBalancer.chooseServer("default"); // TODO: better handling of key
}可以看到他这里用了哪个去找,用的是一个ILoadBalancer,看一下这个/*** Interface that defines the operations for a software loadbalancer. A typical* loadbalancer minimally need a set of servers to loadbalance for, a method to* mark a particular server to be out of rotation and a call that will choose a* server from the existing list of server.* * @author stonse* */
public interface ILoadBalancer {他用的这个组件去找,这个组件就是属于Ribbo下面的com.netflix.loadbalancer.ILoadBalancer所以说他一旦用了负载均衡的技术,都是Ribbon,我们可以看这个方法protected Server getServer(ILoadBalancer loadBalancer) {if (loadBalancer == null) {return null;}return loadBalancer.chooseServer("default"); // TODO: better handling of key
}这里有几个选择,我们就选择com.netflix.loadbalancer.BaseLoadBalancer.chooseServer(Object)/** Get the alive server dedicated to key* * @return the dedicated server*/
public Server chooseServer(Object key) {if (counter == null) {counter = createCounter();}counter.increment();if (rule == null) {return null;} else {try {return rule.choose(key);} catch (Exception e) {logger.warn("LoadBalancer [{}]:  Error choosing server for key {}", name, key, e);return null;}}
}进来之后同样的可以观察这个类之间的关系,这个就比上一个复杂一些了public class BaseLoadBalancer extends AbstractLoadBalancerpublic abstract class AbstractLoadBalancer implements ILoadBalancer {看一下ILoadBalancer接口,这里有一个getServerList/*** @deprecated 2016-01-20 This method is deprecated in favor of the* cleaner {@link #getReachableServers} (equivalent to availableOnly=true)* and {@link #getAllServers} API (equivalent to availableOnly=false).** Get the current list of servers.** @param availableOnly if true, only live and available servers should be returned*/
@Deprecated
public List<Server> getServerList(boolean availableOnly);这个已经标记废弃了,getAllServers这个还在用/*** @return All known servers, both reachable and unreachable.*/
public List<Server> getAllServers();所以我们断定获取所有服务列表,肯定是在这个方法com.netflix.loadbalancer.BaseLoadBalancer.getAllServers()@Override
public List<Server> getAllServers() {return Collections.unmodifiableList(allServerList);
}这里我们要获取列表,所以我们启动两个实例,由于服务刚刚启动完成,还没来得及获取服务列表,你就来访问就来刷新,所以会遇到这个问题,你看这个日志刚刚报了个错之后,DiscoveryClient打印出的日志,他去获取所有已经注册了的服务,这个时候才去获取,这个时候我们再来访问,此时能够获取服务列表了,就是把这个list作为不能再修改的Listlocalhost:8081/getProductMsghttp://10.40.8.144:8080/msg这是第一步获取服务列表,我们再来看一下他的负载均衡策略,/** Get the alive server dedicated to key* * @return the dedicated server*/
public Server chooseServer(Object key) {if (counter == null) {counter = createCounter();}counter.increment();if (rule == null) {return null;} else {try {return rule.choose(key);} catch (Exception e) {logger.warn("LoadBalancer [{}]:  Error choosing server for key {}", name, key, e);return null;}}
}我们关心的是规则了protected IRule rule = DEFAULT_RULE;有个默认的规则private final static IRule DEFAULT_RULE = new RoundRobinRule();默认的规则是什么,通过名字也能够看出来吧,就是轮询的方式,那我们可以来测试一下,看到底是不是轮询,把Product两个都给启动了,为了以示区别@RestController
public class ClientController {//   @Autowired
//  private RestTemplate restTemplate;@Autowiredprivate LoadBalancerClient loadBalancerClient;@GetMapping("/getProductMsg")public String getProductMsg() {// 1.第一种方式(直接使用RestTemplate,url写死)RestTemplate restTemplate = new RestTemplate();
//      String response = restTemplate.getForObject("http://localhost:8080/msg", String.class);
//      System.out.println(response);// 第二种方式(利用loadBalancerClient通过应用名获取url,然后再使用restTemplate 注意这里不能用第三种的restTemplate)ServiceInstance serviceInstance = this.loadBalancerClient.choose("product");String url = String.format("http://%s:%s", serviceInstance.getHost(),serviceInstance.getPort()+"/msg");System.out.println(url);return restTemplate.getForObject(url, String.class);// 3.第三种方式(利用@LoadBalanced,可以在restTemplate里使用应用名字)
//      String response = restTemplate.getForObject("http://PRODUCT/msg", String.class);
//      System.out.println(response);
//      return response;}
}一个是8080,一个是9080localhost:8080/msglocalhost:9080/msg可以看到他时轮询出现的,这里有三个负载均衡类,他用的到底是哪一个呢,我们可以重启一下,日志里面也会打印出来,public DynamicServerListLoadBalancer(IClientConfig clientConfig, IRule rule, IPing ping,ServerList<T> serverList, ServerListFilter<T> filter,ServerListUpdater serverListUpdater) {super(clientConfig, rule, ping);this.serverListImpl = serverList;this.filter = filter;this.serverListUpdater = serverListUpdater;if (filter instanceof AbstractServerListFilter) {((AbstractServerListFilter) filter).setLoadBalancerStats(getLoadBalancerStats());}restOfInit(clientConfig);
}就是我们刚刚说到的轮询,那假如我们想改变负载均衡的规则,其实一般情况下我们不需要改变,你基本上用这个轮询就可以了,假如需要自己定义的时候,直接在配置里面加一个配置就行了,这个配置很长,不建议大家去记,https://cloud.spring.io/spring-cloud-static/Finchley.SR4/multi/multi_spring-cloud.html我们搜索Ribbon关键字,看目录里面,最好在目录里面搜到,我们直接通过配置文件就可以配置了https://cloud.spring.io/spring-cloud-static/Finchley.SR4/multi/multi_spring-cloud-ribbon.html#
_customizing_the_default_for_all_ribbon_clients16.4 Customizing the Ribbon Client by Setting Propertiesusers:ribbon:NIWSServerListClassName: com.netflix.loadbalancer.ConfigurationBasedServerListNFLoadBalancerRuleClassName: com.netflix.loadbalancer.WeightedResponseTimeRule这个就是表示我们要配置的ClassName,order.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RoundRobinRuleZoneAvoidanceRule

追踪源码自定义负载均衡策略相关推荐

  1. Spring Cloud Alibaba - 11 Ribbon 自定义负载均衡策略(同集群优先权重负载均衡算法)

    文章目录 Pre 需求 工程 Code 继承AbstractLoadBalancerRule实现自定义Rule 随机权重策略 配置 验证 源码 Pre Spring Cloud Alibaba - 0 ...

  2. LoadBalance自定义负载均衡策略

    LoadBalance已有策略   LoadBalance的源码中已有两种策略,RandomLoadBalancer(随机).RoundRobinLoadBalancer(轮询,默认的负载均衡策略). ...

  3. SpringCloud Ribbon(二)之自定义负载均衡策略IRule

    一.Ribbon负载均衡策略 一个服务对应一个LoadBalancer,一个LoadBalancer只有一个Rule,LoadBalancer记录服务的注册地址,Rule提供从服务的注册地址中找出一个 ...

  4. Ribbon 自定义负载均衡策略

    Ribbon默认的负载均衡策略默认的有下面几种: 我们也可以自定义负载均衡策略: 修改springcloud-consumer-dept-80的主启动类: 下面开始编写自定义配置类MySelfRule ...

  5. Spring Cloud Alibaba - 10 Ribbon 自定义负载均衡策略(权重算法)

    文章目录 Pre 工程 首先屏蔽细粒度配置 然后通过代码设置一个全局配置 指定 GlobalRibbonConfig GlobalRibbonConfig 设置负载均衡策略 开发自定义策略 (权重访问 ...

  6. 自定义负载均衡策略:

    我们刚刚讲过,只要实现了IRule就可以完成自定义负载均衡,至于具体怎么来,我们先看看他默认的实现 /*** Copyright 2013 Netflix, Inc.** Licensed under ...

  7. 【云原生微服务八】Ribbon负载均衡策略之WeightedResponseTimeRule源码剖析(响应时间加权)

    文章目录 一.前言 二.WeightedResponseTimeRule 1.计算权重? 1)如何更新权重? 2)如何计算权重? 3)例证权重的计算 2.权重的使用 1)权重区间问题? 一.前言 前置 ...

  8. 企业级java springcloud b2bc商城系统开源源码二次开发-负载均衡策略...

    简单轮询负载均衡 以轮询的方式依次将请求调度不同的服务器,即每次调度执行i=(i+1) mod n 文章来源 JAVA ssm b2b2c多用户商城系统源码 随机负载均衡 随机选择状态为UP的serv ...

  9. spring cloud中通过配置文件自定义Ribbon负载均衡策略

    2019独角兽企业重金招聘Python工程师标准>>> spring cloud中通过配置文件自定义Ribbon负载均衡策略 博客分类: 微服务 一.Ribbon中的负载均衡策略 1 ...

最新文章

  1. 个人信息泄露致电信诈骗猖獗 专家:治理亟须完善立法
  2. 区域经济、地理信息、互联网三者交叉之行业背景分析
  3. 【Linux】5_进程管理
  4. error while loading shared libraries:libmysqlclient.so.18 错误
  5. python编写程序输出诗句_Python学习笔记(一)-- print语句
  6. 密钥生成并配置_如何在 CentOS 8 上设置 SSH 密钥
  7. WeixinJSBridge目前还能够直接使用的功能(2019)
  8. python requests库详解_python爬虫之路(一)-----requests库详解
  9. spring实现mqtt服务端_SpringBoot--实战开发--MQTT消息推送(六十)
  10. 工行网银支付浏览器兼容问题小记
  11. Error: DPI-1047: Cannot locate a 64-bit Oracle Client library: “问题
  12. React项目实战(一)
  13. 计算机cpu型号有,Intel九代CPU型号都有哪些?盘点目前已知的Intel处理器型号大全...
  14. 帝国cms !--list.var1--,!--list.var2--的终极用法
  15. 全球四大国际反垃圾邮件组织介绍
  16. ~囍~ 将欢乐进行到底篇
  17. 位置信息、定位技术与位置服务
  18. Windows 通过bat脚本启动Eureka,Cassandra和redis-server
  19. html分列代码,科学网—EXCEL 分列 (TextToColumns) 的C#代码 - 丁祥欢的博文
  20. 元宇宙是骗局,还是人类的未来?

热门文章

  1. 命名规范(1)大小写约定
  2. 安卓开发笔记——关于图片的三级缓存策略(内存LruCache+磁盘DiskLruCache+网络Volley)...
  3. 悟透JavaScript(美绘本)
  4. 网上商城—管理员增加商品
  5. 用java分组查elasticsearch
  6. group_concat默认长度限制
  7. 什么是CPAN(安装NAGIOS使用到)
  8. JavaScript动态加载js文件
  9. 基于SDN的应用定义安全方案
  10. Table 'barfoo_datacenter_config.parttemplates' doesn't exist------Mysql