彻底揭秘负载均衡算法与实现!深入剖析负载均衡核心(上)

本文涉及的产品
传统型负载均衡 CLB,每月750个小时 15LCU
网络型负载均衡 NLB,每月750个小时 15LCU
应用型负载均衡 ALB,每月750个小时 15LCU
简介: 彻底揭秘负载均衡算法与实现!深入剖析负载均衡核心

-     前言     -


记得同事曾说过一个故事:在他刚工作的时候,他同事有一天兴冲冲的跑到公司说,你们知道吗,公司请了个大牛。大牛?对,那人会写AJAX!哇,真是大牛啊,跟着他,可以学不少东西啊。我听了笑了,但有点难以理解,因为现在几乎只要是一个开发,都会写AJAX,怎么写个AJAX就算大牛呢?


后来我明白了,3 年前高深莫测的技术到现在变得普普通通,不足为奇。就像我们今天要讲的负载均衡,过去负载均衡只有大牛才能玩转,但是到今天,一个小开发都可以聊上几句。现在,我们就来简单聊聊负载均衡。


-     负载均衡的维度    -


从负载均衡设备的角度来看,分为硬件负载均衡和软件负载均衡:


  • 硬件负载均衡:比如最常见的F5,还有Array等,这些负载均衡是商业的负载均衡器,性能比较好,毕竟他们就是为了负载均衡而生的,背后也有非常成熟的团队,可以提供各种解决方案,但是价格比较昂贵,所以没有充足的理由和充足的预算是不会考虑的。

  • 软件负载均衡:包括我们耳熟能详的Nginx、LVS、Tengine(阿里对Nginx进行的改造)等。优点就是成本比较低,但是也需要有比较专业的团队去维护,要自己去踩坑,去DIY。


从负载均衡的技术角度来看,分为服务端负载均衡和客户端负载均衡:


  • 服务端负载均衡:当我们访问一个服务,请求会先到另外一台服务器,然后这台服务器,会把请求分发到提供这个服务的服务器。当然如果只有一台服务器,那好说,直接把请求给那一台服务器就可以了,但是如果有多台服务器呢?这时候,就会根据一定的算法选择一台服务器。

  • 客户端负载均衡:客户端服务均衡的概念貌似是有了服务治理才产生的,简单的来说,就是在一台服务器上维护着所有服务的ip,名称等信息,当我们在代码中访问一个服务,是通过一个组件访问的,这个组件会从那台服务器上取到所有提供这个服务的服务器的信息,然后通过一定的算法,选择一台服务器进行请求。


从负载均衡的算法来看,又分为随机、轮询、哈希、最小压力,当然可能还会加上权重的概念,负载均衡的算法就是本文的重点了。


1、随机

public class Servers {
    public List<String> list = new ArrayList<>() {
        {
            add("192.168.1.1");
            add("192.168.1.2");
            add("192.168.1.3");
        }
    };
}
public class FullRandom {
    static Servers servers = new Servers();
    static Random random = new Random();
    public  static String  go() {
        var number = random.nextInt(servers.list.size());
        return servers.list.get(number);
    }
    public static void main(String[] args) {
        for (var i = 0; i < 15; i++) {
            System.out.println(go());
        }
    }
}


运行结果:

image.png

虽说现在感觉并不是那么随机,有的服务器经常被获得到,有的服务器获得的次数比较少,但是当有充足的请求次数,就会越来越平均,这正是随机数的一个特性。


完全随机是最简单的负载均衡算法了,缺点比较明显,因为服务器有好有坏,处理能力是不同的,我们希望性能好的服务器多处理些请求,性能差的服务器少处理一些请求,所以就有了加权随机。


2、加权随机

加权随机,虽然还是采用的随机算法,但是为每台服务器设置了权重,权重大的服务器获得的概率大一些,权重小的服务器获得的概率小一些。


关于加权随机的算法,有两种实现方式:


一种是网上流传的,代码比较简单:构建一个服务器的List,如果A服务器的权重是2,那么往List里面Add两次A服务器,如果B服务器的权重是7,那么我往List里面Add7次B服务器,以此类推,然后再生成一个随机数,随机数的上限就是权重的总和,也就是List的Size。


这样权重越大,被选中的概率当然越高,代码如下:

public class Servers {
    public HashMap<String, Integer> map = new HashMap<>() {
        {
            put("192.168.1.1", 2);
            put("192.168.1.2", 7);
            put("192.168.1.3", 1);
        }
    };
}
public class WeightRandom {
    static Servers servers = new Servers();
    static Random random = new Random();
    public static String go() {
        var ipList = new ArrayList<String>();
        for (var item : servers.map.entrySet()) {
            for (var i = 0; i < item.getValue(); i++) {
                ipList.add(item.getKey());
            }
        }
        int allWeight = servers.map.values().stream().mapToInt(a -> a).sum();
        var number = random.nextInt(allWeight);
        return ipList.get(number);
    }
    public static void main(String[] args) {
        for (var i = 0; i < 15; i++) {
            System.out.println(go());
        }
    }
}

运行结果:

image.png

可以很清楚的看到,权重小的服务器被选中的概率相对是比较低的。


当然我在这里仅仅是为了演示,一般来说,可以把构建服务器List的代码移动到静态代码块中,不用每次都构建。


这种实现方式相对比较简单,很容易就能想到,但是也有缺点,如果我几台服务器权重设置的都很大,比如上千、上万,那么服务器List也有上万条数据,这不是白白占用内存吗?


所以聪明的程序员想到了第二种方式,为了方便解释,还是就拿上面的例子来说。


如果A服务器的权重是2,B服务器的权重是7,C服务器的权重是1:

  • 如果我生成的随机数是1,那么落到A服务器,因为1<=2(A服务器的权重);
  • 如果我生成的随机数是5,那么落到B服务器,因为5>2(A服务器的权重),5-2(A服务器的权重)=3,3<7(B服务器的权重);
  • 如果我生成的随机数是10,那么落到C服务器,因为10>2(A服务器的权重),10-2(A服务器的权重)=8,8>7(B服务器的权重),8-7(B服务器的权重)=1, 1<=1(C服务器的权重)。


也许,光看文字描述还是不够清楚,可以结合下面丑到爆炸的图片来理解下:

image.png

  • 如果生成的随机数是5,那么落到第二块区域;
  • 如果生成的随机数是10,那么落到第三块区域。


代码如下:

public class WeightRandom {
    static Servers servers = new Servers();
    static Random random = new Random();
    public static String go() {
       int allWeight = servers.map.values().stream().mapToInt(a -> a).sum();
        var number = random.nextInt(allWeight);
        for (var item : servers.map.entrySet()) {
            if (item.getValue() >= number) {
                return item.getKey();
            }
            number -= item.getValue();
        }
       return "";
    }
    public static void main(String[] args) {
        for (var i = 0; i < 15; i++) {
            System.out.println(go());
        }
    }
}

运行结果:

image.png

这种实现方式虽然相对第一种实现方式比较“绕”,但却是一种比较好的实现方式, 对内存没有浪费,权重大小和服务器List的Size也没有关系。

-     轮询    -


轮询又分为三种:完全轮询、加权轮询和平滑加权轮询。


1、完全轮询

public class FullRound {
    static Servers servers = new Servers();
    static int index;
    public static String go() {
        if (index == servers.list.size()) {
            index = 0;
        }
        return servers.list.get(index++);
    }
    public static void main(String[] args) {
        for (var i = 0; i < 15; i++) {
            System.out.println(go());
        }
    }
}

运行结果:

image.png

完全轮询,也是比较简单的,但是问题和完全随机是一样的,所以出现了加权轮询。

相关实践学习
部署高可用架构
本场景主要介绍如何使用云服务器ECS、负载均衡SLB、云数据库RDS和数据传输服务产品来部署多可用区高可用架构。
负载均衡入门与产品使用指南
负载均衡(Server Load Balancer)是对多台云服务器进行流量分发的负载均衡服务,可以通过流量分发扩展应用系统对外的服务能力,通过消除单点故障提升应用系统的可用性。 本课程主要介绍负载均衡的相关技术以及阿里云负载均衡产品的使用方法。
目录
相关文章
|
1月前
|
负载均衡 算法
ribbon的7种负载均衡算法和替换方法
ribbon的7种负载均衡算法和替换方法
51 0
ribbon的7种负载均衡算法和替换方法
|
1月前
|
负载均衡 算法 应用服务中间件
面试题:Nginx有哪些负载均衡算法?Nginx位于七层网络结构中的哪一层?
字节跳动面试题:Nginx有哪些负载均衡算法?Nginx位于七层网络结构中的哪一层?
66 0
|
4天前
|
负载均衡 算法 调度
负载均衡算法概述
负载均衡算法概述
|
1月前
|
负载均衡 算法 调度
负载均衡原理及算法
负载均衡原理及算法
24 1
|
1月前
|
负载均衡 算法 Java
Ribbon自定义负载均衡算法
Ribbon自定义负载均衡算法
27 1
|
1月前
|
弹性计算 负载均衡 算法
负载均衡调度算法
负载均衡调度算法介绍
44 2
|
1月前
|
负载均衡 算法
软件体系结构 - 负载均衡算法
软件体系结构 - 负载均衡算法
23 4
|
1天前
|
算法
基于GA遗传优化的混合发电系统优化配置算法matlab仿真
**摘要:** 该研究利用遗传算法(GA)对混合发电系统进行优化配置,旨在最小化风能、太阳能及电池储能的成本并提升系统性能。MATLAB 2022a用于实现这一算法。仿真结果展示了一系列图表,包括总成本随代数变化、最佳适应度随代数变化,以及不同数据的分布情况,如负荷、风速、太阳辐射、弃电、缺电和电池状态等。此外,代码示例展示了如何运用GA求解,并绘制了发电单元的功率输出和年变化。该系统原理基于GA的自然选择和遗传原理,通过染色体编码、初始种群生成、适应度函数、选择、交叉和变异操作来寻找最优容量配置,以平衡成本、效率和可靠性。
|
2天前
|
机器学习/深度学习 算法
基于鲸鱼优化的knn分类特征选择算法matlab仿真
**基于WOA的KNN特征选择算法摘要** 该研究提出了一种融合鲸鱼优化算法(WOA)与K近邻(KNN)分类器的特征选择方法,旨在提升KNN的分类精度。在MATLAB2022a中实现,WOA负责优化特征子集,通过模拟鲸鱼捕食行为的螺旋式和包围策略搜索最佳特征。KNN则用于评估特征子集的性能。算法流程包括WOA参数初始化、特征二进制编码、适应度函数定义(以分类准确率为基准)、WOA迭代搜索及最优解输出。该方法有效地结合了启发式搜索与机器学习,优化特征选择,提高分类性能。
|
2天前
|
机器学习/深度学习 算法 数据可视化
基于BP神经网络的64QAM解调算法matlab性能仿真
**算法预览图省略** MATLAB 2022A版中,运用BP神经网络进行64QAM解调。64QAM通过6比特映射至64复数符号,提高数据速率。BP网络作为非线性解调器,学习失真信号到比特的映射,对抗信道噪声和多径效应。网络在处理非线性失真和复杂情况时展现高适应性和鲁棒性。核心代码部分未显示。

热门文章

最新文章