前往顾页
以后地位: 主页 > 收集编程 > .Net实例教程 >

负载均衡的总结与思虑

时候:2018-01-09 23:23来源:知行网www.zhixing123.cn 编辑:麦田守望者

所谓负载均衡,就是说如果一组计较机节点(或一组过程)供应不异的(同质的)办事,那么对办事的请求就应当均匀的分摊到这些节点上。负载均衡的前提必然是“provide a single Internet service from multiple servers”, 这些供应办事的节点被称之为server farm、server pool或backend servers。

这里的办事是狭义的,可所以简朴的计较,也多是数据的读取或存储。负载均衡也不是新事物,这类思惟在多核CPU期间就有了,只不过在漫衍式体系中,负载均衡更是无处不在,这是漫衍式体系的自然特性决定的,漫衍式就是操纵年夜量计较机节点完成单个计较机无法完成的计较、存储办事,既然丰年夜量计较机节点,那么均衡的调剂就非常首要。

负载均衡的意义在于,让所有节点以最小的代价、最好的状况对外供应办事,如许体系吞吐量最年夜,机能更高,对用户而言请求的时候也更小。并且,负载均衡加强了体系的可靠性,最年夜化降落了单个节点过载、乃至crash的概率。不难想象,如果一个体系绝年夜部分请求都落在同一个节点上,那么这些请求呼应时候都很慢,并且万一节点升级或崩溃,那么所有请求又会转移到下一个节点,造成雪崩。

究竟上,网上有很多文章介绍负载均衡的算法,年夜多都是年夜同小异。本文更多的是本身对这些算法的总结与思虑。

 

一分钟体味负载均衡的一切

图0:关于负载均衡的一切:总结与思考

 

 

常见互联网漫衍式架构如上,分为客户端层、反向代办代理nginx层、站点层、办事层、数据层。可以看到,每个下流都有多个上游调用,只需求做到,每个上游都均匀拜候每个下流,就可以实现“将请求/数据【均匀】分摊到多个操纵单位上履行”。

(1)【客户端层〗】稻反向代办代理层】的负载均衡,是经由过程“DNS轮询”实现的
(2)【反向代办代理层〗】稻站点层】的负载均衡,是经由过程“nginx”实现的
(3)【站点层〗】稻办事层】的负载均衡,是经由过程“办事连接池”实现的
(4)【数据层】的负载均衡,要考虑“数据的均衡”与“请求的均衡”两个点,常见的体例有“遵循范围程度切分”与“hash程度切分”。

数据层的负载均衡,在我之前的《带着问题学习漫衍式体系之数据分片》中有详细介绍。

 

算法衡量

在我看来,当我们提到一个负载均衡算法,或详细的利用处景时,应当考虑以下问题

第一,是不是意想到不合节点的办事才气是不一样的,比如CPU、内存、收集、地理地位

第二,是不是意想到节点的办事才气是静态转变的,高配的机器也有可能因为一些突发启事导致措置速率变得很慢

第三,是不是考虑将同一个客户端,或说一样的请求分发到同一个措置节点,这对“有状况”的办事非常首要,比如session,比如漫衍式存储

第四,谁来卖力负载均衡,即谁充当负载均衡器(load balancer),balancer本身是不是会成为瓶颈

下面会连络详细的算法来考虑这些问题

 

负载均衡算法

 

轮询算法(round-robin)

思惟很简朴,就是供应同质办事的节点一一对外供应办事,如许能做到绝对的均衡。Python示例代码以下

 1 SERVER_LIST = [
 2     '10.246.10.1',
 3     '10.246.10.2',
 4     '10.246.10.3',
 5 ]
 6 def round_robin(server_lst, cur = [0]):
 7     length = len(server_lst)
 8     ret = server_lst[cur[0] % length]
 9     cur[0] = (cur[0] + 1) % length
10     return ret

可以看到,所有的节点都是以一样的概率供应办事,即没有考虑到节点的差别,或许一样数量标请求,高配的机器CPU才20%,低配的机器CPU已80%了

 

加权轮询算法(weight round-robin)

加权轮训算法就是在轮训算法的根本上,考虑到机器的差别性,分派给机器不合的权重,能者多劳。重视,这个权重的分派依靠于请求的范例,比如计较麋集型,那就考虑CPU、内存;如果是IO麋集型,那就考虑磁盘机能。Python示例代码以下

 1 WEIGHT_SERVER_LIST = {
 2     '10.246.10.1': 1,
 3     '10.246.10.2': 3,
 4     '10.246.10.3': 2,
 5 }
 6 
 7 def weight_round_robin(servers, cur = [0]):
 8     weighted_list = []
 9     for k, v in servers.iteritems():
10         weighted_list.extend([k] * v)
11 
12     length = len(weighted_list)
13     ret = weighted_list[cur[0] % length]
14     cur[0] = (cur[0] + 1) % length
15     return ret

 

随机算法(random)

这个就更好了解了,随机挑选一个节点办事,遵循概率,只需请求数量充足多,那么也能到达绝对均衡的结果。并且实现简朴很多

1 def random_choose(server_lst):
2     import random
3     random.seed()
4     return random.choice(server_lst)

 

加权随机算法(random)

如同加权轮训算法至于轮训算法一样,也是在随机的时候引入不合节点的权重,实现也很近似。

def weight_random_choose(servers):
    import random
    random.seed()
    weighted_list = []
    for k, v in servers.iteritems():
        weighted_list.extend([k] * v)
    return random.choice(weighted_list)

当然,如果节点列表和权重转变不年夜,那么也能够对所有节点归一化,然后按概率区间挑选

1 def normalize_servers(servers):
2 normalized_servers = {}
3 total = sum(servers.values())
4 cur_sum = 0
5 for k, v in servers.iteritems():
6 normalized_servers[k] = 1.0 * (cur_sum + v) / total
7 cur_sum += v
8 return normalized_servers
9
10 def weight_random_choose_ex(normalized_servers):
11 import random, operator
12 random.seed()
13 rand = random.random()
14 for k, v in sorted(normalized_servers.iteritems(), key = operator.itemgetter(1)):
15 if v >= rand:
16 return k
17 else:
18 assert False, 'Error normalized_servers with rand %s ' % rand
 

哈希法(hash)

按照客户端的IP,或请求的“Key”,计较出一个hash值,然后对节点数量取模。好处就是,同一个请求可以或许分派到一样的办事节点,这对“有状况”的办事很有需求

1 def hash_choose(request_info, server_lst):
2     hashed_request_info = hash(request_info)
3     return server_lst[hashed_request_info % len(server_lst)]

只需hash成果充足分离,也是能做到绝对均衡的。

 

分歧性哈希

哈希算法的缺点也很较着,当节点的数量产生转变的时候,请求会年夜概率分派到其他的节点,激发到一系列问题,比如sticky session。并且在某些环境,比如漫衍式存储,是绝对的不许可的。

为体味决这个哈希算法的问题,又引入了分歧性哈希算法,简朴来讲,一个物理节点与多个假造节点映照,在hash的时候,利用假造节点数量而不是物理节点数量。当物理节点转变的时候,假造节点的数量无需转变,只触及到假造节点的从头分派。并且,调剂每个物理节点对应的假造节点数量,也就相当于每个物理节点有不合的权重

 

起码连接算法(least connection)

以上的诸多算法,要么没有考虑到节点间的差别(轮训、随机、哈希),要么节点间的权重是静态分派的(加权轮训、加权随机、分歧性hash)。

考虑这么一种环境,某台机器呈现毛病,无法及时措置请求,但新的请求还是会以必然的概率源源不竭的分派到这个节点,造成请求的积存。是以,按照节点的实在负载,静态地调剂节点的权重就非常首要。当然,要获得接节点的实在负载也不是等量齐观的事情,若何定义负载,负载的汇集是不是及时,这都是需求考虑的问题。

每个节点以后的连接数量是一个非常容易汇集的目标,是以lease connection是最常被人提到的算法。也有一些侧重不合或更复杂、更客观的目标,比如最小呼应时候(least response time)、最小活泼数(least active)等等。

 

一点思虑

 

有状况的请求

起首来看看“算法衡量”中提到的第三个问题:同一个请求是不是分发到一样的办事节点,同一个请求指的是同一个用户或一样的独一标示。甚么时候同一请求最好(必须)分发到一样的办事节点呢?那就是有状况 — 请求依靠某些存在于内存或磁盘的数据,比如web请求的session,比如漫衍式存储。怎样实现呢,有以下几种体例:

(1)请求分发的时候,包管同一个请求分发到一样的办事节点。

这个依靠于负载均衡算法,比如简朴的轮训,随机必定是不可的,哈希法在节点增删的时候也会见效。可行的是分歧性hash,和漫衍式存储中的按范围分段(即记录哪些请求由哪个办事节点供应办事),代价是需求在load balancer中保护分外的数据。

(2)状况数据在backend servers之间共享

包管同一个请求分发到一样的办事节点,这个只是手段,目标是请求能利用到对应的状况数据。如果状况数据可以或许在办事节点之间共享,那么也能到达这个目标。比如办事节点连接到共享数据库,或内存数据库如memcached

(3)状况数据保护在客户端

这个在web请求中也无益用,即cookie,不过要考虑宁静性,需求加密。

 

关于load balancer

接上去答复第四个问题:关于load balancer,其实就是说,在那里做负载均衡,是客户端还是办事端,是请求的建议者还是请求的3。详细而言,要么是在客户端,按照办事节点的信息自行挑选,然后将请求直接发送到选中的办事节点;要么是在办事节点集群之前放一个集合式代办代理(proxy),由代办代理卖力请求求分发。不管哪一种,起码都需求晓得以后的办事节点列表这一根本信息。

如果在客户端实现负载均衡,客户端起首得晓得办事器列表,要么是静态建设,要么有简朴接口查询,但backend server的详细负载信息,就不合用经由过程客户端来查询。是以,客户端的负载均衡算法要么是比较简朴的,比如轮训(加权轮训)、随机(加权随机)、哈希这几种算法,只需每个客户端充足随机,遵循年夜数定理,办事节点的负载也是均衡的。要在客户端利用较为复杂的算法,比如按照backend的实际负载,那么就需求去分外的负载均衡办事(external load balancing service)查询到这些信息,在grpc中,就是利用的这类体例

图1:关于负载均衡的一切:总结与思考

 

 

可以看到,load balancer与grpc server通信,获得grpc server的负载等详细详细,然后grpc client从load balancer获得这些信息,终究grpc client直连到被挑选的grpc server。

而基于Proxy的体例是更加常见的,比如7层的Nginx,四层的F5、LVS,既有硬件路由,也有软件分发。集合式的特性在于便利节制,并且能容易实现一些更紧密,更复杂的算法。但错误谬误也很较着,一来负载均衡器本身可能成为机能瓶颈;二来可能引入分外的延迟,请求必然先发到达负载均衡器,然后到达实在的办事节点。

load balance proxy对请求的呼应(response),要么不颠末proxy,如LVS;要么颠末Proxy,如Nginx。下图是LVS示企图(来源见水印)

图2:关于负载均衡的一切:总结与思考

 

 

而如果response也是走load balancer proxy的话,那么全部办事过程对客户端而言就是完整透明的,也避免了客户端去测验测验连接背景办事器,供应了一层宁静保证!

值得重视的是,load balancer proxy不克不及成为单点毛病(single point of failure),是以一般会设想为高可用的主从布局

 

其他

在这篇文章中提到,负载均衡是一种推模型,必然会选出一个办事节点,然后把请求推送过去。而换一种思路,利用动静队列,就变成了拉模型:余暇的办事节点主动去拉取请求进行措置,各个节点的负载自然也是均衡的。动静队列比拟负载均衡好处在于,办事节点不会被年夜量请求冲毁,同时增加办事节点更加容易;错误谬误也很较着,请求不是究竟措置的。

想到别的一个例子,比如在gunicorn这类pre-fork模型中,master(gunicorn 中Arbiter)会fork出指定命量的worker过程,worker过程在一样的端口上监听,谁先监听到收集连接请求,谁就供应办事,这也是worker过程之间的负载均衡

顶一下
(0)
0%
踩一下
(0)
0%
------分开线----------------------------
标签(Tag):负载均衡
------分开线----------------------------
颁发评论
请自发遵循互联网相关的政策法规,严禁公布色情、暴力、革命的谈吐。
评价:
神色:
考证码:点击我更换图片
猜你感兴趣