nginx负载均衡常见算法和原理1. Nginx负载均衡常见算法1.1轮询1.2加权轮询1.3源地址hash ) IP _ IP 1.6最快响应时间(fair )2.源代码分析2.1轮询)2.1.1 RR请求流程图2.1.2 RR请求源代码2.2源地址hash(IP_hash ) 2.3加权轮询
1. Nginx负载平衡中常见的算法1.1轮询(round robin ) ) ) ) ) ) ) ) ) ) )。
轮询,将请求顺序分配给每个后台服务器的默认方法。
用户后台服务器{服务器192.168.31.7; 服务器192.168.31.8; } 1.2加权轮询根据加权顺序轮询,默认值为1,实现LVS中的Wrr、WLC等。 默认时与RR效果相同。
ustreambackserver { server 192.168.31.7 weight=10; server 192.168.31.8重量=20; } 1.3源地址hash(IP_hash )源地址hash调度方法,基于的客户端的remote_addr源地址IPv4的前24位或整个IPv6地址)进行混列计算
upstream backserver { ip_hash; 服务器192.168.31.7; 服务器192.168.31.8; } 1.4目的URLhash(URL_hash ) hash $ request _ uri一致性;
如果后台服务器是缓存,则根据请求的url的哈希值分配服务器会更有效。
ustreambackserver { consistent _ hash $ remote _ addr; 服务器192.168.31.7; 服务器192.168.31.8; } 1.5最小连接数(least_conn ) least_conn;
一种最小连接调度算法,用于将客户端请求优先调度到当前连接最少的后端服务器。 相当于LVS的WLC
upstream backserver { least_conn; 服务器192.168.31.7; 服务器192.168.31.8; } 1.6最快响应时间(fair )根据服务器的响应时间分发,响应时间越短分发得越多。
upstream backserver { fair; 服务器192.168.31.7; 服务器192.168.31.8; } 2.源代码分析nginx的负载平衡策略可以分为两类:
内置策略
缺省情况下,两个策略都编译到nginx内核中,只需在nginx配置中指定参数即可。 扩展策略
缺省情况下,它不编译为nginx内核。 内置策略:
轮询加权轮询等待轮询源地址散列(IP _ hash )扩展策略:
2.1轮询2.1.1 RR请求流程图
2.1.2 RR请求源代码nginx-1.20.1版本为例http://www.Sina.com/3358 www.Sina.com /
current_weight:权重排序的值随请求的处理而动态变化。
用于恢复初始状态的权重:配置值。源码中的重要声明:
服务当前连接到nginx-1.20.1/src/http/ngx _ http _ upstream _ round _ robin.c http://www.Sina.com/: tried 他是位图。 如果服务器数小于32,则一个int可以记录所有服务器的状态。 如果服务数超过32个,则必须在内存池中请求内存并保存。
有关使用位图数组的信息,请参见以下代码:
2.2源地址hash(ip_hash ) IP_hash算法的原理很简单,根据请求所属的客户端IP计算得到值,并将请求发送到与该值对应的后端。
因此,只要后端不可用,来自同一客户端的请求就会发送到同一后端。 ip_hash具有维持会话的效果。
ip_hash基于round robin,确定后端是否可用的方法相同。
第一步是根据客户端IP计算得到数值。 HasH1=(HasH0*113addr[0] ) % 6271; HasH2=(HasH1*113addr[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.c
每个后端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不用减小。
加权轮询算法可描述为:
peer->current_weight += peer->effecitve_weight。
同时累加所有peer的effective_weight,保存为total。从集群中选出current_weight最大的peer,作为本次选定的后端。对于本次选定的后端,执行: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的数据量虽然是一致的,但通常都是满载,并且存在数据重 复缓存的情况。如果后端服务器数据容量或者用户的访问热点数远远超过缓存机器的内存容量,甚至配置的disk cache容量,那么squid将会大量使用磁盘或者不停与后端服务器索取内容。
在新的架构下,使用nginx架载于squid之前,如果squid机器有4台,那么在这4台机器上装上nginx,nginx使用80端口,而 squid改为3128端口或其他端口。nginx的效率非常高,消耗内存也非常少,所以并不需考虑加装nginx所带来的性能损耗。然后在nginx上 配置url hash,使访问量根据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_module.c
least_conn算法,首选遍历后端集群,比较每个后端的conns/weight,选取该值最小的后端。如果有多个后端的conns/weight值同为最小的,那么对它们采用加权轮询算法。
在一个upstream配置块中,如果有least_conn指令,表示使用least connected负载均衡算法。least_conn指令的解析函数为ngx_http_upstream_least_conn
主要作用:
名称作用NGX_HTTP_UPSTREAM_CREATE检查是否重复创建,以及必要的参数是否填写NGX_HTTP_UPSTREAM_WEIGHTserver指令支持weight属性NGX_HTTP_UPSTREAM_MAX_FAILSserver指令支持max_fails属性NGX_HTTP_UPSTREAM_FAIL_TIMEOUTserver指令支持fail_timeout属性NGX_HTTP_UPSTREAM_DOWNserver指令支持down属性NGX_HTTP_UPSTREAM_BACKUPserver指令支持backup属性
初始化upstream块
执行完指令的解析函数后,紧接着会调用所有HTTP模块的init main conf函数。
在执行ngx_http_upstream_module的init main conf函数时,会调用所有upstream块的初始化函数。对于使用least_conn的upstream块,其初始化函数(peer.init_upstream)就是上一步中指定ngx_http_upstream_init_least_conn
主要作用:
初始化请求的负载均衡数据
收到一个请求后,一般使用的反向代理模块(upstream模块)为ngx_http_proxy_module,其NGX_HTTP_CONTENT_PHASE阶段的处理函数为ngx_http_proxy_handler,在初始化upstream机制的ngx_http_upstream_init_request函数中,调用在第二步中指定的peer.init,主要用于初始化请求的负载均衡数据。对于least_conn,peer.init实例为ngx_http_upstream_init_least_conn_peer
主要作用:
least_conn的per request负载均衡数据和round robin的完全一样,都是一个ngx_http_upstream_rr_peer_data_t实例。
选取一台后端服务器
一般upstream块中会有多台后端,那么对于本次请求,要选定哪一台后端呢?
这时候第三步中r->upstream->peer.get指向的函数就派上用场了:
采用least connected算法,从集群中选出一台后端来处理本次请求。 选定后端的地址保存在pc->sockaddr,pc为主动连接。
函数的返回值:
fair采用的不是内建负载均衡使用的轮换的均衡算法,而是可以根据页面大小、加载时间长短智能的进行负载均衡。
由于不是默认策略.需要单独安装