`
huorongbj
  • 浏览: 19680 次
文章分类
社区版块
存档分类
最新评论

分布式系统关注点——仅需这一篇,吃透「负载均衡」妥妥的

阅读更多

本文长度为3426字,预计读完需1.2MB流量,建议阅读9分钟。

 

  上一篇《分布式系统关注点——初识「高可用」》我们对「高可用」有了一个初步认识,其中认为「负载均衡」是「高可用」的核心工作。那么,本篇将通过图文并茂的方式,来描述出每一种负载均衡策略的完整样貌。

 

 

一、「负载均衡」是什么

        正如题图所示的这样,由一个独立的统一入口来收敛流量,再做二次分发的过程就是「负载均衡」,它的本质和「分布式系统」一样,是「分治」。

 

        如果大家习惯了开车的时候用一些导航软件,我们会发现,导航软件的推荐路线方案会有一个数量的上限,比如3条、5条。因此,其实本质上它也起到了一个类似「负载均衡」的作用,因为如果只能取Top3的通畅路线,自然拥堵严重的路线就无法推荐给你了,使得车流的压力被分摊到了相对空闲的路线上。

 

        在软件系统中也是一样的道理,为了避免流量分摊不均,造成局部节点负载过大(如CPU吃紧等),所以引入一个独立的统一入口来做类似上面的“导航”的工作。但是,软件系统中的「负载均衡」与导航的不同在于,导航是一个柔性策略,最终还是需要使用者做选择,而前者则不同。

 

        怎么均衡的背后是策略在起作用,而策略的背后是由某些算法或者说逻辑来组成的。比如,导航中的算法属于「路径规划」范畴,在这个范畴内又细分为「静态路径规划」和「动态路径规划」,并且,在不同的分支下还有各种具体计算的算法实现,如Dijikstra、A*等。同样的,在软件系统中的负载均衡,也有很多算法或者说逻辑在支撑着这些策略,巧的是也有静态和动态之分。

 

 

二、常用「负载均衡」策略图解

        下面来罗列一下日常工作中最常见的5种策略。

 

01  轮询

 

这是最常用也最简单策略,平均分配,人人都有、一人一次。大致的代码如下。

 

int  globalIndex = 0;   //注意是全局变量,不是局部变量。

try
{

    return servers[globalIndex];
}
finally
{
    globalIndex++;
    if (globalIndex == 3)
        globalIndex = 0;
}

 

02  加权轮询

 

      在轮询的基础上,增加了一个权重的概念。权重是一个泛化后的概念,可以用任意方式来体现,本质上是一个能者多劳思想。比如,可以根据宿主的性能差异配置不同的权重。大致的代码如下。

 

int matchedIndex = -1;
int total = 0;
for (int i = 0; i < servers.Length; i++)
{
      servers[i].cur_weight += servers[i].weight;//①每次循环的时候做自增(步长=权重值)
      total += servers[i].weight;//②将每个节点的权重值累加到汇总值中
      if (matchedIndex == -1 || servers[matchedIndex].cur_weight < servers[i].cur_weight) //③如果 当前节点的自增数 > 当前待返回节点的自增数,则覆盖。
      {
            matchedIndex = i;
      }
}

servers[matchedIndex].cur_weight -= total;//④被选取的节点减去②的汇总值,以降低下一次被选举时的初始权重值。
return servers[matchedIndex];

 

        这段代码的过程如下图的表格。"()"中的数字就是自增数,代码中的cur_weight。

 

 

        值得注意的是,加权轮询本身还有不同的实现方式,虽说最终的比例都是2:1:2。但是在请求送达的先后顺序上可以所有不同。比如「5-4,3,2-1」和上面的案例相比,最终比例是一样的,但是效果不同。「5-4,3,2-1」更容易产生并发问题,导致服务端拥塞,且这个问题随着权重数字越大越严重。例子:10:5:3的结果是「18-17-16-15-14-13-12-11-10-9,8-7-6-5-4,3-2-1」 

 

03  最少连接数

 

        这是一种根据实时的负载情况,进行动态负载均衡的方式。维护好活动中的连接数量,然后取最小的返回即可。大致的代码如下。

 

var matchedServer = servers.orderBy(e => e.active_conns).first();

matchedServer.active_conns += 1;

return matchedServer;

//在连接关闭时还需对active_conns做减1的动作。

 

04  最快响应

 

        这也是一种动态负载均衡策略,它的本质是根据每个节点对过去一段时间内的响应情况来分配,响应越快分配的越多。具体的运作方式也有很多,上图的这种可以理解为,将最近一段时间的请求耗时的平均值记录下来,结合前面的「加权轮询」来处理,所以等价于2:1:3的加权轮询。

 

        题外话:一般来说,同机房下的延迟基本没什么差异,响应时间的差异主要在服务的处理能力上。如果在跨地域(例:浙江->上海,还是浙江->北京)的一些请求处理中运用,大多数情况会使用定时「ping」的方式来获取延迟情况,因为是OSI的L3转发,数据更干净,准确性更高。

 

05  Hash法

 

        hash法的负载均衡与之前的几种不同在于,它的结果是由客户端决定的。通过客户端带来的某个标识经过一个标准化的散列函数进行打散分摊

 

        上图中的散列函数运用的是最简单粗暴的「取余法」。

        题外话:散列函数除了取余之外,还有诸如「变基」、「折叠」、「平方取中法」等等,此处不做展开,有兴趣的小伙伴可自行查阅资料。

 

        另外,被求余的参数其实可以是任意的,只要最终转化成一个整数参与运算即可。最常用的应该是用来源ip地址作为参数,这样可以确保相同的客户端请求尽可能落在同一台服务器上。

 

 

三、常用「负载均衡」策略优缺点和适用场景

        我们知道,没有完美的事物,负载均衡策略也是一样。上面列举的这些最常用的策略也有各自的优缺点和适用场景,我稍作了整理,如下。

 

 

        这些负载均衡算法之所以常用也是因为简单,想要更优的效果,必然就需要更高的复杂度。比如,可以将简单的策略组合使用、或者通过更多维度的数据采样来综合评估、甚至是基于进行数据挖掘后的预测算法来做。

 

 

四、用「健康探测」来保障高可用

        不管是什么样的策略,难免会遇到机器故障或者程序故障的情况。所以要确保负载均衡能更好的起到效果,还需要结合一些「健康探测」机制。定时的去探测服务端是不是还能连上,响应是不是超出预期的慢。如果节点属于“不可用”的状态的话,需要将这个节点临时从待选取列表中移除,以提高可用性。一般常用的「健康探测」方式有3种。

 

01  HTTP探测

        使用Get/Post的方式请求服务端的某个固定的URL,判断返回的内容是否符合预期。一般使用Http状态码、response中的内容来判断。

 

02  TCP探测

        基于Tcp的三次握手机制来探测指定的IP + 端口。最佳实践可以借鉴阿里云的SLB机制,如下图。

▲图片来源于阿里云,版权归原作者所有


        值得注意的是,为了尽早释放连接,在三次握手结束后立马跟上RST来中断TCP连接。

 

03  UDP探测

        可能有部分应用使用的UDP协议。在此协议下可以通过报文来进行探测指定的IP + 端口。最佳实践同样可以借鉴阿里云的SLB机制,如下图。

▲图片来源于阿里云,版权归原作者所有

 

        结果的判定方式是:在服务端没有返回任何信息的情况下,默认正常状态。否则会返回一个ICMP的报错信息。

 

 

五、结语

        用一句话来概括负载均衡的本质是:

        将请求或者说流量,以期望的规则分摊到多个操作单元上进行执行。

        通过它可以实现横向扩展(scale out),将冗余的作用发挥为「高可用」。另外,还可以物尽其用,提升资源使用率。

 

 

 

相关文章:

 

 

作者:Zachary(个人微信号:Zachary-ZF
微信公众号(首发):跨界架构师。<-- 点击查阅近期热门文章
定期发表原创内容:架构设计丨分布式系统丨产品丨运营丨一些深度思考
扫码加入小圈子 ↓

 

 

1
0
分享到:
评论

相关推荐

    大规模分布式系统架构与设计实战

    《大规模分布式系统架构与设计实战》从作者的实战经验出发,深入浅出地讲解了如何建立一个Hadoop那样的分布式系统,实现对多台计算机CPU、内存、硬盘的统一利用,从而获取强大计算能力去解决复杂问题。一般互联网...

    《大规模分布式系统架构与设计实战》PDF

    《大规模分布式系统架构与设计实战》从作者的实战经验出发,深入浅出地讲解了如何建立一个Hadoop那样的分布式系统,实现对多台计算机CPU、内存、硬盘的统一利用,从而获取强大计算能力去解决复杂问题。一般互联网...

    300分钟吃透分布式缓存pdf和markdown

    分布式缓存是现代大型互联网应用中的重要组成部分,它能够有效地解决数据访问延迟、减轻数据库压力,提高系统的响应速度和并发处理能力。在这个300分钟的学习资料中,我们将深入探讨分布式缓存的基本概念、工作原理...

    学习笔记:300分钟吃透分布式缓存.docx

    "学习笔记:300分钟吃透分布式缓存" 缓存是指用于加速数据交换的存储介质,可以是硬件也可以是软件。缓存存在的意义就是通过开辟一个新的数据交换缓冲区,来解决原始数据获取代价太大的问题,让数据得到更快的访问...

    300分钟吃透分布式缓存.txt

    学习后可以掌握: 1.掌握redis/Memcached底层实现与高级特性 2.剖析缓存在秒杀、计数器、Feed流中的应用 3.掌握大规模穿透、雪崩等经典问题的解决方案 4.揭秘新浪微博的百万级QPS技术核心

    【架构视角】一篇文章带你彻底吃透Spring.doc

    SpringCloud集成了注册中心、配置中心、负载均衡、熔断器、API网关等多个组件,帮助开发者构建可扩展、高可用的微服务系统。 总的来说,Spring框架的精髓在于解耦和简化,通过Bean管理和功能增强,使得开发人员可以...

    分布式缓存.docx

    分布式缓存是现代Web应用程序中不可或缺的一部分,它能显著提高系统的响应速度和处理能力,减少对后端数据库的依赖。本文将深入探讨Ehcache作为JVM缓存和分布式缓存的角色,以及Redis作为分布式缓存的解决方案,包括...

    300分钟吃透分布式缓存

    内部包括分布式缓存的概念,设计模式,组件选择,key如何考虑和设计,缓存失效时如何处理,特定场景的缓存如何设计,崩溃了如何恢复。具体内容包括(只列举了部分示例): 如何根据业务来选择缓存模式和组件? 设计...

    吃透分布式缓存(拉勾课).pdf

    吃透分布式缓存(拉勾课)

    面试准备 - 分布式系统 CAP 理论.docx

    图文并茂吃透面试题,看完这个,吊打面试官,拿高薪offer!

    数据结构.doc————电子版_doc版

    数据结构.doc————电子版_doc版 数据结构是计算机科学中的一个基本概念,它是指计算机存储、组织和管理数据的方式。数据结构的研究对象是数据的逻辑结构、存储结构和算法结构。 数据结构的定义可以形式地表示为...

    分布式缓存REDIS学习笔记

    01 Redis快速入门 - Redis教程 02-Redis环境安装 - Redis教程 03-Redis 的安装配置介绍 04-Redis数据类型 - Redis教程 05-Redis命令 - Redis教程 06-Redis键 - Redis教程。。。 13-Redis发布订阅 - Redis教程 ...

    面试题:分布式系统接口,如何避免表单的重复提交?.docx

    图文并茂吃透面试题,看完这个,吊打面试官,拿高薪offer!

    吃透OLED模块——玩转OLED模块各种使用方法

    这是其中一种工作方式的模块,如图: ALIENTEK OLED模块默认设置是BS0接GND,BS1和BS2接VCC(8080模式),如果想要设置成其他的模式,则需要在OLED的背面,用烙铁修改BS0-BS2的设置。(硬件改动) 从原理图中我们...

    (新高考适用)3 任务群三 文言文阅读1 吃透考题,四个对话 课件——2021届高考语文冲刺复习.ppt

    (新高考适用)3 任务群三 文言文阅读1 吃透考题,四个对话 课件——2021届高考语文冲刺复习.ppt

    (新高考适用)2 任务群二 文学类文本阅读 1 吃透考题,四个对话 课件——2021届高考语文冲刺复习.ppt

    【标题】中的“2 任务群二 文学类文本阅读 1 吃透考题,四个对话 课件——2021届高考语文冲刺复习”指的是高考语文复习中的一个重要部分,聚焦于文学类文本阅读的策略和技巧,旨在帮助学生理解和掌握这类题目的解题...

    PyFlink必修课!一小时吃透PyFlink1

    一小时吃透PyFlink1】 PyFlink是Apache Flink项目的一个重要组件,它提供了Python接口,使得数据科学家和Python开发者能够利用Flink的强大功能进行流处理和批处理任务。Flink作为一个高度活跃的开源项目,在大数据...

Global site tag (gtag.js) - Google Analytics