前言
当我们的应用单实例不能支撑用户请求时,此时就需要扩容,从一台服务器扩容到两台,几十台,上百台,甚至更多。然后用户访问是通过一个域名的方式访问,在请求时,浏览器首先会查询DNS服务器获取对应IP,然后通过此IP访问对应服务。
因此一种方式是将域名解析到多个IP,但是存在一个简单的问题,假设某台服务重启或者出现故障,DNS会有一定的缓存时间,故障切换时间长,而且没有对后端服务进行心跳检查和失败重试的机制。
因此,外网DNS应该用来实现GSLB(全局负载均衡)进行流量调度,如将用户分配到离他最近的服务器上以提升体验。而且当某一区域的机房出现问题时(如断网),可以通过DNS指向其他区域的IP来是服务可用。
对于内网DNS,可以实现简单的轮询负载均衡。但是,还是会有一定缓存时间并且没有失败重试机制。因此我们可以使用HaProxy和Nginx。
而且对于一般应用来说,有Nginx就可以了。但Nginx一般用户7层负载均衡,其吞吐量是有一定限制的。为了提升整体吞吐量,会再DNS和Nginx之间引入接入层,如使用LVS(软件负载均衡)、F5(硬件负载均衡器)可以做4层负载均衡,即首先DNS解析到LVX/F5,返回LVS/F5转发给Nginx,再由Nginx转发给后端Server。
一、Nginx负载均衡算法
负载均衡用来解决用户请求到来时如何选择upstream server进行处理,默认采用round-robin(轮询),同时支持其他几种算法。
1: round-robin:轮询,默认负载均衡算法,即以轮询的方式将请求转发到上游服务器,通过配合weight配置可以实现基于权重的轮询。
upstream api{
server 172.31.72.157:80 weight=1;
server 172.31.72.155:80 weight=1;
}
2:ip_hash:根据客户IP进行负载,即相同的IP负载均衡到同一个server。
upstream api{
ip_hash;
server 172.31.72.157:80 weight=1;
server 172.31.72.155:80 weight=1;
}
3:hash key:对某一个key进行哈希或者使用一致性哈希算法进行负载均衡。使用hash算法存在的问题是,当添加/删除一台服务器时,将导致很多key被重新负载均衡到不同的服务器(从而导致后端可能出现问题);因此建议考虑使用一致性哈希算法,这样当添加/删除一台服务器时,只有少数key将被重新负载均衡到不同的服务器。
upstream api{
has $uri;
server 172.31.72.157:80 weight=1;
server 172.31.72.155:80 weight=1;
}
4:一致性哈希算法:consistent_key
upstream api{
has $consistent_key consistent;
server 172.31.72.157:80 weight=1;
server 172.31.72.155:80 weight=1;
}
5:least_conn:将请求负载均衡到最少活跃连接的上游服务器。如果配置的服务器较少,则将转而使用基于权重的轮询算法
二、失败重试
主要有两部分配置:upstream server 和proxy_pass
upstream api{
server 172.31.72.157:80 max_fails=2 fial_timeout=10s weight=1;
server 172.31.72.155:80 max_fails=2 fial_timeout=10s weight=1;
}
通过配置上游服务器的max_fails和fial_timeout,来指定每个上游服务器,当fail_timeout时间内失败了max_fails次请求,则认为该上游服务器不可用/不存活,然后将摘掉该上游服务器,fail_timeout时间后会再次将该服务器加入到存活上游服务器列表进行重试。
三、健康检查
Nginx对上游服务器的健康检查默认采用的是惰性策略,Nginx商业版提供了health_check进行主动健康检查。当然也可以集成nginx_upstream_check_module模块来进行主动健康检查。
nginx_upstream_check_module支持TCP心跳和HTTP心跳来实现健康检查
TCP心跳检查
upstream api{
server 172.31.72.157:80 max_fails=2 fial_timeout=10s weight=1;
server 172.31.72.155:80 max_fails=2 fial_timeout=10s weight=1;
check interval=3000 rise=1 fall=3 timeout=2000 type=tcp;
}
· interval:检测间隔时间,此处配置每3s检测一次
· fall:检测失败多少次后,上游服务器被标识为不存活
· rise:检测成功多少次后,上游服务被标识为存活,并可以处理请求
· timeout:检查请求超时时间
HTTP心跳检查
upstream api{
server 172.31.72.157:80 max_fails=2 fial_timeout=10s weight=1;
server 172.31.72.155:80 max_fails=2 fial_timeout=10s weight=1;
check interval=3000 rise=1 fall=3 timeout=2000 type=htpp;
check_http_send "GET /check HTTP/1.0\r\n\r\n";
check_http_expect_alive http_2xx | http_3xx;
}
HTTP心跳检查有如下两个参数需要额外配置
· check_http_send:检查时发的HTTP请求内容
· check_http_expect_alive:当上游服务器返回匹配的响应状态码时,则认为上游服务器存活
需要注意,检查间隔时间不能太短,否则可能因为心跳检查包太多造成上游服务器挂掉,同时要设置合理的超时时间。
备份上游服务器
代码如下(示例):
upstream api{
server 172.31.72.157:80 weight=1;
server 172.31.72.152:80 weight=2 backup;
}
将172.31.72.152服务器80端口的上游服务器配置为备上游服务,当所有主上游服务器都不存活时,请求会转发给备上游服务器
不可用上游服务器
upstream api{
server 172.31.72.157:80 weight=1;
server 172.31.72.152:80 weight=2 down;
}
将172.31.72.152服务器80端口的上游服务器配置为永久不可用,当测试或者机器出现故障时,暂时通过该配置临时摘掉机器。