【ribbon】Ribbon的负载均衡和扩展功能

这篇具有很好参考价值的文章主要介绍了【ribbon】Ribbon的负载均衡和扩展功能。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Ribbon的核心接口

参考:org.springframework.cloud.netflix.ribbon.RibbonClientConfiguration

  • IClientConfig:Ribbon的客户端配置,默认采用DefaultClientConfigImpl实现。
  • IRule:Ribbon的负载均衡策略,默认采用ZoneAvoidanceRule实现,该策略能够在多区域环境下选出最佳区域的实例进行访问。
  • IPing:Ribbon的实例检查策略,默认采用DummyPing实现,该检查策略是一个特殊的实现,实际上它并不会检查实例是否可用,而是始终返回true,默认认为所有服务实例都是可用的。
  • ServerList:服务实例清单的维护机制,默认采用ConfigurationBasedServerList实现。
  • ServerListFilter:服务实例清单过滤机制,默认采ZonePreferenceServerListFilter,该策略能够优先过滤出与请求方处于同区域的服务实例。
  • ILoadBalancer:负载均衡器,默认采用ZoneAwareLoadBalancer实现,它具备了区域感知的能力。

Ribbon负载均衡策略

【ribbon】Ribbon的负载均衡和扩展功能,springcloud,ribbon,负载均衡,java,spring boot,springcloud

  • RandomRule:随机选择一个Server。
  • RetryRule:对选定的负载均衡策略机上重试机制,在一个配置时间段内当选择Server不成功,则一直尝试使用subRule的方式选择一个可用的server。
  • RoundRobinRule:轮询选择,轮询index,选择index对应位置的Server。
  • AvailabilityFilteringRule:过滤掉一直连接失败的被标记为circuit tripped的后端Server,并过滤掉那些高并发的后端Server或者使用一个AvailabilityPredicate来包含过滤server的逻辑,其实就是检查status里记录的各个Server的运行状态。
  • BestAvailableRule:选择一个最小的并发请求的Server,逐个考察Server,如果Server被tripped了,则跳过。
  • WeightedResponseTimeRule:根据响应时间加权,响应时间越长,权重越小,被选中的可能性越低。
  • ZoneAvoidanceRule:默认的负载均衡策略,即复合判断Server所在区域的性能和Server的可用性选择Server,在没有区域的环境下,类似于轮询
  • NacosRule: 优先调用同一集群的实例,基于随机权重

修改默认负载均衡策略

全局配置

全局配置:所有调用的微服务一律使用指定的负载均衡策略,只需要向容器中注入IRule实例即可。

package com.morris.user.config;

import com.alibaba.cloud.nacos.ribbon.NacosRule;
import com.netflix.loadbalancer.IRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class RibbonConfig {
    @Bean
    public IRule ribbonRule() {
        // 指定使用Nacos提供的负载均衡策略(优先调用同一集群的实例,基于随机权重)
        return new NacosRule();
    }
}

局部配置

局部配置:可以在配置文件中调用指定微服务时,使用对应的负载均衡策略。

# 被调用的微服务名
order-service:
  ribbon:
    # 指定使用Nacos提供的负载均衡策略(优先调用同一集群的实例,基于随机&权重)
    NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule

自定义负载均衡策略

通过实现IRule接口可以自定义负载策略,主要的选择服务逻辑在choose方法中。

实现基于Nacos权重的负载均衡策略:

package com.morris.user.config;

import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.cloud.nacos.NacosServiceManager;
import com.alibaba.cloud.nacos.ribbon.NacosServer;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.DynamicServerListLoadBalancer;
import com.netflix.loadbalancer.Server;
import lombok.extern.slf4j.Slf4j;

import javax.annotation.Resource;

@Slf4j
public class NacosRandomWithWeightRule extends AbstractLoadBalancerRule {


    @Resource
    private NacosServiceManager nacosServiceManager;

    @Resource
    private NacosDiscoveryProperties nacosDiscoveryProperties;

    @Override
    public Server choose(Object key) {
        DynamicServerListLoadBalancer loadBalancer = (DynamicServerListLoadBalancer) getLoadBalancer();
        String serviceName = loadBalancer.getName();
        NamingService namingService = nacosServiceManager.getNamingService(nacosDiscoveryProperties.getNacosProperties());
        try {
            //nacos基于权重的算法
            Instance instance = namingService.selectOneHealthyInstance(serviceName);
            return new NacosServer(instance);
        } catch (NacosException e) {
            log.error("获取服务实例异常:{}", e.getMessage());
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public void initWithNiwsConfig(IClientConfig iClientConfig) {

    }
}

可以将NacosRandomWithWeightRule按照上面的全局配置或者局部配置。

饥饿加载

在进行服务调用的时候,如果网络情况不好,第一次调用会超时。Ribbon默认懒加载,意味着只有在发起调用的时候才会创建客户端。

应用启动后第一次请求会有2s左右的延时,如果此时有大量请求进来就会抛出大量异常。

2023-07-21 16:50:37.718  INFO 20488 --- [nio-8030-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
2023-07-21 16:50:37.718  INFO 20488 --- [nio-8030-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2023-07-21 16:50:37.733  INFO 20488 --- [nio-8030-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 15 ms
2023-07-21 16:50:39.332  INFO 20488 --- [nio-8030-exec-1] c.netflix.loadbalancer.BaseLoadBalancer  : Client: order-service instantiated a LoadBalancer: DynamicServerListLoadBalancer:{NFLoadBalancer:name=order-service,current list of Servers=[],Load balancer stats=Zone stats: {},Server stats: []}ServerList:null
2023-07-21 16:50:39.346  INFO 20488 --- [nio-8030-exec-1] c.n.l.DynamicServerListLoadBalancer      : Using serverListUpdater PollingServerListUpdater
2023-07-21 16:50:39.534  INFO 20488 --- [nio-8030-exec-1] c.n.l.DynamicServerListLoadBalancer      : DynamicServerListLoadBalancer for client order-service initialized: DynamicServerListLoadBalancer:{NFLoadBalancer:name=order-service,current list of Servers=[2.0.0.1:8020],Load balancer stats=Zone stats: {unknown=[Zone:unknown;	Instance count:1;	Active connections count: 0;	Circuit breaker tripped count: 0;	Active connections per server: 0.0;]
},Server stats: [[Server:2.0.0.1:8020;	Zone:UNKNOWN;	Total Requests:0;	Successive connection failure:0;	Total blackout seconds:0;	Last connection made:Thu Jan 01 08:00:00 CST 1970;	First connection made: Thu Jan 01 08:00:00 CST 1970;	Active Connections:0;	total failure count in last (1000) msecs:0;	average resp time:0.0;	90 percentile resp time:0.0;	95 percentile resp time:0.0;	min resp time:0.0;	max resp time:0.0;	stddev resp time:0.0]
]}ServerList:com.alibaba.cloud.nacos.ribbon.NacosServerList@fb090e

开启饥饿加载,解决第一次调用慢的问题:

ribbon:
  eager-load:
    enabled: true
    clients: order-service

参数说明:

  • ribbon.eager-load.enabled:开启ribbon的饥饿加载模式
  • ribbon.eager-load.clients:指定需要饥饿加载的服务名,也就是你需要调用的服务,如果有多个服务,则用逗号隔开

看下效果,在启动过程中就已经初始化连接了:

2023-07-21 16:54:18.480  INFO 22040 --- [           main] com.morris.user.UserServiceApplication   : Started UserServiceApplication in 6.846 seconds (JVM running for 8.265)
2023-07-21 16:54:19.254  INFO 22040 --- [           main] c.netflix.loadbalancer.BaseLoadBalancer  : Client: order-service instantiated a LoadBalancer: DynamicServerListLoadBalancer:{NFLoadBalancer:name=order-service,current list of Servers=[],Load balancer stats=Zone stats: {},Server stats: []}ServerList:null
2023-07-21 16:54:19.260  INFO 22040 --- [           main] c.n.l.DynamicServerListLoadBalancer      : Using serverListUpdater PollingServerListUpdater
2023-07-21 16:54:19.286  INFO 22040 --- [           main] c.n.l.DynamicServerListLoadBalancer      : DynamicServerListLoadBalancer for client order-service initialized: DynamicServerListLoadBalancer:{NFLoadBalancer:name=order-service,current list of Servers=[2.0.0.1:8020],Load balancer stats=Zone stats: {unknown=[Zone:unknown;	Instance count:1;	Active connections count: 0;	Circuit breaker tripped count: 0;	Active connections per server: 0.0;]
},Server stats: [[Server:2.0.0.1:8020;	Zone:UNKNOWN;	Total Requests:0;	Successive connection failure:0;	Total blackout seconds:0;	Last connection made:Thu Jan 01 08:00:00 CST 1970;	First connection made: Thu Jan 01 08:00:00 CST 1970;	Active Connections:0;	total failure count in last (1000) msecs:0;	average resp time:0.0;	90 percentile resp time:0.0;	95 percentile resp time:0.0;	min resp time:0.0;	max resp time:0.0;	stddev resp time:0.0]
]}ServerList:com.alibaba.cloud.nacos.ribbon.NacosServerList@432469

NacosRule源码分析

com.alibaba.cloud.nacos.ribbon.NacosRule#choose

@Override
public Server choose(Object key) {
    try {
        String clusterName = this.nacosDiscoveryProperties.getClusterName();
        String group = this.nacosDiscoveryProperties.getGroup();
        DynamicServerListLoadBalancer loadBalancer = (DynamicServerListLoadBalancer) getLoadBalancer();
        String name = loadBalancer.getName();

        // 获取NamingService,在我们的代码中也可以这么使用
        NamingService namingService = nacosServiceManager
                .getNamingService(nacosDiscoveryProperties.getNacosProperties());
        // 筛选出同一个group的实例,不同group之间不能通讯
        List<Instance> instances = namingService.selectInstances(name, group, true);
        if (CollectionUtils.isEmpty(instances)) {
            LOGGER.warn("no instance in service {}", name);
            return null;
        }

        List<Instance> instancesToChoose = instances;
        if (StringUtils.isNotBlank(clusterName)) {
            // 找出同一个集群的节点
            List<Instance> sameClusterInstances = instances.stream()
                    .filter(instance -> Objects.equals(clusterName,
                            instance.getClusterName()))
                    .collect(Collectors.toList());
            if (!CollectionUtils.isEmpty(sameClusterInstances)) {
                instancesToChoose = sameClusterInstances;
            }
            else {
                LOGGER.warn(
                        "A cross-cluster call occurs,name = {}, clusterName = {}, instance = {}",
                        name, clusterName, instances);
            }
        }

        // 带权重的随机选择一个节点
        Instance instance = ExtendBalancer.getHostByRandomWeight2(instancesToChoose);

        return new NacosServer(instance);
    }
    catch (Exception e) {
        LOGGER.warn("NacosRule error", e);
        return null;
    }
}

NacosRule是AlibabaNacos自己实现的一个负载均衡策略,可以在nacos平台中根据自定义权重进行访问。

基于Nacos元数据的版本控制自定义负载均衡

实际项目,我们可能还会有这样的需求:

一个微服务在线上可能多版本共存,且多个版本的微服务并不兼容。使用Nacos的自定义元数据,可以实现微服务的版本控制。

配置文件的格式: spring.cloud.nacos.discovery.metadata.{key}={value}

当前配置的版本: spring.cloud.nacos.discovery.metadata.version=V1文章来源地址https://www.toymoban.com/news/detail-613769.html

package com.morris.user.config;

import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.cloud.nacos.NacosServiceManager;
import com.alibaba.cloud.nacos.ribbon.ExtendBalancer;
import com.alibaba.cloud.nacos.ribbon.NacosServer;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.BaseLoadBalancer;
import com.netflix.loadbalancer.Server;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;

import javax.annotation.Resource;
import java.util.List;
import java.util.stream.Collectors;

@Slf4j
public class ClusterMetaDataRibbonRule extends AbstractLoadBalancerRule {
 
    @Resource
    private NacosDiscoveryProperties nacosDiscoveryProperties;

    @Resource
    private NacosServiceManager nacosServiceManager;
 
    @Override
    public void initWithNiwsConfig(IClientConfig iClientConfig) {
    }
 
    @Override
    public Server choose(Object o) {
        log.info("-------key: {}", o);
 
        // 获取当前服务的集群名称
        String currentClusterName = nacosDiscoveryProperties.getClusterName();
 
        // 获取当前版本
        String currentVersion = nacosDiscoveryProperties.getMetadata().get("version");
 
        // 获取被调用的服务的名称
        BaseLoadBalancer baseLoadBalancer = (BaseLoadBalancer) getLoadBalancer();
        String serviceName = baseLoadBalancer.getName();
 
        // 获取nacos clinet的服务注册发现组件的api
        NamingService namingService = nacosServiceManager.getNamingService(nacosDiscoveryProperties.getNacosProperties());
 
        try {
            // 获取所有被调用服务
            List<Instance> allInstances = namingService.getAllInstances(serviceName);
 
            // 过滤出相同版本且相同集群下的所有服务
            List<Instance> sameVersionAndClusterInstances = allInstances.stream()
                    .filter(x -> StringUtils.equalsIgnoreCase(x.getMetadata().get("version"), currentVersion)
                            && StringUtils.equalsIgnoreCase(x.getClusterName(), currentClusterName)
                    ).collect(Collectors.toList());
 
            Instance chooseInstance;
            if(sameVersionAndClusterInstances.isEmpty()) {
                // 过滤出所有相同版本的服务
                List<Instance> sameVersionInstances = allInstances.stream()
                        .filter(x -> StringUtils.equalsIgnoreCase(x.getMetadata().get("version"), currentVersion))
                        .collect(Collectors.toList());
                if(sameVersionInstances.isEmpty()) {
                    log.info("跨集群调用找不到对应合适的版本当前版本为:currentVersion:{}",currentVersion);
                    throw new RuntimeException("找不到相同版本的微服务实例");
                }
                else {
                    // 随机权重
                    chooseInstance = ExtendBalancer.getHostByRandomWeight2(sameVersionInstances);
                    log.info("跨集群同版本调用--->当前微服务所在集群:{},被调用微服务所在集群:{},当前微服务的版本:{},被调用微服务版本:{},Host:{},Port:{}",
                            currentClusterName, chooseInstance.getClusterName(), chooseInstance.getMetadata().get("current-version"),
                            chooseInstance.getMetadata().get("current-version"), chooseInstance.getIp(), chooseInstance.getPort());
                }
            }
            else {
                chooseInstance = ExtendBalancer.getHostByRandomWeight2(sameVersionAndClusterInstances);
                log.info("同集群同版本调用--->当前微服务所在集群:{},被调用微服务所在集群:{},当前微服务的版本:{},被调用微服务版本:{},Host:{},Port:{}",
                        currentClusterName, chooseInstance.getClusterName(), chooseInstance.getMetadata().get("version"),
                        chooseInstance.getMetadata().get("current-version"), chooseInstance.getIp(), chooseInstance.getPort());
            }
            return new NacosServer(chooseInstance);
        } catch (NacosException e) {
            log.error("error,", e);
            return null;
        }
    }
}

到了这里,关于【ribbon】Ribbon的负载均衡和扩展功能的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • SpringCloud Ribbon负载均衡(十一)

    前面搭建了初步例子,但是还没实现真正负载均衡,我们这里要先搞三个服务提供者集群,然后才能演示负载均衡,以及负载均衡策略; 新建项目microservice-student-provider-1002,microservice-student-provider-1003 pom.xml,application.yml,以及java类都复制一份,启动类名称对应的改下;  

    2024年02月09日
    浏览(43)
  • SpringCloud(三) Ribbon负载均衡

    SpringCloud(二) Eureka注册中心的使用-CSDN博客 在SpringCloud(二)中学习了如何通过Eureka实现服务的注册和发送,从而通过RestTemplate实现不同微服务之间的调用,加上@LoadBalance注解之后实现负载均衡,那负载均衡的原理是什么呢? 目录 一, 负载均衡 1.1 负载均衡原理  1.2 源码追踪 1, LoadBa

    2024年02月06日
    浏览(45)
  • SpringCloud系列:负载均衡组件-Ribbon

    作者平台: | CSDN:blog.csdn.net/qq_41153943 | 掘金:juejin.cn/user/651387… | 知乎:www.zhihu.com/people/1024… | GitHub:github.com/JiangXia-10… 本文一共4529字,预计阅读12分钟 前面几篇文章介绍了微服务相关的内容,比如什么是微服务,常见的一些服务注册中心组件,以及微服务之间是如何进

    2024年02月17日
    浏览(44)
  • SpringCloud学习笔记-Ribbon负载均衡

    SpringCloudRibbon的底层采用了一个拦截器,拦截了RestTemplate发出的请求,对地址做了修改。用一幅图来总结一下: 基本流程如下: 拦截我们的RestTemplate请求http://userservice/user/1 RibbonLoadBalancerClient会从请求url中获取服务名称,也就是user-service DynamicServerListLoadBalancer根据user-service到

    2024年02月07日
    浏览(40)
  • 负载均衡 —— SpringCloud Netflix Ribbon

    Ribbon 是 Netfix 客户端的负载均衡器,可对 HTTP 和 TCP 客户端的行为进行控制。为 Ribbon 配置服务提供者地址后,Ribbon 就可以基于某种负载均衡算法自动帮助服务消费者去请求。Ribbon 默认提供了很多负载均衡算法,例如轮询、随机等,也可以为 Ribbon 实现自定义的负载均衡算法

    2024年02月08日
    浏览(33)
  • Springcloud基础(4)-Ribbon负载均衡

    Spring Cloud Ribbon 是一套基于 Netflix Ribbon 实现的客户端负载均衡和服务调用工具。Ribbon是Netflix发布的开源项目,主要功能是提供客户端的软件负载均衡算法,将Netflix的中间层服务连接在一起。Ribbon客户端组件提供一系列完善的配置项如连接超时,重试等。简单的说,就是在配

    2024年02月16日
    浏览(37)
  • springcloud Ribbon负载均衡服务调用

    地址:https://github.com/13thm/study_springcloud/tree/main/days6_Ribbon Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端 负载均衡的工具。 简单的说,Ribbon是Netflix发布的开源项目,主要功能是提供客户端的软件负载均衡算法和服务调用。Ribbon客户端组件提供一系列完善的配置项如连接超时

    2024年01月20日
    浏览(48)
  • 03-SpringCloud-Ribbon负载均衡

    SpringCloud底层其实是利用了一个名为Ribbon的组件,来实现负载均衡功能的。 那么我们发出的请求明明是http://userservice/user/1,怎么变成了http://localhost:8081的呢? 为什么我们只输入了service名称就可以访问了呢?之前还要获取ip和端口。 显然有人帮我们根据service名称,获取到了服

    2024年02月03日
    浏览(51)
  • 【微服务 SpringCloud】实用篇 · Ribbon负载均衡

    微服务(4) 在前面,我们添加了@LoadBalanced注解,即可实现负载均衡功能,这是什么原理、什么策略呢? SpringCloud底层其实是利用了一个名为 Ribbon 的组件 ,来实现负载均衡功能的。 那么我们发出的请求明明是http://userservice/user/1,怎么变成了http://localhost:8081的呢? 为什么我

    2024年02月08日
    浏览(49)
  • SpringCloud Ribbon中的7种负载均衡策略

    负载均衡通器常有两种实现手段,一种是服务端负载均衡器,另一种是客户端负载均衡器,而我们今天的主角 Ribbon 就属于后者——客户端负载均衡器。 服务端负载均衡器的问题是,它提供了更强的流量控制权,但无法满足不同的消费者希望使用不同负载均衡策略的需求,而

    2024年02月11日
    浏览(38)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包