Nginx负载均衡配置与算法
1 Nginx配置负载均衡
1.1 配置反向代理/负载均衡
配置反向代理:配置一个server虚拟主机(server 块) 用来监听端口,用来接收http请求,location 配置为 proxy_pass(代理通过) 用来表示请求转发到上游服务器 upstream。
配置多台server,便具有了负载均衡。
upstream cluster (upstream 块)上有服务器信息,内部包含{ sever 服务器ip对应端口} ,如果是多台会自动实现负载均衡。
# 配置上游服务器(测试时在一台虚拟机上配置了两台Tomcat)
upstream cluster {
server 192.168.233.130:8080;
server 192.168.233.130:8088;
}
# 配置server
server {
listen 80;
server_name www.awecoder.com;
location / {
# 转发请求
proxy_pass http://cluster;
}
}
1.2 Jmeter压力测试
Jmeter官网jmeter.apache.org下载并按照压测工具。
使用步骤:
- 添加线程组--配置线程数、间隔、每个线程发送多少请求
- 添加取样器--HTTP请求--添加ip/端口等
- 添加监听器--聚合报告/结果数/表格查看结果。
注意关注异常率,查看请求成功与失败的日志。可以设置异常率阈值(例如20%),超过阈值表示到达并发峰值,需要进行扩容等操作。
针对于上面配置负载均衡的压力测试,首先直接访问某个Tomcat服务器,再测试访问Nginx集群,查看压测效果。
注:本地测试,可能会出现集群错误率高于单机的情况。本地压测有大量IO,nginx作为中转代理,所有请求流量会经过nginx分发,对网络和磁盘都有要求。
1.3 upstream 模块参数
- weight 节点资源不均时,设置权重
- max_conns 限制每台上游服务器最大的连接数,防止过载,起到限流作用。请求超出阈值,会异常502:Bad Gateway。
upstream cluster {
server 192.168.233.130:8080 max_conns=2;
server 192.168.233.130:8088 max_conns=2;
}
- slow_start 缓启动,服务器从0逐渐升至设定值。是付费功能,不能用于hash和random负载均衡方法;只有一台服务器时,参数失效。
server 192.168.233.130:8088 weight=3 slow_start=30s;
- down 标记某个节点(server)永久不可用。
- backup 标记节点为备用机,在主节点全部宕机时才会启用。不能用于hash和random负载均衡方法。
- max_fails 和 fail_timeout 结合使用。max_fails 表示失败几次,则标记该server已宕机。fail_timeout 表示重试时间。默认1次,10s。
max_fails=3 fail_timeout=30s 代表在30s内请求某个节点失败3次,认为该节点宕机,然后等待30s,期间内新的请求值发送给正常的应用。直到30s后,Nginx再次尝试转发新请求到宕机节点,并且仅尝试一次,如果还是失败,则继续等待30s,直到节点恢复。
1.4 http upstream 模块参数
- keepalive connections 缓存上游节点的连接,我们可以视为长连接。缓存长连接,可以提高吞吐量。
upstream cluster {
server 192.168.233.130:8080;
server 192.168.233.130:8088;
keepalive 32;
}
server {
listen 80;
server_name www.awecoder.com;
location / {
proxy_pass http://cluster;
# HTTP 1.1 才支持长连接,并清空连接头
proxy_http_version 1.1;
proxy_set_header Connection "";
}
}
2 负载均衡算法
2.1 轮询(RR)与加权轮询(WRR,使用较多)
Nginx默认的负载均衡策略是轮询,每个节点接收几乎同样数量的请求。
服务器配置通常不同,硬件配置越好,处理的请求也会越多。可以配置节点权重,改变nginx请求转发比例。
upstream cluster {
server 192.168.233.130:8080 weight=1;
server 192.168.233.130:8088 weight=3;
}
weight=1是默认权重,weight值越高,服务器接收请求几率越大。
2.2 ip_hash算法
通过ip_hash算法,可以保证对于同一个ip,hash值相同,即同一个请求可以访问同一个节点。
hash(ip) % node_counts = index
类似场景,例如数据库分表,假设将某张表拆分成三张表,可以将主键取出取hash和取模,放入分表中。
```nginx
upstream cluster {
ip_hash;
server 192.168.233.130:8080;
server 192.168.233.130:8088;
}
使用ip_hash需要注意的是,
- 如果采用动态ip,则不能保证每次访问到相同节点。
- 如果用户发起高并发请求,或者恶意请求,会导致某个节点性能急剧下降。
- 如果某个server需要临时删除,需要使用down参数标记,以此保留客户端ip地址的当前hash值。如果直接删除,所有hash取模需要重新计算,用户会话丢失,缓存失效。
2.3 其他算法(least_conn/url_hash/fair)
- url_hash算法 (第三方) 根据每次请求的url地址,hash后访问到固定的服务器节点。当然,节点也可以是一台Nginx。
- least_conn 传入的请求是根据每台服务器当前所打开的连接数来分配。
- fair(第三方)根据后台响应时间来分发请求,响应时间短的分发的请求多。
upstream cluster {
hash $request_uri;
#least_conn
server 192.168.233.130:8080;
server 192.168.233.130:8088;
}
2.4 一致性哈希算法 (需要引入第三方模块ngx_http_upstream_consistent_hash,了解原理)
一致性hash算法提出的初衷是为了解决分布式缓存问题,在分布式系统中广泛应用。
考虑到分布式系统每个节点都有可能失效,并且新的节点很可能动态的增加进来,如何保证当系统的节点数目发生变化时仍然能够对外提供良好的服务,这是值得考虑的。尤其是在设计分布式缓存系统时,如果某台服务器失效,对于整个系统来说如果不采用合适的算法来保证一致性,那么缓存于系统中的所有数据都可能会失效(因为节点总数减少,客户端请求经过hash取模时,hash值发生改变,很可能找不到原先保存该对象的节点),因此一致性hash就显得至关重要。
一致性hash算法原理
- 一致性哈希将整个哈希值空间组织成一个虚拟的圆环,如假设某哈希函数H的值空间为0-2^32-1(即哈希值是一个32位无符号整形),整个哈希空间环如下:
整个空间按顺时针方向组织。0和2^32-1在零点中方向重合。
-
将各个服务器使用Hash进行一个哈希,具体可以选择服务器的ip或主机名作为关键字进行哈希,这样每台机器就能确定其在哈希环上的位置。
-
使用如下算法定位数据访问到相应服务器:将数据key使用相同的函数Hash计算出哈希值,并确定此数据在环上的位置,从此位置沿环顺时针“行走”,第一台遇到的服务器就是其应该定位到的服务器。
例如我们有Object A、Object B、Object C、Object D四个数据对象,经过哈希计算后,在环空间上的位置如下:
-
容错性分析。现假设Node C不幸宕机,可以看到此时对象A、B、D不会受到影响,只有C对象被重定位到Node D。一般的,在一致性哈希算法中,如果一台服务器不可用,则受影响的数据仅仅是此服务器到其环空间中前一台服务器(即沿着逆时针方向行走遇到的第一台服务器)之间数据,其它不会受到影响。
-
可扩展性分析。
下面考虑另外一种情况,如果在系统中增加一台服务器Node X,此时对象Object A、B、D不受影响,只有对象C需要重定位到新的Node X 。
- 对于服务节点过少,造成数据倾斜问题,一致性hash算法采用虚拟节点机制。
小结
一致性hash算法有着这样几个特点:
- hash结果在空间内尽量均匀(hash算法的共性)。
- 具有良好的容错性和扩展性,在节点宕机和扩展节点时,影响最少的数据。