springcloud微服务总结四 负载均衡
一:Ribbon简介
Ribbon是Netflix公司开源的一个负载均衡的项目,是一个客户端负载均衡器,运行在客户端上。它是一个经过了云端测试的IPC库,可以很好地控制HTTP和TCP客户端的一些行为。 Feign已经默认使用了Ribbon。
二:Ribbon的工作流程

1:user微服务1、user微服务2、user微服务3是一个服务集群,它们都会向注册中心注册服务(它们的应用名都是USER-SERVICE)
2:注册中心记录集群元数据信息,即USER-SERVICE下有3个服务节点
3:Ribbon拦截所有的请求,从请求信息中获取应用名
4:ribbon根据应用名从eureka注册中心获取服务列表
5:ribbon从服务列表中通过相关均衡策略获取具体某个服务
6:请求远程服务
三:Ribbon源码解析
第一步:Ribbon拦截请求,获取应用名
LoadBalancerAutoConfiguration是Ribbon的自动配置类,在这个配置类里面配置了一个拦截器,该拦截器会拦截所有请求,这就是Ribbon的入口

LoadBalancerInterceptor的intercept方法(当远程调用的时候都会被拦截器拦截)
@Overridepublic ClientHttpResponse intercept(final HttpRequest request, final byte[] body, final ClientHttpRequestExecution execution) throws IOException { final URI originalUri = request.getURI(); String serviceName = originalUri.getHost();//这里就是获取应用名可以打断点测试 Assert.state(serviceName != null, "Request URI does not contain a valid hostname: " + originalUri); return this.loadBalancer.execute(serviceName, requestFactory.createRequest(request, body, execution));} |
第二步:通过应用名获取服务列表
负载均衡器ZoneAwareLoadBalancer是获取服务列表的重要组件
@Override
public <T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException {
ILoadBalancer loadBalancer = getLoadBalancer(serviceId);//获取负载均衡器
Server server = getServer(loadBalancer);
if (server == null) {
throw new IllegalStateException("No instances available for " + serviceId);
}
RibbonServer ribbonServer = new RibbonServer(serviceId, server, isSecure(server,
serviceId), serverIntrospector(serviceId).getMetadata(server)); return execute(serviceId, ribbonServer, request);
}
ILoadBalancer是一个接口,具体的实现类是ZoneAwareLoadBalancer
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
// package com.netflix.loadbalancer; import java.util.List; public interface ILoadBalancer {
void addServers(List<Server> var1);
//从列表中获取具体某个服务
Server chooseServer(Object var1); void markServerDown(Server var1); /** @deprecated */
@Deprecated
List<Server> getServerList(boolean var1); List<Server> getReachableServers();
//获取服务列表
List<Server> getAllServers();
}
ZoneAwareLoadBalancer负载均衡器是在RibbonClientConfiguration中提前定义的
@Bean
@ConditionalOnMissingBean
public ILoadBalancer ribbonLoadBalancer(IClientConfig config, ServerList<Server> serverList, ServerListFilter<Server> serverListFilter, IRule rule, IPing ping, ServerListUpdater serverListUpdater) {
return (ILoadBalancer)(this.propertiesFactory.isSet(ILoadBalancer.class, this.name) ?
(ILoadBalancer)this.propertiesFactory.get(ILoadBalancer.class, config, this.name) :
new ZoneAwareLoadBalancer(config, rule, ping, serverList, serverListFilter, serverListUpdater));
}
|
|
ZoneAwareLoadBalancer的继承关系图如下:

getAllServers获取服务列表,ZoneAwareLoadBalancer没有定义getAllServers方法,但是父类BaseLoadBalancer定义了该方法
第三步:从列表中获取具体服务
ZoneAwareLoadBalancer定义了获取服务的方法,但是该方法最终调用的是父类BaseLoadBalancer chooseServer方法
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;
}
}
}
|
|
默认均衡策略ZoneAvoidanceRule,在RibbonClientConfiguration配置类中配置了IRule bean

均衡策略的接口是IRule,具体实现类有10个:

IRule
这是所有负载均衡策略的父接口,里边的核心方法就是choose方法,用来选择一个服务实例。
AbstractLoadBalancerRule
AbstractLoadBalancerRule是一个抽象类,里边主要定义了一个ILoadBalancer,就是我们上文所说的负载均衡器,负载均衡器的功能我们在上文已经说的很详细了,这里就不再赘述,这里定义它的目的主要是辅助负责均衡策略选取合适的服务端实例。
RandomRule
看名字就知道,这种负载均衡策略就是随机选择一个服务实例,看源码我们知道,在RandomRule的无参构造方法中初始化了一个Random对象,然后在它重写的choose方法又调用了choose(ILoadBalancer lb, Object key)这个重载的choose方法,在这个重载的choose方法中,每次利用random对象生成一个不大于服务实例总数的随机数,并将该数作为下标所以获取一个服务实例。
RoundRobinRule
RoundRobinRule这种负载均衡策略叫做轮询负载均衡策略,也就是我们在上文所说的BaseLoadBalancer负载均衡器中默认采用的负载均衡策略。这个类的choose(ILoadBalancer lb, Object key)函数整体逻辑是这样的:开启一个计数器count,在while循环中遍历服务清单,获取清单之前先通过incrementAndGetModulo方法获取一个下标,这个下标是一个不断自增长的数先加1然后和服务清单总数取模之后获取到的(所以这个下标从来不会越界),拿着下标再去服务清单列表中取服务,每次循环计数器都会加1,如果连续10次都没有取到服务,则会报一个警告No available alive servers after 10 tries from load balancer: XXXX。
RetryRule
看名字就知道这种负载均衡策略带有重试功能。首先RetryRule中又定义了一个subRule,它的实现类是RoundRobinRule,然后在RetryRule的choose(ILoadBalancer lb, Object key)方法中,每次还是采用RoundRobinRule中的choose规则来选择一个服务实例,如果选到的实例正常就返回,如果选择的服务实例为null或者已经失效,则在失效时间deadline之前不断的进行重试(重试时获取服务的策略还是RoundRobinRule中定义的策略),如果超过了deadline还是没取到则会返回一个null。
WeightedResponseTimeRule
WeightedResponseTimeRule是RoundRobinRule的一个子类,在WeightedResponseTimeRule中对RoundRobinRule的功能进行了扩展,WeightedResponseTimeRule中会根据每一个实例的运行情况来给计算出该实例的一个权重,然后在挑选实例的时候则根据权重进行挑选,这样能够实现更优的实例调用。WeightedResponseTimeRule中有一个名叫DynamicServerWeightTask的定时任务,默认情况下每隔30秒会计算一次各个服务实例的权重,权重的计算规则也很简单,如果一个服务的平均响应时间越短则权重越大,那么该服务实例被选中执行任务的概率也就越大。
ClientConfigEnabledRoundRobinRule
ClientConfigEnabledRoundRobinRule选择策略的实现很简单,内部定义了RoundRobinRule,choose方法还是采用了RoundRobinRule的choose方法,所以它的选择策略和RoundRobinRule的选择策略一致,不赘述。
BestAvailableRule
BestAvailableRule继承自ClientConfigEnabledRoundRobinRule,它在ClientConfigEnabledRoundRobinRule的基础上主要增加了根据loadBalancerStats中保存的服务实例的状态信息来过滤掉失效的服务实例的功能,然后顺便找出并发请求最小的服务实例来使用。然而loadBalancerStats有可能为null,如果loadBalancerStats为null,则BestAvailableRule将采用它的父类即ClientConfigEnabledRoundRobinRule的服务选取策略(线性轮询)。
PredicateBasedRule
PredicateBasedRule是ClientConfigEnabledRoundRobinRule的一个子类,它先通过内部定义的一个过滤器过滤出一部分服务实例清单,然后再采用线性轮询的方式从过滤出来的结果中选取一个服务实例。
ZoneAvoidanceRule(Finchley.SR1版本中默认均衡策略)
ZoneAvoidanceRule是PredicateBasedRule的一个实现类,只不过这里多一个过滤条件,ZoneAvoidanceRule中的过滤条件是以ZoneAvoidancePredicate为主过滤条件和以AvailabilityPredicate为次过滤条件组成的一个叫做CompositePredicate的组合过滤条件,过滤成功之后,继续采用线性轮询的方式从过滤结果中选择一个出来。
四:自定义均衡策略
在引导类中配置负载均衡策略
@Bean
public IRule myRule(){
//return new RoundRobinRule();//轮询
// return new RetryRule();//重试
return new BestAvailableRule();
}
springcloud微服务总结四 负载均衡的更多相关文章
- java框架之SpringCloud(4)-Ribbon&Feign负载均衡
在上一章节已经学习了 Eureka 的使用,SpringCloud 也提供了基于 Eureka 负载均衡的两种方案:Ribbon 和 Feign. Ribbon负载均衡 介绍 SpringCloud ...
- springcloud微服务总结二 注册中心
一:netflix和springcloud关系 netflix公司开源了很多组件,包括服务注册与发现(Netflix Eureka).断路器(Netflix Hystrix).负载均衡(Netflix ...
- SpringCloud之Ribbon:负载均衡
Spring Cloud集成了Ribbon,结合Eureka,可实现客户端的负载均衡. 下面实现一个例子,结构下图所示. 一.服务器端 1.创建项目 开发工具:IntelliJ IDEA 2019.2 ...
- SpringCloud学习笔记:负载均衡Ribbon(3)
1. RestTemplate简介 RestTemplate是Spring Resource中一个访问第三方RESTful API接口的网络请求框架. RestTemplate是用来消费REST服务的 ...
- Dubbo 源码解析四 —— 负载均衡LoadBalance
欢迎来我的 Star Followers 后期后继续更新Dubbo别的文章 Dubbo 源码分析系列之一环境搭建 Dubbo 入门之二 --- 项目结构解析 Dubbo 源码分析系列之三 -- 架构原 ...
- SpringCloud Netflix Ribbon(负载均衡)
⒈Ribbon是什么? Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端负载均衡工具. Ribbon是Netflix发布的开源项目,主要功能是提供客户端的软件负 ...
- 【架构】SpringCloud 注册中心、负载均衡、熔断器、调用监控、API网关示例
示例代码: https://github.com/junneyang/springcloud-demo 参考资料: SpringCloud系列 Eureka 一句话概括下spring框架及spring ...
- SpringCloud学习(4)——Ribbon负载均衡
Ribbon概述 SpringCloud Ribbon是基于Netflix Ribbon实现的一套客户端负载均衡工具. 简单的说, Ribbon是Netflix发布的开源项目, 主要功能是提供客户端软 ...
- springcloud微服务总结 zuul
一 springcloud网关组件理解: 为什么需要网关呢? 我们知道我们要进入一个服务本身,很明显我们没有特别好的办法,直接输入IP地址+端口号,我们知道这样的做法很糟糕的,这样的做法大有问题,首先 ...
随机推荐
- windows 共存多个位数不同的jdk时,eclipse的报错对应措施
1. 判断当前jdk的位数 # java -version java version "1.6.0_26" Java(TM) SE Runtime Environment (bui ...
- mysql存储引擎简介
- SQL SERVER 微软下载地址
https://www.microsoft.com/zh-cn/search/DownloadsDrillInResults.aspx?q=sql+server+2012&cateorder= ...
- maven学习总结-eclipse开发
一.创建Web项目 1.1 选择建立Maven Project 选择File -> New ->Project,如下图所示:
- PHP开发札记-星期/周操作中常用的日期获取方法
本周一echo date('Y-m-d',(time()-((date('w')==0?7:date('w'))-1)*24*3600)); //w为星期几的数字形式,这里0为周日 本周日 echo ...
- ubuntu16.04 安装openpose
安装 Anaconda3 Tensorflow-cpu python3tensorflow 1.4.1+opencv3, protobuf, python3-tk ================== ...
- c语言练习 二维数组 年平均降水量 月平均降水量
#define YEARS 5#define MONTHES 12 int main(void) { const float rain[YEARS][MONTHES] = { {4.3,4.3,4.3 ...
- p5156 [USACO18DEC]Sort It Out
传送门 分析 我们发现对于没有发现的点相对位置不会发生改变 于是我们可以吧问题转化为求一个lis 于是我们字典序第k小的答案就是字典序第k大的lis 代码 #include<iostream&g ...
- C/C++预处理指令常见的预处理指令
C/C++预处理指令常见的预处理指令如下: #空指令,无任何效果 #include包含一个源代码文件 #define定义宏 #undef取消已定义的宏 #if如果给定条件为真,则编译下面代码 #ifd ...
- springMVC工作原理趣味解析
springMVC 涉及的人有: 1:浏览器 2:DispatherServlet 3:Handler 4:HandlerAdapter ...