2023年7月19日发(作者:)
nginx负载均衡中常见的算法及原理nginx负载均衡中常见的算法及原理1. Nginx负载均衡中常见的算法1.1 轮询(round robin)轮询,依次将请求分配到各个后台服务器,默认⽅式。upstream backserver {
server 192.168.31.7;
server 192.168.31.8;
}
1.2 加权轮询(weight round robin)根据权重加权依次轮询,默认为1,实现类似于LVS中的WRR,WLC等.默认时和rr效果⼀样.upstream backserver {
server 192.168.31.7 weight=10;
server 192.168.31.8 weight=20;
}
1.3 源地址hash(ip_hash)源地址hash调度⽅法,基于的客户端的remote_addr(源地址IPv4的前24位或整个IPv6地址)做hash计算,以实现会话保持.upstream backserver {
ip_hash;server 192.168.31.7;
server 192.168.31.8;
}
1.4 ⽬的Url hash(url_hash)hash $request_uri consistent;根据请求的url的hash值分配服务器,当后台服务器为缓存时,效率较⾼.upstream backserver {
consistent_hash $remote_addr;server 192.168.31.7;
server 192.168.31.8;
}
1.5 最少连接数(least_conn)least_conn;最少连接调度算法,优先将客户端请求调度到当前连接最少的后端服务器,相当于LVS中的WLCupstream backserver {
least_conn;server 192.168.31.7;
server 192.168.31.8;
}
1.6 最快响应时间(fair)根据服务器响应时间来分发,响应时间短,分发越多。upstream backserver {
fair;server 192.168.31.7;
server 192.168.31.8;
}
2. 源码剖析nginx的负载均衡策略可以划分为两⼤类:内置策略在默认情况下这两种策略会编译进nginx内核,只需在nginx配置中指明参数即可。扩展策略默认不编译进nginx内核。内置策略:轮询(round robin)加权轮询(weight round robin)源地址hash(ip_hash)扩展策略:2.1 轮询(round robin)2.1.1 RR 请求流程图2.1.2 RR 请求源码以nginx-1.20.1版本为例源码中的重要声明:nginx-1.20.1/src/http/ngx_http_upstream_round_nt_weight: 权重排序的值,随着处理请求会动态的变化.weight: 配置值,⽤来恢复初始状态。轮询的创建过程。代码如下图:nginx-1.20.1/src/http/ngx_http_upstream_round_robin.c变量tried: tried中记录了服务器当前是否被尝试连接过。他是⼀个位图。如果服务器数量⼩于32,则只需在⼀个int中即可记录下所有服务器状态。如果服务器数量⼤于32,则需在内存池中申请内存来存储。对该位图数组的使⽤可参考如下代码:2.2 源地址hash(ip_hash)ip_hash算法的原理很简单,根据请求所属的客户端IP计算得到⼀个数值,然后把请求发往该数值对应的后端。所以同⼀个客户端的请求,都会发往同⼀台后端,除⾮该后端不可⽤了。ip_hash能够达到保持会话的效果。ip_hash是基于round robin的,判断后端是否可⽤的⽅法是⼀样的。第⼀步,根据客户端IP计算得到⼀个数值。hash1 = (hash0 * 113 + addr[0]) % 6271;hash2 = (hash1 * 113 + addr[1]) % 6271;hash3 = (hash2 * 113 + addr[2]) % 6271;hash3就是计算所得的数值,它只和初始数值hash0以及客户端的IP有关。第⼆步,根据计算所得数值,找到对应的后端。w = hash3 % total_weight;while (w >= peer->weight) { w -= peer->weight; peer = peer->next; p++;}total_weight为所有后端权重之和。遍历后端链表时,依次减去每个后端的权重,直到w⼩于某个后端的权重。选定的后端在链表中的序号为p。因为total_weight和每个后端的weight都是固定的,所以如果hash3值相同,则找到的后端相同。nginx-1.20.1/src/http/modules/ngx_http_upstream_ip_hash_module.c2.3 加权轮询(weight round robin)每个后端peer都有三个权重变量,先解释下它们的含义。(1) weight配置⽂件中指定的该后端的权重,这个值是固定不变的。(2) effective_weight后端的有效权重,初始值为weight。在释放后端时,如果发现和后端的通信过程中发⽣了错误,就减⼩effective_weight。此后有新的请求过来时,在选取后端的过程中,再逐步增加effective_weight,最终⼜恢复到weight。之所以增加这个字段,是为了当后端发⽣错误时,降低其权重。(3) current_weight后端⽬前的权重,⼀开始为0,之后会动态调整。那么是怎么个动态调整呢?每次选取后端时,会遍历集群中所有后端,对于每个后端,让它的current_weight增加它的effective_weight,同时累加所有后端的effective_weight,保存为total。如果该后端的current_weight是最⼤的,就选定这个后端,然后把它的current_weight减去total。如果该后端没有被选定,那么current_weight不⽤减⼩。加权轮询算法可描述为:1. 对于每个请求,遍历集群中的所有可⽤后端,对于每个后端peer执⾏:peer->current_weight += peer->effecitve_weight。同时累加所有peer的effective_weight,保存为total。2. 从集群中选出current_weight最⼤的peer,作为本次选定的后端。3. 对于本次选定的后端,执⾏:peer->current_weight -= total。上述描述可能不太直观,来看个例⼦。现在使⽤以下的upstream配置块:upstream backend { server a weight=3; server b weight=2; server c weight=1;}2.4 ⽬的Url hash(url_hash)按照这个配置,每6个客户端请求中,a会被选中3次、b会被选中2次、c会被选中1次,且分布平滑。url hash是⽤于提⾼squid命中率的⼀种架构算法,⼀般现⾏的架构通常是使⽤dns轮询或lvs等将访问量负载均衡到数台squid,这样做可以使 squid的访问量做到了均衡,但是忽略了⼀个重要⽅⾯–数据量。在这种架构下,每台squid的数据量虽然是⼀致的,但通常都是满载,并且存在数据重 复缓存的情况。如果后端服务器数据容量或者⽤户的访问热点数远远超过缓存机器的内存容量,甚⾄配置的diskcache容量,那么squid将会⼤量使⽤磁盘或者不停与后端服务器索取内容。在新的架构下,使⽤nginx架载于squid之前,如果squid机器有4台,那么在这4台机器上装上nginx,nginx使⽤80端⼝,⽽ squid改为3128端⼝或其他端⼝。nginx的效率⾮常⾼,消耗内存也⾮常少,所以并不需考虑加装nginx所带来的性能损耗。然后在nginx上 配置urlhash,使访问量根据url均衡分布到各台squid,根据url分流之后,每⼀个url就会只存在于⼀台squid中,每台squid的数据都会完全 不同。我们有4台机器,每台2G内存的话,原先极有可能因为数据⼤量重复,内存使⽤率仍然为2G,⽽现在我们经过数据均衡分布,8G内存可以达到充分利 ⽤。是否会存在访问不均的情况呢?是有可能的,但是根据⼤数原理,访问量基本可以保持⼀致,只要不存在单⼀的特别夸张的热点。假如squid是利⽤squidclient来刷新数据的话,新的架构提供了更⾼效的⽅法:在后端服务器中模拟url hash的算法来找到内容所在的squid,然后对此服务器刷新内容即可。在旧的架构中,需要遍历所有的服务器,⽐较低效。2.5 最少连接数(least_conn)nginx-1.20.1/src/http/modules/ngx_http_upstream_least_conn__conn算法,⾸选遍历后端集群,⽐较每个后端的conns/weight,选取该值最⼩的后端。如果有多个后端的conns/weight值同为最⼩的,那么对它们采⽤加权轮询算法。在⼀个upstream配置块中,如果有least_conn指令,表⽰使⽤least connected负载均衡算法。least_conn指令的解析函数为ngx_http_upstream_least_conn主要作⽤:指定初始化此upstream块的函数uscf->_upstream指定此upstream块中server指令⽀持的属性名称NGX_HTTP_UPSTREAM_CREATENGX_HTTP_UPSTREAM_WEIGHTNGX_HTTP_UPSTREAM_MAX_FAILSNGX_HTTP_UPSTREAM_FAIL_TIMEOUTNGX_HTTP_UPSTREAM_DOWNNGX_HTTP_UPSTREAM_BACKUP作⽤检查是否重复创建,以及必要的参数是否填写server指令⽀持weight属性server指令⽀持max_fails属性server指令⽀持fail_timeout属性server指令⽀持down属性server指令⽀持backup属性初始化upstream块执⾏完指令的解析函数后,紧接着会调⽤所有HTTP模块的init main conf函数。在执⾏ngx_http_upstream_module的init main conf函数时,会调⽤所有upstream块的初始化函数。对于使⽤least_conn的upstream块,其初始化函数(_upstream)就是上⼀步中指定ngx_http_upstream_init_least_conn主要作⽤:调⽤round robin的upstream块初始化函数来创建和初始化后端集群,保存该upstream块的数据指定per request的负载均衡初始化函数初始化请求的负载均衡数据收到⼀个请求后,⼀般使⽤的反向代理模块(upstream模块)为ngx_http_proxy_module,其NGX_HTTP_CONTENT_PHASE阶段的处理函数为ngx_http_proxy_handler,在初始化upstream机制的ngx_http_upstream_init_request函数中,调⽤在第⼆步中指定的,主要⽤于初始化请求的负载均衡数据。对于least_conn,实例为ngx_http_upstream_init_least_conn_peer主要作⽤:调⽤round robin的来初始化请求的负载均衡数据重新指定,⽤于从集群中选取⼀台后端服务器least_conn的per request负载均衡数据和round robin的完全⼀样,都是⼀个ngx_http_upstream_rr_peer_data_t实例。选取⼀台后端服务器⼀般upstream块中会有多台后端,那么对于本次请求,要选定哪⼀台后端呢?这时候第三步中r->upstream->指向的函数就派上⽤场了:采⽤least connected算法,从集群中选出⼀台后端来处理本次请求。 选定后端的地址保存在pc->sockaddr,pc为主动连接。函数的返回值:名称NGX_DONENGX_OKNGX_BUSY作⽤选定⼀个后端,和该后端的连接已经建⽴。之后会直接发送请求。选定⼀个后端,和该后端的连接尚未建⽴。之后会和后端建⽴连接。所有的后端(包括备份集群)都不可⽤。之后会给客户端发送502(Bad Gateway)。2.6 最快响应时间(fair)fair采⽤的不是内建负载均衡使⽤的轮换的均衡算法,⽽是可以根据页⾯⼤⼩、加载时间长短智能的进⾏负载均衡。由于不是默认策略.需要单独安装
发布者:admin,转转请注明出处:http://www.yc00.com/web/1689741859a282632.html
评论列表(0条)