一、概要

随着系统日益庞大、逻辑业务越来越复杂,系统架构由原来的单一系统到垂直系统,发展到现在的分布式系统。分布式系统中,可以做到公共业务模块的高可用,高容错性,高扩展性,然而,当系统越来越复杂时,需要考虑的东西自然也越来越多,要求也越来越高,比如服务路由、负载均衡等。此文将针对负载均衡算法进行讲解,不涉及具体的实现。

二、负载均衡算法

在分布式系统中,多台服务器同时提供一个服务,并统一到服务配置中心进行管理,消费者通过查询服务配置中心,获取到服务到地址列表,需要选取其中一台来发起RPC远程调用。如何选择,则取决于具体的负载均衡算法,对应于不同的场景,选择的负载均衡算法也不尽相同。负载均衡算法的种类有很多种,常见的负载均衡算法包括轮询法、随机法、源地址哈希法、加权轮询法、加权随机法、最小连接法、Latency-Aware等,应根据具体的使用场景选取对应的算法。

1、轮询(Round Robin)法

轮询很容易实现,将请求按顺序轮流分配到后台服务器上,均衡的对待每一台服务器,而不关心服务器实际的连接数和当前的系统负载。使用轮询策略的目的是,希望做到请求转移的绝对均衡,但付出的代价性能也是相当大的。为了保证pos变量的并发互斥,引入了重量级悲观锁synchronized,将会导致该轮询代码的并发吞吐量明显下降。
轮询法适用于机器性能相同的服务,一旦某台机器性能不好,极有可能产生木桶效应,性能差的机器扛不住更多的流量。

2、随机法

通过系统随机函数,根据后台服务器列表的大小值来随机选取其中一台进行访问。由概率概率统计理论可以得知,随着调用量的增大,其实际效果越来越接近于平均分配流量到后台的每一台服务器,也就是轮询法的效果。
同样地,它也不适用于机器性能有差异的分布式系统。

3、随机轮询法

所谓随机轮询,就是将随机法和轮询法结合起来,在轮询节点时,随机选择一个节点作为开始位置index,此后每次选择下一个节点来处理请求,即(index+1)%size。
这种方式只是在选择第一个节点用了随机方法,其他与轮询法无异,缺点跟轮询一样。

4、源地址哈希法

源地址哈希法的思想是根据服务消费者请求客户端的IP地址,通过哈希函数计算得到一个哈希值,将此哈希值和服务器列表的大小进行取模运算,得到的结果便是要访问的服务器地址的序号。采用源地址哈希法进行负载均衡,相同的IP客户端,如果服务器列表不变,将映射到同一个后台服务器进行访问。该方法适合访问缓存系统,如果为了增强缓存的命中率和单调性,可以用一致性哈希算法,相关博文在https://blog.csdn.net/okiwilldoit/article/details/51352743

5、加权轮询(Weight Round Robin)法

不同的后台服务器可能机器的配置和当前系统的负载并不相同,因此它们的抗压能力也不一样。跟配置高、负载低的机器分配更高的权重,使其能处理更多的请求,而配置低、负载高的机器,则给其分配较低的权重,降低其系统负载,加权轮询很好的处理了这一问题,并将请求按照顺序且根据权重分配给后端。Nginx的负载均衡默认算法是加权轮询算法

Nginx负载均衡算法简介

有三个节点{a, b, c},他们的权重分别是{a=5, b=1, c=1}。发送7次请求,a会被分配5次,b会被分配1次,c会被分配1次。

一般的算法可能是:
1、轮训所有节点,找到一个最大权重节点;
2、选中的节点权重-1;
3、直到减到0,恢复该节点原始权重,继续轮询;
这样的算法看起来简单,最终效果是:{a, a, a, a, a, b, c},即前5次可能选中的都是a,这可能造成权重大的服务器造成过大压力的同时,小权重服务器还很闲。
Nginx的加权轮询算法将保持选择的平滑性,希望达到的效果可能是{a, b, a, a, c, a, a},即尽可能均匀的分摊节点,节点分配不再是连续的。

Nginx加权轮询算法

1、概念解释,每个节点有三个权重变量,分别是:
(1) weight: 约定权重,即在配置文件或初始化时约定好的每个节点的权重。
(2) effectiveWeight: 有效权重,初始化为weight。
在通讯过程中发现节点异常,则-1;
之后再次选取本节点,调用成功一次则+1,直达恢复到weight;
此变量的作用主要是节点异常,降低其权重。
(3) currentWeight: 节点当前权重,初始化为0。

2、算法逻辑
(1) 轮询所有节点,计算当前状态下所有节点的effectiveWeight之和totalWeight;
(2) currentWeight = currentWeight + effectiveWeight; 选出所有节点中currentWeight中最大的一个节点作为选中节点;
(3) 选中节点的currentWeight = currentWeight - totalWeight;

基于以上算法,我们看一个例子:
这时有三个节点{a, b, c},权重分别是{a=4, b=2, c=1},共7次请求,初始currentWeight值为{0, 0, 0},每次分配后的结果如下:

观察到七次调用选中的节点顺序为{a, b, a, c, a, b, a},a节点选中4次,b节点选中2次,c节点选中1次,算法保持了currentWeight值从初始值{c=0,b=0,a=0}到7次调用后又回到{c=0,b=0,a=0}。
参考文档为:https://www.cnblogs.com/markcd/p/8456870.html

6、加权随机(Weight Random)法

加权随机法跟加权轮询法类似,根据后台服务器不同的配置和负载情况,配置不同的权重。不同的是,它是按照权重来随机选取服务器的,而非顺序。

7、最小连接数法

前面我们费尽心思来实现服务消费者请求次数分配的均衡,我们知道这样做是没错的,可以为后端的多台服务器平均分配工作量,最大程度地提高服务器的利用率,但是,实际上,请求次数的均衡并不代表负载的均衡。因此我们需要介绍最小连接数法,最小连接数法比较灵活和智能,由于后台服务器的配置不尽相同,对请求的处理有快有慢,它正是根据后端服务器当前的连接情况,动态的选取其中当前积压连接数最少的一台服务器来处理当前请求,尽可能的提高后台服务器利用率,将负载合理的分流到每一台服务器。

8、Latency-Aware

与方法7类似,该方法也是为了让性能强的机器处理更多的请求,只不过方法7使用的指标是连接数,而该方法用的请求服务器的往返延迟(RTT),动态地选择延迟最低的节点处理当前请求。该方法的计算延迟的具体实现可以用EWMA算法来实现,它使用滑动窗口来计算移动平均耗时。具体代码如下:

public class EWMA {private static final long serialVersionUID = 2979391326784043002L;//时间类型枚举public static enum Time {MICROSECONDS(1),MILLISECONDS(1000),SECONDS(MILLISECONDS.getTime() * 1000),MINUTES(SECONDS.getTime() * 60),HOURS(MINUTES.getTime() * 60),DAYS(HOURS.getTime() * 24),WEEKS(DAYS.getTime() * 7);private long micros;private Time(long micros) {this.micros = micros;}public long getTime() {return this.micros;}}//三个alpha常量,这些值和Unix系统计算负载时使用的标准alpha值相同public static final double ONE_MINUTE_ALPHA = 1 - Math.exp(-5d / 60d / 1d);public static final double FIVE_MINUTE_ALPHA = 1 - Math.exp(-5d / 60d / 5d);public static final double FIFTEEN_MINUTE_ALPHA = 1 - Math.exp(-5d / 60d / 15d);private long window;private long alphaWindow;private long last;private double average;private double alpha = -1D;private boolean sliding = false;private long requests;//请求量private double weight;//权重public EWMA() {}public EWMA sliding(double count, Time time) {return this.sliding((long) (time.getTime() * count));}public EWMA sliding(long window) {this.sliding = true;this.window = window;return this;}public EWMA withAlpha(double alpha) {if (!(alpha > 0.0D && alpha <= 1.0D)) {throw new IllegalArgumentException("Alpha must be between 0.0 and 1.0");}this.alpha = alpha;return this;}public EWMA withAlphaWindow(long alphaWindow) {this.alpha = -1;this.alphaWindow = alphaWindow;return this;}public EWMA withAlphaWindow(double count, Time time) {return this.withAlphaWindow((long) (time.getTime() * count));}/*** 默认使用当前时间更新移动平均值*/public void mark(){mark(System.currentTimeMillis());}/*** 更新移动平均值* @param time*/public void mark(long time){if(this.sliding){//如果发生时间间隔大于窗口,则重置滑动窗口if(time-this.last > this.window){this.last = 0;}}if(this.last == 0){this.average = 0;this.requests = 0;this.last = time;}// 计算上一次和本次的时间差long diff = time - this.last;// 计算alphadouble alpha = this.alpha != -1.0 ? this.alpha : Math.exp(-1.0*((double)diff/this.alphaWindow));// 计算当前平均值this.average = (1.0-alpha)*diff + alpha*this.average;this.last = time;// 请求量加1this.requests++;// 计算权重值// this.weight = this.average != 0 ? this.requests/this.average : -1;}//返回mark()方法多次调用的平均值public double getAverage() {return this.average;}//按照特定的时间单位来返回平均值,单位详见Time枚举public double getAverageIn(Time time) {return this.average == 0.0 ? this.average : this.average / time.getTime();}//返回特定时间度量内调用mark()的频率public double getAverageRatePer(Time time) {return this.average == 0.0 ? this.average : time.getTime() / this.average;}//返回mark()方法多次调用的权重值public double getWeight() {return this.weight;}public long getRequests() {return this.requests;}public static   void main(String[] args) {//建立1分钟滑动窗口EWMA实例EWMA ewma = new EWMA().sliding(1.0, Time.MINUTES).withAlpha(EWMA.ONE_MINUTE_ALPHA).withAlphaWindow(1.0, EWMA.Time.MINUTES);int randomSleep = 0;long markVal = System.currentTimeMillis() * 1000;//单位为微秒try {ewma.mark(markVal);for (int i = 1; i <= 10000000; i++) {randomSleep = util.get_rand_32() % 1500;markVal += randomSleep;ewma.mark(markVal);if (i % 1000 == 0) {System.out.println("Round: " + i + ", Time: " + randomSleep+ ", Requests: " + ewma.getRequests()+ ", Average: " + ewma.getAverage()+ ", Weight:" + ewma.getWeight());}}}catch (Exception e) {e.printStackTrace();}}
}

Twitter的负载均衡算法基于这种思想,不过实现起来更加简单,即P2C算法。首先随机选取两个节点,在这两个节点中选择延迟低,或者连接数小的节点处理请求,这样兼顾了随机性,又兼顾了机器的性能,实现很简单。
具体参见:https://linkerd.io/1/features/load-balancing/。

分布式系统常见负载均衡算法相关推荐

  1. 算法高级(12)-分布式系统常见负载均衡算法

    负载均衡这个话题比较大,一篇估计说不完,今天先来第一篇. 一.负载均衡介绍 [百度百科]负载均衡,英文名称为Load Balance,其含义就是指将负载(工作任务)进行平衡.分摊到多个操作单元上进行运 ...

  2. 算法高级(13)-常见负载均衡算法Java代码实现

    我们在分布式系统常见负载均衡算法中对负载均衡及负载均衡算法进行了介绍,接下来我们用代码对常见的几种算法进行实现. 本文讲述的是"将外部发送来的请求均匀分配到对称结构中的某一台服务器上&quo ...

  3. 负载均衡轮询算法和服务器性能,负载均衡算法

    对于要实现高性能集群,选择好负载均衡器很重要,同时针对不同的业务场景选择合适的负载均衡算法也是非常重要的. 一.负载均衡算法分类 任务平分类 负载均衡系统将收到的任务平均分配给服务器进行处理,这里的& ...

  4. 服务器负载均衡算法之哈希算法

    文章目录 1.一致性哈希算法的问题 2.哈希算法的应用场景 3.如何分配请求? 4.加权轮询算法解决负载均衡问题 5.哈希算法带来的问题 6.一致性哈希算法带来的问题 7.虚拟节点提高一致性哈希算法的 ...

  5. Java实现基于Socket的负载均衡代理服务器(含六种负载均衡算法)

    目录 前言 一.常见负载均衡算法 1.完全轮询算法 2.加权轮询算法 3.完全随机算法 4.加权随机算法 5.余数Hash算法 6.一致性Hash算法 二.代码实现 1.项目结构 2.代码实现 总结 ...

  6. 负载均衡算法 — 轮询

    负载均衡算法 - 轮询 目录 概述 简单轮询 加权轮询 平滑加权轮询 1. 概述 在分布式系统中,为了实现负载均衡,必然会涉及到负载调度算法,如 Nginx 和 RPC 服务发现等场景.常见的负载均衡 ...

  7. 后宫佳丽三千,假如古代皇帝也懂负载均衡算法...

    古代皇帝,后宫佳丽三千,没法做到雨露均沾,但为了繁衍后代,子嗣繁盛,弱水三千,只取一瓢饮显然是不行的.不同的朝代有不同的宠幸妃子的方法,著名的有羊车望幸.掷筛侍寝.翻牌悬灯等等.如果皇帝懂得负载均衡算 ...

  8. 负载均衡算法--轮询法(Round Robin)

    在分布式系统中,为了实现系统的高性能.高并发.高可用,在构架中都会进行负载均衡设计,它是分布式系统的核心和中枢,负载均衡的好坏直接影响着整个系统的性能.负载均衡分为软件均衡和硬件均衡两类,比如apac ...

  9. 集群,分布式,负载均衡,负载均衡算法

    集群 集群的概念 计算机集群通过一组松散集成的计算机软件和/或硬件连接起来高度紧密地协作完成计算工作.在某种意义上,他们可以被看作是一台计算机.集群系统中的单个计算机通常称为节点,通常通过局域网连接, ...

最新文章

  1. moss2007 权限体系分析(深入到数据库结构的分析)
  2. Pet Shop4解密配置文件
  3. 鸿蒙可胜安卓,【鸿蒙币谈】币圈投资中八大见顶信号,让你抓住最佳买卖机会!...
  4. 虚拟交换机软件_H3C交换机IRF配置介绍
  5. ASP.NET MVC Music Store教程(2):控制器
  6. ticket进行urlencode是什么意思_request请求中进行url转码,结果意想不到,python爬虫(2)...
  7. Microsoft Enterprise Library 5.0 系列(四) Logging Application Block
  8. 优秀的程序员是如何处理技术 Bug 的?
  9. laravel使用dompdf总结
  10. 成功解决3dmax中,旋转时透视图可以看穿物体
  11. 物联网是什么,和互联网之间主要有什么区别
  12. Pyramidal Convolution: Rethinking Convolutional Neural Networks for Visual Recognition阅读笔记
  13. google 语音识别 VS 百度语音识别
  14. 【ABAP】采购订单行项目 税码 自动默认
  15. 手把手教你部署Docker(手撸官网)
  16. 小火狐进化_《乐贝星空》宠物大全 解析小火狐三阶进化
  17. 如何在 Web 浏览器中启用 Java?
  18. 小米6刷Ubuntu Touch系统
  19. 极具参考价值的Python面试题!从创业公司到一线大厂的所有面经汇总
  20. Android 开源的UI框架

热门文章

  1. 【2017年第2期】开发商业智能应用 小心大数据“陷阱”
  2. ZZULIOJ:1171:加密
  3. 微信小程序 --- 绘画
  4. 面向对象方法中的数据库设计
  5. define定义常量和宏 以及 寄存器关键字register
  6. 【整理】MSbuild
  7. Plan for the day
  8. 从Java到ObjC语言的桥梁:谷歌J2ObjC 0.7版本亮相
  9. 苹果试玩换个新id行不_【图】- 苹果试玩无限刷论坛 app试玩能换个id继续么 - 枣庄市中其他服务 - 枣庄百姓网...
  10. vue 基础 —— html版的 Vue 入门基础