nginx是一款比较常用的轻量级组件,常用在web服务器上做代理(正向/反向)、负载均衡、静态资源发布等,市面上现在与它功能类似的有Apache和IIS等。这里主要介绍一下nginx的负载均衡功能。负载均衡的一般需求场景是并发访问比较大,单机撑不起这么多请求的时候,需要布署两台或多台服务器的时候。
1. HTTP Load Balancing
主要使用的是nginx的http模块来实现两台或多台http服务器的负载均衡,配置为:
upstream backend { server 10.10.12.45:80 weight=1; server app.example.com:80 weight=2;}server { location / { proxy_pass http://backend; }}
weight为2是告诉nginx要给第二个server两倍于第一个server的连接请求。weight参数默认值是1。
http health checks:
2. TCP Load Balancing
主要使用nignx的stream模块来对多台tcp服务进行负载,配置为:
stream { upstream mysql_read { server read1.example.com:3306 weight=5; server read2.example.com:3306; server 10.10.12.34:3306 backup; } server { listen 3306; proxy_pass mysql_read; }}
这里是监听3306端口,在mysql server和调用方之间做负载,配置成backup的会在其它节点挂掉时顶上。
health checks:
3. UDP Load Balancing
配置:
health checks:
平时使用不多,需要的话参考:https://docs.nginx.com/nginx/admin-guide/load-balancer/tcp-udp-load-balancer/
4. Load-Balancing Load Balancers with DNS
看下官方Cook book page 34的描述:
3. 负载均衡的方法
3.1 Round robin
默认的负载均衡方法,它会用一个upstream池来维护server列表,weight会被考虑进算法里,权重越大,表示这台server可以撑起的请求容量越多,就会被越多选中。权重的实现算法只是加权平均的统计概率。当weight都为1时,会平等地对待每台server。
- 普通的Round robin实现方式: 用S[next.getAndIncrement() % S.length]获取server,其中S[]是一个维护server列表的数组。
- 带权重的Round robin实现方式: 每个server节点有三个权重变量: 1. weight:nginx配置文件中配置的约定权重,初始化时约定好的; 2. effectiveWeight:有效权重,主要用于在节点异常时降低其权重,最大值是weight的值,通讯过程中发现节点异常(调用失败)则-1,调用成功则+1,直到和weight的值一样就不再增加。
- currentWeight:节点的当前权重,初始值为0。在处理时,轮询所有节点,计算节点当前的权重变量值,其中totalWeight为weight+effectiveWeight+currentWeight,currentWeight = currentWeight + effectiveWeight,然后选择所有节点中currentWeight最大的那个来使用,节点被选中之后,它的currentWeight = currentWeight - totalWeight。参考:https://www.cnblogs.com/markcd/p/8456870.html
upstream backend { # no load balancing method is specified for Round Robin server backend1.example.com; server backend2.example.com;}
3.2 Least connections
它的配置指令名称是least_conn,根据后端服务器当前的连接情况,动态地选取其中当前积压连接数最少的一台服务器来处理当前的请求,尽可能地提高后端服务的利用效率,将负责合理地分流到每一台服务器。weight(权重)也会像Round robin一样考虑在内。配置为:
upstream backend { least_conn; server backend.example.com; server backend1.example.com;}
3.3 Least time
这个是nginx plus新增的特性,它的配置指令名称是least_time,它会优先选择列表中当前连接数量最少的servers,但是会偏向于选择其中响应速度最快的server。它的实现比较复杂,而且比较切合web应用的需要。因为连接最少的不一定是响应最快的,所以它需要权衡多个变量的值。
upstream backend { least_time header; server backend1.example.com; server backend2.example.com;}
- header – 接收server端返回的第一个字节所花的时间
- last_byte – 接收server端整个响应返回所花的时间
- last_byte inflight – 接收server端整个响应返回所花的时间,也会将未完成的请求计算在内。
3.4 Generic hash
确定发送请求的服务器是根据用户定义的键来确定的,可以是一个文本字符串,变量,或组合。例如,关键字可能是成对的源IP地址和端口,或者一个URI:
upstream backend { hash $request_uri consistent; server 192.168.1.22:7777; server 192.168.1.33:8888; hash_method crc32; }
- 在upstream中加入hash语句。server语句中不能写入weight等其他的參数,hash_method是使用的hash算法。
- consistent参数表示打开 ketama 一致性hash功能,这个功能的作用是当有新的upstream server机器加入server列表时,只有很少的key需要重新映射,当有缓存时能减少缓存miss(关于一致性hash,请关注之后的关于一致性hash在redis布署中的应用的文章)。
3.5 IP hash
它的指令是ip_hash,这种算法在最新的版本中只支持http协议。使用client端的ip地址的hash值作为用于路由的hash。它可以保证同一个客户端的请求被路由到同一个server中处理,这也是很多web服务器在分布式环境下维持session的一种解决方案。weight参数也会考虑在hash的分布中。它的配置为:
upstream backend { ip_hash; server backend1.example.com; server backend2.example.com;}
如果想要临时下线其中的某台机器,可以加个down参数,在路由的时候会跳过这台,配置为:
upstream backend { server backend1.example.com; server backend2.example.com; server backend3.example.com down;}
3.6 Random
随机选择一个server,它的指令是random,如果加上参数two会有两个效果:nginx会随机选择两个server来计算server的权重,然后选择使用下面方法的servers中的一个:
- leastconn – 活跃连接数最少的 leasttime=header (NGINX Plus) – 接收到服务端响应头的最小平均时间 ($upstreamheadertime) leasttime=lastbyte (NGINX Plus) – 接收到服务端所有响应信息的最小平均时间($upstreamresponsetime)
配置为:
upstream backend { random two least_time=last_byte; server backend1.example.com; server backend2.example.com; server backend3.example.com; server backend4.example.com;}
它的应用场景是在分布式环境下使用多个负载均衡器都将请求转发到相同的backends中去的时候。当负载均衡器能够应对所有请求时,最好选择其它的负载均衡器。
除了Round Robin不用配置之外,其他的负载均衡都需要在upstream{}块中的第一行配上server指令,指令主要有: (hash, iphash, leastconn, least_time, or random)。
4. 其他参数
- 服务端slow-start特性可以防止刚刚恢复的服务很快被连接压满而下线。在nginx plus中server指令后面可以添加slow_start参数:
upstream backend { server backend1.example.com slow_start=30s; server backend2.example.com; server 192.0.0.1 backup;}
- nginx plus中也添加了session持久化的配置,如sticky cookie指令:
upstream backend { server backend1.example.com; server backend2.example.com; sticky cookie srv_id expires=1h domain=.example.com path=/;}
sticky route指令:
upstream backend { server backend1.example.com route=a; server backend2.example.com route=b; sticky route $route_cookie $route_uri;}
cookie learn方法:
upstream backend { server backend1.example.com; server backend2.example.com; sticky learn create=$upstream_cookie_examplecookie lookup=$cookie_examplecookie zone=client_sessions:1m timeout=1h;}
详细细节参考:https://docs.nginx.com/nginx/admin-guide/load-balancer/http-load-balancer/#method
- 限流配置,通过maxconns参数配置,当请求数量超过maxconns的值时,请求会被放入一个队列中,这个队列也是需要配置的,当队列也满了的时候,会等待timeout时间,超时后client会收到错误信息。
upstream backend { server backend1.example.com max_conns=3; server backend2.example.com; queue 100 timeout=70;}
当在nginx worker进程中有空闲的keepalive 连接打开时,max_conns参数会被忽略。
另外需要注意的一点是,nginx的限流还有其他两种方式: (1) limiereqzone: 用令牌桶算法(brust参数)来限制用户的连接频率,属于ngxhttplimitreqmodule模块,是默认安装的。(2) limit_zone:用于限制一个客户端的并发连接数:
http模块中:limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;server模块中:server { location ~* .htm$ { limit_req zone=one burst=5 nodelay; proxy_pass http://backend_tomcat; }}
说明:区域名称为one(自定义),占用空间大小为10m,平均处理的请求频率不能超过每秒一次。$binaryremoteaddr是$remoteaddr(客户端IP)的二进制格式,固定占用4个字节(可能是C语言的long类型长度)。而$remoteaddr按照字符串存储,占用7-15个字节。burst是指峰值或者缓冲队列的长度,rate=1r/s表示每秒钟只处理1个请求。当有两个请求同时过来时,如果设置了nodelay则会立刻处理两个请求,如果没有nodelay会严格按照rate=1r/s来执行,即 只处理一个请求,到下一秒再处理另外一个请求。具体限流的细节,这里不作深究,请关注后面的文章。
- down 表示单前的server临时不參与负载.
- weight 默觉得1.weight越大,负载的权重就越大。
- maxfails :同意请求失败的次数默觉得1.当超过最大次数时,返回proxynext_upstream 模块定义的错误.
- failtimeout : maxfails次失败后。暂停的时间。
- backup:其他全部的非backup机器down或者忙的时候,请求backup机器。所以这台机器压力会最轻。