• Ribbon负载均衡的深度分析和使用


    前言:
    本篇文章主要介绍Ribbon负载均衡的使用,策略及原理,希望能加深自己的印象以及帮助各位大佬???
    如果文章有什么需要改进的地方还请大佬多多指正
    小威在这里先感谢各位大佬了???

    在这里插入图片描述

    文章目录

    ??Ribbon负载均衡使用

    接着上一篇文章的来,运用负载均衡的注解 @LoadBalanced进行管理

     @Bean
        @LoadBalanced
        public RestTemplate restTemplate() {
            return new RestTemplate();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    ??Ribbon项目使用流程

    在这里插入图片描述

    • 拦截我们的RestTemplate请求http://userservice/user/1
    • RibbonLoadBalancerClient会从请求url中获取服务名称,也就是user-service
    • DynamicServerListLoadBalancer根据user-service到eureka拉取服务列表
    • eureka返回列表,localhost:8081、localhost:8082
    • IRule利用内置负载均衡规则,从列表中选择一个,例如localhost:8081
    • RibbonLoadBalancerClient修改请求地址,用localhost:8081替代userservice,得到http://localhost:8081/user/1,发起真实请求

    ??Ribbon负载均衡分析

    负载均衡拦截器实现客户端http请求拦截器(ClientHttpRequestInterceptor)并重写方法

    public class LoadBalancerInterceptor implements ClientHttpRequestInterceptor {
        private LoadBalancerClient loadBalancer;
        private LoadBalancerRequestFactory requestFactory;
    
        public LoadBalancerInterceptor(LoadBalancerClient loadBalancer, LoadBalancerRequestFactory requestFactory) {
            this.loadBalancer = loadBalancer;
            this.requestFactory = requestFactory;
        }
    
        public LoadBalancerInterceptor(LoadBalancerClient loadBalancer) {
            this(loadBalancer, new LoadBalancerRequestFactory(loadBalancer));
        }
    
        public ClientHttpResponse intercept(final HttpRequest request, final byte[] body, final ClientHttpRequestExecution execution) throws IOException {
            URI originalUri = request.getURI();
            String serviceName = originalUri.getHost();
            Assert.state(serviceName != null, "Request URI does not contain a valid hostname: " + originalUri);
            return (ClientHttpResponse)this.loadBalancer.execute(serviceName, this.requestFactory.createRequest(request, body, execution));
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    找到Eureka服务列表并根据负载均衡算法选取一个服务

    public  T execute(String serviceId, LoadBalancerRequest request, Object hint) throws IOException {
            ILoadBalancer loadBalancer = this.getLoadBalancer(serviceId);//根据服务名称找Eureka服务列表
            Server server = this.getServer(loadBalancer, hint);//根据负载均衡算法从Eureka的server列表中选出一个   
                 if (server == null) {
                throw new IllegalStateException("No instances available for " + serviceId);
            } else {
                RibbonLoadBalancerClient.RibbonServer ribbonServer = new RibbonLoadBalancerClient.RibbonServer(serviceId, server, this.isSecure(server, serviceId), this.serverIntrospector(serviceId).getMetadata(server));
                return this.execute(serviceId, (ServiceInstance)ribbonServer, (LoadBalancerRequest)request);
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

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

    在BaseLoadBalancer.class的类下,利用IRule实现负载均衡的策略

    跟进上面的getServer方法,继续跟踪源码在BaseLoadBalancer类下找到chooseServer方法

     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);//进行服务选择的Key
                } catch (Exception var3) {
                    logger.warn("LoadBalancer [{}]:  Error choosing server for key {}", new Object[]{this.name, key, var3});
                    return null;
                }
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    ??Ribbon负载均衡策略

    跟进上面的rule,rule,规则,即负载均衡的规则,有以下几种

    public class BaseLoadBalancer extends AbstractLoadBalancer implements PrimeConnectionListener, IClientConfigAware {
        private static Logger logger = LoggerFactory.getLogger(BaseLoadBalancer.class);
        private static final IRule DEFAULT_RULE = new RoundRobinRule();//这里的rule默认值是一个`RoundRobinRule`的类型
        private static final BaseLoadBalancer.SerialPingStrategy DEFAULT_PING_STRATEGY = new BaseLoadBalancer.SerialPingStrategy((SyntheticClass_1)null);
        private static final String DEFAULT_NAME = "default";
        private static final String PREFIX = "LoadBalancer_";
        protected IRule rule;
        protected IPingStrategy pingStrategy;
        protected IPing ping;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    在这里插入图片描述

    在这里插入图片描述

    RoundRobinRule(轮询策略):按照一定的顺序依次调用服务实例。多个服务轮流访问。它是Ribbon默认的负载均衡规则。
    RandomRule(随机策略):从服务提供者的列表中随机选择一个服务实例
    WeightedResponseTimeRule(权重策略):根据每个服务提供者的响应时间分配个权重,响应时间越长,权重越小,被选中的可能性也就越低。
    RetryRule(重试策略):按照轮询策略来获取服务,如果获取的服务实例为 null 或已经失效,则在指定的时间之内不断地进行重试来获取服务,如果超过指定时间依然没获取到服务实例则返回 null
    AvailabilityFilteringRule(可敏感性策略):先过滤掉健康的服务实例,然后再选择连接数较的服务实例。
    ZoneAvoidanceRule(区域敏感策略):根据服务所在区域(zone)的性能和服务的可性来选择服务实例,在没有区域的环境下,该策略和轮询策略类似。
    BestAvailableRule(最小连接数策略):也叫最小并发数策略,它是遍历服务提供者列表,选取连接数最小的个服务实例。如果有相同的最连接数,那么会调轮询策略进行选取。即忽略那些短路的服务器,并选择并发数较低的服务器。
    在这里插入图片描述

    ??自定义负载均衡策略

    我们需要在order-service中的OrderApplication类中,定义一个新的IRule:

    @Bean
    public IRule randomRule(){
        return new RandomRule();
    }
    
    • 1
    • 2
    • 3
    • 4

    配置文件方式:在order-service的application.yml文件中,添加新的配置也可以修改规则:

    userservice: # 给某个微服务配置负载均衡规则,这里是userservice服务
      ribbon:
        NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule # 负载均衡规则 
    
    • 1
    • 2
    • 3

    ??Ribbon设置饥饿加载

    Ribbon默认是采用懒加载,就是第一次访问的时候才会去创建LoadBalanceClient,这样的情况下会导致请求时间很长,影响我们的使用效率。

    而饥饿加载则会在项目启动时创建,降低第一次访问的耗时,以下是开启饥饿加载的配置

    ribbon:
      eager-load:
        enabled: true
        clients: userservice
    
    • 1
    • 2
    • 3
    • 4

    本文到此结束,希望能帮到各位小伙伴儿???
    如果文章有什么需要改进的地方还请大佬多多指教???
    以下是我的V信,欢迎加入我们的圈子???
    再次感谢各位大佬???
    在这里插入图片描述

    先自我介绍一下,小编13年上师交大毕业,曾经在小公司待过,去过华为OPPO等大厂,18年进入阿里,直到现在。深知大多数初中级java工程师,想要升技能,往往是需要自己摸索成长或是报班学习,但对于培训机构动则近万元的学费,着实压力不小。自己不成体系的自学效率很低又漫长,而且容易碰到天花板技术停止不前。因此我收集了一份《java开发全套学习资料》送给大家,初衷也很简单,就是希望帮助到想自学又不知道该从何学起的朋友,同时减轻大家的负担。添加下方名片,即可获取全套学习资料哦

  • 相关阅读:
    Selenium爬取内容并存储至MySQL数据库
    关联路网拓扑特性的车辆出行行为画像分析
    解决ubuntu网卡失效-更换内核版本
    记录:利用 Agora 在 Unity3D MRTK场景中创建实时视频聊天应用
    重新认识Java
    记一次加锁导致ECS服务器CPU飙高的处理
    STM32F4-ADC-常规通道-转换模式配置-总结
    微积分 - 导数
    工作卷?一行更比一行卷
    计算机毕业论文选题推荐|软件工程|系列八
  • 原文地址:https://blog.csdn.net/m0_54866636/article/details/126114015