Ribbon 负载均衡源码解读

简介: Ribbon 负载均衡源码解读

转载请注明出处:

1.什么是Ribbon

  是 Netflix 发布的一个负载均衡器,有助于控制 HTTP 和 TCP客户端行为。在 SpringCloud 中, nacos一般配合Ribbon进行使用,Ribbon提供了客户端负载均衡的功能,Ribbon利用从nacos中读 取到的服务信息,在调用服务节点提供的服务时,会合理(策略)的进行负载。 在SpringCloud中可以将注册中心和Ribbon配合使用,Ribbon自动的从注册中心中获取服务提供者的 列表信息,并基于内置的负载均衡算法,请求服务。

  Ribbon的主要作用:基于Ribbon实现服务调用, 通过拉取到的所有服务列表组成(服务名-请求路径的)映射关系。借助 RestTemplate 最终进行调用负载均衡,当有多个服务提供者时,Ribbon可以根据负载均衡的算法自动的选择需要调用的服务地址

 

2. restTemplate 调用接口时使用Ribbon

  首先需要定义 RestTemplate 使用 Ribbon 策略;

@LoadBalanced
    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }


  本地使用 RestTemplate 调用远程接口;

@Autowired
private RestTemplate restTemplate;
@RequestMapping(value = "/echo/{id}", method = RequestMethod.GET)
public String echo(@PathVariable Long id) {
    return restTemplate.getForObject("http://member-service/member/get/" + id, String.class);
}

 

3. Ribbon 原理

  使用RestTemplate对象只需要访问一个带有对象名称的路径,也就是http://userservice/user/XX,就可以访问到相对应的接口,这其中离不开LoadBalancerInterceptor的帮助,它会去RestTemplate的请求进行拦截,然后从Eureka中获取服务id与端口号,随后利用负载均衡算法得到真实的服务地址信息,替换服务id。

  在LoadBalancerInterceptor这个类中,会有一个intercept方法,其拦截了用户的HttpRequest请求,通过调用以下api ;

public ClientHttpResponse intercept(final HttpRequest request, final byte[] body, final ClientHttpRequestExecution execution) throws IOException {
        // 获取请求uri,也就是 http://user-service/user/8
        URI originalUri = request.getURI();
        // 获取uri路径的主机名,其实就是服务id,user-service
        String serviceName = originalUri.getHost();
        Assert.state(serviceName != null, "Request URI does not contain a valid hostname: " + originalUri);
        // 处理服务id,和用户请求
        return (ClientHttpResponse)this.loadBalancer.execute(serviceName, this.requestFactory.createRequest(request, body, execution));
    }

  获取到了url、主机名、和服务的id,再将这些信息作为参数传到LoadBalancerClient(this.loadBalancer)的execute的方法中;

  而在LoadBalancerClient的execute方法中可以通过服务id获取到服务列表,并获取合适的服务的端口号,这个方法的实现会进入到 RibbonLoadBalancerClient.execute 方法中;

  • getLoadBalancer(serviceId):根据服务id获取ILoadBalancer,而ILoadBalancer会拿着服务id去eureka中获取服务列表并保存起来。
  • getServer(loadBalancer):利用内置的负载均衡算法,从服务列表中选择一个。也就是127.0.0.1:8080

  从这里可以知道,负载均衡的实现是在getServer方法中实现的

protected Server getServer(ILoadBalancer loadBalancer, Object hint) {

  return loadBalancer == null ? null : loadBalancer.chooseServer(hint != null ? hint : "default");

}

  查看 loadBalancer.chooseServer 的实现,进入 BaseLoadBalancer 类

public Server chooseServer(Object key) {
        if (this.counter == null) {
            this.counter = this.createCounter();
        }
        this.counter.increment();
        if (this.rule == null) {
            return null;
        } else {
            try {
                return this.rule.choose(key);
            } catch (Exception var3) {
                logger.warn("LoadBalancer [{}]:  Error choosing server for key {}", new Object[]{this.name, key, var3});
                return null;
            }
        }
    }

  从方法名中可以看出 rule.choose 为定义的负载均衡规则的选择,查看这个方法的实现:

  通过快捷键查看该方法的实现类可以看到 项目中所支持的负载均衡规则;若打断点 可以发现,前面传过来的default对应的是RoundRobinRule对象 ; RoundRobinRule对应的是一个轮询的规则,所以这里采用的默认负载均衡规则是轮询;

  集成了nacos 后,使用 NacosRule 规则进行负载均衡:

public Server choose(Object key) {
        try {
            String clusterName = this.nacosDiscoveryProperties.getClusterName();
            String group = this.nacosDiscoveryProperties.getGroup();
            DynamicServerListLoadBalancer loadBalancer = (DynamicServerListLoadBalancer)this.getLoadBalancer();
            String name = loadBalancer.getName();
            // 根据group,name 等获取nacos 中的服务组
            NamingService namingService = this.nacosServiceManager.getNamingService(this.nacosDiscoveryProperties.getNacosProperties());        
            // 获取服务组对应的所有实例信息:updateServiceNow 里面去调用 /instance/list接口查询服务信息
            List<Instance> instances = namingService.selectInstances(name, group, true);
            if (CollectionUtils.isEmpty(instances)) {
                LOGGER.warn("no instance in service {}", name);
                return null;
            } else {
                List<Instance> instancesToChoose = instances;
                Instance instance = ExtendBalancer.getHostByRandomWeight2(instancesToChoose);
                // 返回nacos的服务实例
                return new NacosServer(instance);
            }
        } catch (Exception var10) {
            LOGGER.warn("NacosRule error", var10);
            return null;
        }
    }

 

4.常用的Ribbon负载均衡策略

  

内置负载均衡规则类 规则描述
RoundRobinRule 简单轮询服务列表来选择服务器。它是Ribbon默认的负载均衡规则。
AvailabilityFilteringRule 对以下两种服务器进行忽略: (1)在默认情况下,这台服务器如果3次连接失败,这台服务器就会被设置为“短路”状态。短路状态将持续30秒,如果再次连接失败,短路的持续时间就会几何级地增加。 (2)并发数过高的服务器。如果一个服务器的并发连接数过高,配置了AvailabilityFilteringRule规则的客户端也会将其忽略。并发连接数的上限,可以由客户端的..ActiveConnectionsLimit属性进行配置。
WeightedResponseTimeRule 为每一个服务器赋予一个权重值。服务器响应时间越长,这个服务器的权重就越小。这个规则会随机选择服务器,这个权重值会影响服务器的选择。
ZoneAvoidanceRule 以区域可用的服务器为基础进行服务器的选择。使用Zone对服务器进行分类,这个Zone可以理解为一个机房、一个机架等。而后再对Zone内的多个服务做轮询。
BestAvailableRule 忽略那些短路的服务器,并选择并发数较低的服务器。
RandomRule 随机选择一个可用的服务器。
RetryRule 重试机制的选择逻辑

 

  注意:nacos-discovery依赖了ribbon,可以不用再引入ribbon依赖

 

标签: spring cloud

目录
相关文章
|
1月前
|
负载均衡 算法 架构师
Ribbon负载均衡
上一节就已经实现的负载均衡笔者并未深入探讨,本节通过分析负载均衡算法、Ribbon实现负载均衡的底层原理和实现过程,让大家对负载均衡有了一个大体认识,同时针对Ribbon自定义负载均衡策略,饥饿加载让大家对于Ribbon的了解又多一些。Ribbon实现的负载均衡只是方案之一,我们可以尽量多了解但不要局限于此。
|
23天前
|
存储 设计模式 缓存
OpenFeign集成Ribbon负载均衡-过滤和选择服务核心实现
该文章主要介绍了如何在OpenFeign中集成Ribbon以实现负载均衡,并详细分析了Ribbon中服务选择和服务过滤的核心实现过程。文章还涉及了Ribbon中负载均衡器(ILoadBalancer)和负载均衡策略(IRule)的初始化方式。
OpenFeign集成Ribbon负载均衡-过滤和选择服务核心实现
|
23天前
|
缓存 负载均衡 Java
OpenFeign最核心组件LoadBalancerFeignClient详解(集成Ribbon负载均衡能力)
文章标题为“OpenFeign的Ribbon负载均衡详解”,是继OpenFeign十大可扩展组件讨论之后,深入探讨了Ribbon如何为OpenFeign提供负载均衡能力的详解。
OpenFeign最核心组件LoadBalancerFeignClient详解(集成Ribbon负载均衡能力)
|
12天前
|
负载均衡 算法 调度
负载均衡原理分析与源码解读
负载均衡原理分析与源码解读
|
2月前
|
负载均衡 Java API
Feign 进行rpc 调用时使用ribbon负载均衡源码解析
Feign 进行rpc 调用时使用ribbon负载均衡源码解析
56 11
|
3月前
|
负载均衡 算法 Java
Ribbon怎么实现的负载均衡
Ribbon怎么实现的负载均衡
23 0
|
3月前
|
缓存 负载均衡 算法
解读 Nginx:构建高效反向代理和负载均衡的秘密
解读 Nginx:构建高效反向代理和负载均衡的秘密
89 2
|
2月前
|
负载均衡 算法 应用服务中间件
nginx自定义负载均衡及根据cpu运行自定义负载均衡
nginx自定义负载均衡及根据cpu运行自定义负载均衡
29 1
|
2月前
|
运维 负载均衡 算法
SLB与NGINX的异同是什么
SLB与NGINX的异同是什么
92 2
|
4月前
|
负载均衡 应用服务中间件 nginx
解决nginx配置负载均衡时invalid host in upstream报错
在Windows环境下,配置Nginx 1.11.5进行负载均衡时遇到问题,服务无法启动。错误日志显示“invalid host in upstream”。检查发现上游服务器列表中,192.168.29.128的主机地址无效。负载均衡配置中,两个服务器地址前误加了&quot;http://&quot;。修正方法是删除上游服务器列表和proxy_pass中的&quot;http://&quot;。问题解决后,Nginx服务应能正常启动。
261 4
解决nginx配置负载均衡时invalid host in upstream报错
下一篇
DDNS