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

本文长度为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的报错信息。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏大数据挖掘DT机器学习

R语言与Excel约架!谁更适合做数据分析?

这两款工具的使用方法截然不同。使用Excel时,可以通过鼠标点击完成大部分工作,你可以访问界面内不同位置的各种工具。因此Excel非常便于使用(熟能生巧),...

34340
来自专栏进击的程序猿

The Clean Architecture in PHP 读书笔记(一)

框架是非常好的,可以帮助我们快速的开发,但是前期的学习成本往往很高,特别是如果想要深入理解框架,需要花费大量的经历。

10530
来自专栏ytkah

Excel每隔两行自动求和一次怎么操作?

  今天ytkah得到一份数据,要求进行统计分析,由于是原始数据,还没处理过,数据量有点大,如下图所示(Excel每隔两行自动求和),每天的数字由两项组成,男生...

40250
来自专栏吉浦迅科技

Titan V做计算真的这么不靠谱么?

今年3月份有一篇文章在高性能计算这个领域算是引起了一个不小的波动英伟达的 Titan V GPU 计算故障:2+2=4,呃=4.1,不,=4.3.....

90120
来自专栏Python小屋

Python使用三种方法批量修改记事本文件编码格式

应用背景:近期计划写一个贝叶斯算法邮件分类的教学案例,苦于没有足够的训练集,就让同学们帮忙每人从自己的邮箱中找几封垃圾邮件把内容复制下来放到记事本文件中发给我,...

11620
来自专栏FreeBuf

借你一双慧眼,鸟瞰二进制世界的秘密

由于Java世界的特性所致,安卓应用在代码自身保护方面一直乏善可陈。所谓的Java混淆等技术,也不过是一层簿簿的面纱,极易被撕开,毫无秘密可言。所以,当前也没有...

17800
来自专栏AI科技大本营的专栏

8月精选Python开源项目Top10

【导读】过去一个月里,我们对近 250 个 Python 开源项目进行了排名,并挑选出热度前 10 的项目。这份清单的平均 github star 数量高达 1...

22050
来自专栏存储

你真的很熟分布式和事务吗?

微吐槽 hello,world. 不想了,我等码农,还是看看怎么来处理分布式系统中的事务这个老大难吧! 本文略长,读者需要有一定耐心,如果你是高级码农或者架构师...

24090
来自专栏小文博客

在线图片识别系统Ver2.0

该工具是小文博客基于Django框架开发的图片识别系统,调用腾讯云API,目前可识别身份证、驾驶证、行驶证、营业执照、印刷体、手写体等十几种图片。在Ver1.0...

3.3K20
来自专栏码农分享

3.2、苏宁百万级商品爬取 思路讲解 商品爬取

如果我要得到A类别的第B页的商品我应该如何拼接符合条件的地址 我们首先分析地址,地址如下

12230

扫码关注云+社区

领取腾讯云代金券