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

在线体验各类最新模型,更有模型 免费Token 额度领取!
立即体验
简介: 【云原生&微服务八】Ribbon负载均衡策略之WeightedResponseTimeRule源码剖析(响应时间加权)

@[TOC]

一、前言

前置Ribbon相关文章:

  1. 【云原生&微服务一】SpringCloud之Ribbon实现负载均衡详细案例(集成Eureka、Ribbon)
  2. 【云原生&微服务二】SpringCloud之Ribbon自定义负载均衡策略(含Ribbon核心API)
  3. 【云原生&微服务三】SpringCloud之Ribbon是这样实现负载均衡的(源码剖析@LoadBalanced原理)
  4. 【云原生&微服务四】SpringCloud之Ribbon和Erueka集成的细节全在这了(源码剖析)
  5. 【微服务五】Ribbon随机负载均衡算法如何实现的
  6. 【微服务六】Ribbon负载均衡策略之轮询(RoundRobinRule)、重试(RetryRule)
  7. 【微服务七】Ribbon负载均衡策略之BestAvailableRule

我们聊了以下问题:

  1. 为什么给RestTemplate类上加上了@LoadBalanced注解就可以使用Ribbon的负载均衡?
  2. SpringCloud是如何集成Ribbon的?
  3. Ribbon如何作用到RestTemplate上的?
  4. 如何获取到Ribbon的ILoadBalancer?
  5. ZoneAwareLoadBalancer(属于ribbon)如何与eureka整合,通过eureka client获取到对应注册表?
  6. ZoneAwareLoadBalancer如何持续从Eureka中获取最新的注册表信息?
  7. 如何根据负载均衡器ILoadBalancer从Eureka Client获取到的List<Server>中选出一个Server?
  8. Ribbon如何发送网络HTTP请求?
  9. Ribbon如何用IPing机制动态检查服务实例是否存活?
  10. Ribbon负载均衡策略之随机(RandomRule)、轮询(RoundRobinRule)、重试(RetryRule)、选择并发量最小的(BestAvailableRule)实现方式;

本文继续讨论 根据响应时间加权算法(WeightedResponseTimeRule)是如何实现的?

二、WeightedResponseTimeRule

WeightedResponseTimeRule继承自RoundRobinRule,也就是说该策略是对RoundRobinRule的扩展,其增加了 根据实例运行情况来计算权重 并根据权重挑选实例的规则,以达到更优的负载、实例分配效果。

下面我们一点点来看WeightedResponseTimeRule是如何实现根据相应时间计算权重并根据权重挑选实例的?

1、计算权重?

WeightedResponseTimeRule在初始化的时候会初始化父类RoundRobinRule,在RoundRobinRule的有参构造函数中会调用setLoadBalancer(ILoadBalancer)方法,WeightedResponseTimeRule类中重写了setLoadBalancer(ILoadBalancer)方法,在setLoadBalancer(ILoadBalancer)中会调用initialize(ILoadBalancer)对权重进行初始化、并定时更新。
在这里插入图片描述

public static final int DEFAULT_TIMER_INTERVAL = 30 * 1000;

private int serverWeightTaskTimerInterval = DEFAULT_TIMER_INTERVAL;

1)如何更新权重?

WeightedResponseTimeRule通过Timer#schedule()方法启动一个上一个任务结束到下一个任务开始之间间隔30s执行一次的定时任务为每个服务实例计算权重;
在这里插入图片描述
定时任务的主体是DynamicServerWeightTask

// WeightedResponseTimeRule的内部类
class DynamicServerWeightTask extends TimerTask {
    public void run() {
        ServerWeight serverWeight = new ServerWeight();
        try {
            serverWeight.maintainWeights();
        } catch (Exception e) {
            logger.error("Error running DynamicServerWeightTask for {}", name, e);
        }
    }
}

DynamicServerWeightTask的run()方法中会实例化一个ServerWeight对象,并通过其maintainWeights()方法计算权重。

2)如何计算权重?

无论是权重的初始化还是权重的定时更新,都是使用ServerWeight#maintainWeights()方法来计算权重:

// WeightedResponseTimeRule的内部类
class ServerWeight {

    public void maintainWeights() {
        ILoadBalancer lb = getLoadBalancer();
        if (lb == null) {
            return;
        }
        // CAS保证只有一个线程可以进行权重的计算操作
        if (!serverWeightAssignmentInProgress.compareAndSet(false,  true))  {
            return; 
        }
        
        try {
            logger.info("Weight adjusting job started");
            AbstractLoadBalancer nlb = (AbstractLoadBalancer) lb;
            LoadBalancerStats stats = nlb.getLoadBalancerStats();
            if (stats == null) {
                return;
            }
            // 所有实例的平均响应时间总和
            double totalResponseTime = 0;
            for (Server server : nlb.getAllServers()) {
                // 汇总每个实例的平均响应时间到totalResponseTime上
                ServerStats ss = stats.getSingleServerStat(server);
                totalResponseTime += ss.getResponseTimeAvg();
            }
            // 计算每个实例的权重:weightSoFar + totalResponseTime - 实例的平均响应时间
            // 实例的平均响应时间越长、权重就越小,就越不容易被选择到
            Double weightSoFar = 0.0;
            
            List<Double> finalWeights = new ArrayList<Double>();
            for (Server server : nlb.getAllServers()) {
                ServerStats ss = stats.getSingleServerStat(server);
                double weight = totalResponseTime - ss.getResponseTimeAvg();
                weightSoFar += weight;
                finalWeights.add(weightSoFar);   
            }
            setWeights(finalWeights);
        } catch (Exception e) {
            logger.error("Error calculating server weights", e);
        } finally {
            // 表示权重计算结束,允许其他线程进行权重计算
            serverWeightAssignmentInProgress.set(false);
        }

    }
}

方法的核心逻辑:

  1. LoadBalancerStats中记录了每个实例的统计信息,累加所有实例的平均响应时间,得到总平均响应时间totalResponseTime
  2. 为负载均衡器中维护的实例列表逐个计算权重(从第一个开始),计算规则为:weightSoFar + totalResponseTime - 实例的平均响应时间
  3. 其中weightSoFar初始化为零,并且每计算好一个权重需要累加到weightSoFar上供下一次计算使用;

3)例证权重的计算

举个例子,假如服务A有四个实例:A、B、C、D,他们的平均响应时间(单位:ms)为:10、50、100、200。

  • 服务A的所有实例的总响应时间(totalResponseTime)为:10 + 50 + 100 + 200 = 360
  • 每个实例的权重计算规则为:总响应时间(totalResponseTime) 减去 实例的平均响应时间 + 累加的权重weightSoFar,具体到每个实例的计算如下:
  1. 实例A:360 - 10 + 0 = 350(weightSoFar = 0)
  2. 实例B:360 - 50 + 350 = 660(weightSoFar = 350)
  3. 实例C:360 - 100 + 660 = 920(weightSoFar = 660)
  4. 实例D:360 - 200 + 920 = 1080(weightSoFar = 920)

这里的权重值表示各实例权重区间的上限,以上面的计算结果为例,它为这4个实例各构建了一个区间:

  1. 每个实例的区间下限是上一个实例的区间上限;
  2. 每个实例的区间上限是我们计算出的并存储于在List<Double>类型的accumulatedWeights变量中的权重值,其中第一个实例的下限默认为零。

所以,根据上面示例的权重计算结果,我们可以得到每个实例的权重区间:

  1. 实例A:[0,350](weightSoFar = 0)
  2. 实例B:(350, 660](weightSoFar = 350)
  3. 实例C:(660, 920](weightSoFar = 660)
  4. 实例D:(920, 1080](weightSoFar = 920)

从这里我们可以确定每个区间的宽度实际就是:总的平均响应时间 - 实例的平均响应时间,所以服务实例的平均响应时间越短、权重区间的宽度就越大,服务实例被选中的概率就越高。

这些区间边界的开闭如何确定?区间在哪里使用?

2、权重的使用

我们知道Ribbon负载均衡算法体现在IRule的choose(Object key)方法中,而choose(Object key)方法中又会调用choose(ILoadBalancer lb, Object key)方法,所以我们只需要看WeightedResponseTimeRule的choose(ILoadBalancer lb, Object key)方法:
在这里插入图片描述

方法的核心流程如下:

  1. 如果服务实例的最大权重值 < 0.001 或者服务的实例个数发生变更,则采用父类RoundRobinRule做轮询负载;
  2. 否则,利用Random函数生成一个随机数randomWeight,然后遍历权重列表,找到第一个权重值大于等于随机数randomWeight的列表索引下标,然后拿当前权重列表的索引值去服务实例列表中获取具体实例。

1)权重区间问题?

正常每个区间都为(x, y],但是第一个实例和最后一个实例不同:

  1. 由于随机数的最小取值可以为0,所以第一个实例的下限是闭区间;
  2. 随机数的最大值取不到最大权重值,所以最后一个实例的上限是开区间;
相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
相关文章
|
人工智能 安全 Java
智慧工地源码,Java语言开发,微服务架构,支持分布式和集群部署,多端覆盖
智慧工地是“互联网+建筑工地”的创新模式,基于物联网、移动互联网、BIM、大数据、人工智能等技术,实现对施工现场人员、设备、材料、安全等环节的智能化管理。其解决方案涵盖数据大屏、移动APP和PC管理端,采用高性能Java微服务架构,支持分布式与集群部署,结合Redis、消息队列等技术确保系统稳定高效。通过大数据驱动决策、物联网实时监测预警及AI智能视频监控,消除数据孤岛,提升项目可控性与安全性。智慧工地提供专家级远程管理服务,助力施工质量和安全管理升级,同时依托可扩展平台、多端应用和丰富设备接口,满足多样化需求,推动建筑行业数字化转型。
455 5
|
缓存 负载均衡 监控
微服务架构下的电商API接口设计:策略、方法与实战案例
本文探讨了微服务架构下的电商API接口设计,旨在打造高效、灵活与可扩展的电商系统。通过服务拆分(如商品、订单、支付等模块)和标准化设计(RESTful或GraphQL风格),确保接口一致性与易用性。同时,采用缓存策略、负载均衡及限流技术优化性能,并借助Prometheus等工具实现监控与日志管理。微服务架构的优势在于支持敏捷开发、高并发处理和独立部署,满足电商业务快速迭代需求。未来,电商API设计将向智能化与安全化方向发展。
598 102
|
12月前
|
缓存 监控 API
电商API的微服务架构优化策略
随着电商快速发展,API成为连接用户、商家与系统的核心。本文探讨微服务架构下电商API的优化策略,分析高并发、低延迟与数据一致性等挑战,并提供服务拆分、缓存异步、监控容器化等实践方案,助力构建高性能、高可用的电商系统,提升用户体验与业务效率。
|
负载均衡 算法 Java
除了 Ribbon,Spring Cloud 中还有哪些负载均衡组件?
这些负载均衡组件各有特点,在不同的场景和需求下,可以根据项目的具体情况选择合适的负载均衡组件来实现高效、稳定的服务调用。
1504 61
|
监控 JavaScript 数据可视化
建筑施工一体化信息管理平台源码,支持微服务架构,采用Java、Spring Cloud、Vue等技术开发。
智慧工地云平台是专为建筑施工领域打造的一体化信息管理平台,利用大数据、云计算、物联网等技术,实现施工区域各系统数据汇总与可视化管理。平台涵盖人员、设备、物料、环境等关键因素的实时监控与数据分析,提供远程指挥、决策支持等功能,提升工作效率,促进产业信息化发展。系统由PC端、APP移动端及项目、监管、数据屏三大平台组成,支持微服务架构,采用Java、Spring Cloud、Vue等技术开发。
672 7
|
算法 NoSQL Java
微服务架构下的接口限流策略与实践#### 一、
本文旨在探讨微服务架构下,面对高并发请求时如何有效实施接口限流策略,以保障系统稳定性和服务质量。不同于传统的摘要概述,本文将从实际应用场景出发,深入剖析几种主流的限流算法(如令牌桶、漏桶及固定窗口计数器等),通过对比分析它们的优缺点,并结合具体案例,展示如何在Spring Cloud Gateway中集成自定义限流方案,实现动态限流规则调整,为读者提供一套可落地的实践指南。 #### 二、
554 3
|
监控 安全 持续交付
构建高效微服务架构:策略与实践####
在数字化转型的浪潮中,微服务架构凭借其高度解耦、灵活扩展和易于维护的特点,成为现代企业应用开发的首选。本文深入探讨了构建高效微服务架构的关键策略与实战经验,从服务拆分的艺术到通信机制的选择,再到容器化部署与持续集成/持续部署(CI/CD)的实践,旨在为开发者提供一套全面的微服务设计与实现指南。通过具体案例分析,揭示如何避免常见陷阱,优化系统性能,确保系统的高可用性与可扩展性,助力企业在复杂多变的市场环境中保持竞争力。 ####
300 2
|
存储 NoSQL 分布式数据库
微服务架构下的数据库设计与优化策略####
本文深入探讨了在微服务架构下,如何进行高效的数据库设计与优化,以确保系统的可扩展性、低延迟与高并发处理能力。不同于传统单一数据库模式,微服务架构要求更细粒度的服务划分,这对数据库设计提出了新的挑战。本文将从数据库分片、复制、事务管理及性能调优等方面阐述最佳实践,旨在为开发者提供一套系统性的解决方案框架。 ####
|
消息中间件 运维 Cloud Native
云原生架构下的微服务优化策略####
本文深入探讨了云原生环境下微服务架构的优化路径,针对服务拆分、通信效率、资源管理及自动化运维等核心环节提出了具体的优化策略。通过案例分析与最佳实践分享,旨在为开发者提供一套系统性的解决方案,以应对日益复杂的业务需求和快速变化的技术挑战,助力企业在云端实现更高效、更稳定的服务部署与运营。 ####
|
Cloud Native 安全 API
云原生架构下的微服务治理策略与实践####
—透过云原生的棱镜,探索微服务架构下的挑战与应对之道 本文旨在探讨云原生环境下,微服务架构所面临的关键挑战及有效的治理策略。随着云计算技术的深入发展,越来越多的企业选择采用云原生架构来构建和部署其应用程序,以期获得更高的灵活性、可扩展性和效率。然而,微服务架构的复杂性也带来了服务发现、负载均衡、故障恢复等一系列治理难题。本文将深入分析这些问题,并提出一套基于云原生技术栈的微服务治理框架,包括服务网格的应用、API网关的集成、以及动态配置管理等关键方面,旨在为企业实现高效、稳定的微服务架构提供参考路径。 ####
354 5