负载均衡算法浅谈

Random LoadBalance

随机算法,顾名思义,当有大量请求时,根据概率学可以知道每一台服务器分配的流量基本会均等。
广义版本是加权随机算法,需要思考的问题是,如何让请求根据权重随机分配到多个服务器上?
当不考虑权重的时候,如果有n个服务器,可以用randomInt(n)的方式生成随机数,随机数即对应相应server的ID。
当需要考虑权重的时候,可以按将权重的和当成虚拟服务器的数量,比如有三个服务器a,b,c,权重分别为(1,2,3)。可以认为有6台虚拟服务器在提供服务,分别是(a,b1,b2,c1,c2,c3),然后生成随机数randomInt(6),并按此数字选择服务器。选到虚拟服务器c1,c2,c3时实际上都会将请求分配到c服务器。
Dubbo实现的是加权随机算法,并将这种算法设置为默认采取的负载均衡策略。

RoundRobin LoadBalance

轮转法,服务器排成一个圈,顺着往下一个个点,点到谁谁服务。一圈转完再来一圈,稳定的公平分配。
轮转法也有加权版本,加权的目的是将请求按权重分配到每个服务器中,比如我们有服务器对应的权重a(1), b(2), c(3);那么总权重是6,我们可以简单的生成序列(a,b,b,c,c,c)(a,b,b,c,c,c)...,这样每有6个请求就会1个请求到a,2个请求到b,三个请求到c,从而实现了请求按权重分配。
这个序列的缺陷在于有连续的请求压在一台服务器,我们更希望序列是类似(c,a,b,c,b,c)这样交叉的序列。6个请求中仍然有一个到a,两个到b,三个到c,但分布更为均匀。
如何实现这样更为均匀的序列呢?如果暴力解这个问题,可以将序列(a,b,b,c,c,c)人工随机打乱后存储在调度服务器中,这样服务器就会按指定的序列调度。这种方式的问题在于需要调度服务器存储一个可能是非常巨大的序列。
暴力解通常采取数学的方式来优化。RoundRobin也需要需要寻找一种数学运算,它能够生成一个均匀的序列,并且不需要调度服务器维护过多的状态。
这里介绍一种轮转序列生成的方式,背后的数学原理和验证不做深究。
smooth weighted round-robin balancing
平滑加权轮转均衡,nginx中使用的算法。我们用peer表示负载服务器,调度服务器需要为每个peer维护三个变量:权重,有效权重及当前权重
peer(weight, effective_weight, current_weight)
weight及配置中指定的服务器权重,effective_weight初始值是weight,为了实现动态调整,effective_weight会由于出现调用错误时减小,调用成功时增加,从而可以实现权重动态调整。当前权重初始值0,此值用于实现我们需要生成的序列。
具体算法如下

public class LoadBalanceTest {

  public static class Peer {

    String name;
    int weight;
    int effectiveWeight;
    int currentWeight;

    Peer(String name, int weight) {
      this.name = name;
      this.weight = weight;
      this.effectiveWeight = weight;
      this.currentWeight = 0;
    }

    @Override
    public String toString() {
      return "[" + this.weight + "," + this.effectiveWeight + ","
          + this.currentWeight + "]";
    }
  }

  @Test
  public void testRoundRobin() {
    List<Peer> peers = new ArrayList<>();
    peers.add(new Peer("a", 1));
    peers.add(new Peer("b", 2));
    peers.add(new Peer("c", 3));

    int n_REQUESTS = 12;
    for (int i = 0; i < n_REQUESTS; i++) {
      int total = 0;
      int max = -1;
      int index = 0;
      for (int j = 0; j < peers.size(); j++) {
        Peer peer = peers.get(j);
        peer.currentWeight += peer.effectiveWeight;
        total += peer.effectiveWeight;
        if (peer.currentWeight > max) {
          max = peer.currentWeight;
          index = j;
        }
      }
      peers.get(index).currentWeight -= total;
      System.out.print("select: " + peers.get(index).name + " ");
      System.out.println("state: " + peers);
    }
  }
}

输出结果为:

select: c state: [1,1,1] [2,2,2] [3,3,-3] 
select: b state: [1,1,2] [2,2,-2] [3,3,0] 
select: a state: [1,1,-3] [2,2,0] [3,3,3] 
select: c state: [1,1,-2] [2,2,2] [3,3,0] 
select: b state: [1,1,-1] [2,2,-2] [3,3,3] 
select: c state: [1,1,0] [2,2,0] [3,3,0] 
-----------------------------------------------
select: c state: [1,1,1] [2,2,2] [3,3,-3] 
select: b state: [1,1,2] [2,2,-2] [3,3,0] 
select: a state: [1,1,-3] [2,2,0] [3,3,3] 
select: c state: [1,1,-2] [2,2,2] [3,3,0] 
select: b state: [1,1,-1] [2,2,-2] [3,3,3] 
select: c state: [1,1,0] [2,2,0] [3,3,0] 

LeastActive LoadBalance

前面两种负载均衡算法只为服务器分配了固定了权重,而没有考虑服务器当前的处理状态。比如当一个服务器收到一个耗时的请求导致服务器处于高负载状态,而之前的两种负载均衡算法对此并无感知。我们希望提供一种算法能考虑到服务器当前的状态来分配请求。
LeastActive LoadBalance根据服务器的活跃数来分配请求,使得慢的服务提供者收到更少的请求。从而让请求能根据服务器的当前状态来动态分配。
活跃数可以理解成服务器当前正在处理的请求的个数。比如我们有a,b两台服务器,a正在处理3个请求,b正在处理2个请求。那么a的活跃数是3,b的活跃数是2。如果再来一个请求,我们需要选择的服务器是b。
这里仍然可以加入考虑服务器a,b的权重。当有多个服务器的活跃数相同时,这几个服务器中的负载均衡可以退化成使用加权随机算法。

ConsistentHash LoadBalance

最后谈到鼎鼎大名的一致性哈希算法。
前面提到的三种算法都只考虑了服务器的状态和特性(权重),而没有考虑到请求本身的特性。比如有一个根据ID加载数据的服务,服务提供者会在请求时将相应数据在服务器上缓存一段时间。在这种应用场景中,我们希望将相同ID的请求分配到同一台服务器,从而实现服务加速。前面的三种均衡算法都无法满足这种需求。
要将请求根据ID定向到某台服务器,自然就需要应用到哈希。一个简单的思路是按哈希值取模,比如我们有3台服务器,那么按hash(ID)%3的方式,就能将请求分配到三台服务器。从而按请求ID来分发到服务器。
这样简单的哈希算法有什么问题呢?我们需要考虑到现实环境是残酷的,计算机运行环境会因为网络分区无法访问,服务也有可能会crash。使用这种简单的算法,如果三台服务器中如果有一台服务器crash掉,所有对应的ID的请求都无法获得服务,这显然不是我们希望的结果。为了实现服务的可用性,我们希望在一台服务器crash掉的时候,自动的将对应的ID的请求分配到其他的可用服务器上。
hash(ID)%3这种分发方式中,我们采用了模除的方法决定了哈希值是如何对应到服务器上的。我们可以采用其他的对应方式。哈希值的区间是0~90,我们可以给定如下的对应关系
0~30 -> a
31~60 ->b
61~90 -> c
这种对应方式就可以完成我们采用hash(ID)%3实现的分发功能,需要增加的代价是每台服务器需要存储两个值对应其hash空间,这种代价是可以接受的。
在这种分发模式下,如何应对某台服务器不可用呢?一个简单的方案是如果一个服务器cash,将对应于它的请求转移到下一台服务器中。比如当a服务器crash掉时,分发的对应关系转变成
0~60 -> b
61~90 -> c
如果是c服务器crash,分发的对应关系转变成
61~90, 0~30 -> a
31~60 -> b
即我们将a,b,c看成了一个环形的关系,每当一个服务器crash时,将对应其的请求转移到下一台服务器中,从而实现服务的可用性。
这里有一个显然的违反直觉的缺陷,如果a服务器crash掉,我们更希望采取的方式是将原来对应于a的请求平均分派到b,c上,而不是将全部压力转移到b服务器。
如何实现呢?回到Random balance算法中,我们采用了虚拟服务器的思路,将一台服务器可以看成多台服务器。在这里,是不是可以采用同样的思路呢,我们采取如下的分派策略
0~15 -> a1
15~30 - a2
31~60 ->b
61~90 -> c
此时如果a服务器crash请求仍然会全部转移到b服务器。但如果调整一下顺序
0~15 -> a1
16~45 -> b
46~60 -> a2
61~90 -> c
这中分派模式下,如果a服务器crash压力就会平均转移到b,c上,从而满足了我们的需求。
这就是一致性哈希算法。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,478评论 5 467
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,825评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,482评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,726评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,633评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,018评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,513评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,168评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,320评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,264评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,288评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,995评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,587评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,667评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,909评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,284评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,862评论 2 339

推荐阅读更多精彩内容

  • 常见的负载均衡算法 轮询法(Round Robin) 加权轮询(Weight Round Robin) 随机算法(...
    luoyoub阅读 637评论 0 1
  • 【摘要】 面对大量用户访问、高并发请求,海量数据,可以使用高性能的服务器、大型数据库,存储设备,高性能Web服务器...
    静修佛缘阅读 4,521评论 0 24
  • 一直想写出来,身为一位母亲,我真的很失败。 我一直犹豫着要不要写出来。在倍受煎熬后,我还是决定...
    丁香女人阅读 1,380评论 28 17
  • 最新有拍照的需求是这样的 ~ 手动点击屏幕聚焦,聚焦完成之后就自动拍照 于是开始各种脑补,在别人的基本拍照框架上进...
    MakeThatChange阅读 11,968评论 26 26
  • 大学,是职场的预科班 大二,要上职业规划课,老师建议我们去参观下学校毕业的招聘会。 职业规划书写了一半,跑去操场参...
    陈多芬阅读 156评论 1 0