负载均衡
- 关注点
- 上游服务器配置:使用upstream server配置上游服务器
- 负载均衡算法:配置多个上游服务器时的负载均衡机制
- 失败重试机制:配置当超时或上游服务器不存活时,是否需要重试其他上游服务器
- 服务器心跳检查:上游服务器的健康检查/心跳检查
- nginx提供的负载均衡可以实现上游服务器的负载均衡、故障转移、失败重试、容错、健康检查等,当某些上游服务器出问题时,可以将请求转移到其他上游服务器保障高可用,使用OpenResty实现更智能的负载均衡,如热点与非热点流量分离、正常流量与爬虫流量分离等;同时也是反向代理服务器,将用户请求通过nginx代理到上游服务器,反向代理服务器可以将响应结果进行缓存、压缩等提升性能。
- upstream配置:第一步,给nginx配置上游服务器,即负载均衡到真实的处理业务的服务器,通过在http指令下配置upstream即可:
upstream backend { server 192.168.61.1:9080 weight=1; server 192.168.61.1:9090 weight=2; }
权重:默认都是1,值越大,分配的请求越多。 第二步,可以配置proxy_pass来处理用户请求
location / { proxy_pass http://backend; }
当访问nginx时,会将请求反向代理到backend配置的upstream server.
- 负载均衡算法:解决用户请求到时如何选择upstream server进行处理,默认用round-robin(轮询),同时支持其他几种算法
- round-robin:轮询,默认负载均衡算法,即以轮询的方式将请求转发到上游服务器,通过配合weight配置可以实现基于权重的轮询。
- ip_hash:根据客户IP进行负载均衡,即相同的IP将负载均衡到同一个upstream server.
upstream backend{ ip_hash; server 192.168.61.1:9080 weight=1; server 192.168.61.1:9090 weight=2; }
- hash key[consistent]:对某一个key进行hash或者使用一致性哈希算法进行负载均衡。使用hash存在的问题是,当添加/删除服务器时,将导致很多key被重新负载均衡到不同的服务器(从而导致后端可能出现 问题),因此,建义使用一致性哈希,当添加/删除一台服务器时,只有少数key将被重新负载均衡到不同的服务器。
- 哈希算法:根据请求uri进行负载均衡,可以使用nginx变量,实现复杂算法。
upstream backend{ hash $uri; server 192.168.61.1:9080 weight=1; server 192.168.61.1:9090 weight=2; }
- 一致性哈希算法:consistent_key动态指定
upstream backend{ hash $consistent_key consistent; server 192.168.61.1:9080 weight=1; server 192.168.61.1:9090 weight=2; }
如下location指定了一致性hash key,此处会优先考虑请求参数cat,如果没有,则再根据请求uri进行负载均衡
location /{ set $consistent_key $arg_cat; if ($consistent_key = "") { set $consistent_key $request_uri; } }
而实际会通过lua设置一致性哈希key.
set_by_lua_file $consistent_key "lua_balancing.lua" lua_balancing.lua代码如下: local consistent_key = args.cat if not consistent_key or consistent_key == '' then consistent_key = ngx_var.request_uri end loca value = balancing_cache:get(consistent_key) if not value then success,err = balancing_cache:set(consistent_key,1,60) else newval,err = balancing_cache:incr(consistent_key,1) end
如果某一个分类请求量太大,上游服务器可能处理不了这么多请求,此时可以在一致性哈希key后加上递增计数以实现类似轮询的算法。
if newval > 5000 then consistent_key = consistent_key .. '_' .. newval
- least_conn:将请求负载均衡到最少活跃连接的上游服务器。
- 失败重试:upstream server 和 proxy_pass
upstream backend{
server 192.168.61.1:9080 weight=1 max_fails=2 fail_timeout=10s;
server 192.168.61.1:9090 weight=1 max_fails=2 fail_timeout=10s;
}
通过配置上游服务器的max_fails和fail_timeout,来指定每个上游服务器,当fail_timeout时间内失败了max_fails次请求,则认为该上游服务器不可用/不存活,然后将摘掉该上游服务器,fail_timeout时间后再次将该服务器加入到存活上游服务器列表进行重试。
location /test {
proxy_connect_timeout 5s;
proxy_read_timeout 5s;
proxy_send_timeout 5s;
proxy_next_upstream error timeout;
proxy_next_upstream_timeout 10s;
proxy_next_upstream_tries 2;
proxy_pass http://backend;
add_header upstream_addr $upstream_addr;
}
进行proxy_next_upstream相关配置,当遇到配置的错误时,会重试下一台上游服务器。
- 健康检查:nginx对上游服务器的健康检查默认采用的是惰性策略,nginx商业版提供了health_check进行主动健康检查。也可以集成nginx_upstream_check_module模块来进行主动健康检查(支持tcp/http心跳来实现健康检查)
- TCP心跳检查
upstream backend{ server 192.168.61.1:9080 weight=1; server 192.168.61.1:9090 weight=2; check interval=3000 rise=1 fall=3 timeout=2000 type=tcp; }
- interval:检测间隔时间,此处3S检测一次
- fall:检测失败多少次后,上游服务器下线
- rise:检测成功多少次后,上上游服务器被标识为存活并可以处理请求
- timeout:检测请求超时时间设置
- HTTP心跳检查
upstream backend{ server 192.168.61.1:9080 weight=1; server 192.168.61.1:9090 weight=2; check interval=3000 rise=1 fall=3 timeout=2000 type=http; check_http_send "HEAD / status HTTP/1.0\r\n\r\n"; check_http_expect_alive http_2xx http_3xx; }
- check_http_send:检查时发的HTTP请求内容
- check_http_expect_alive:当上游服务器返回匹配的响应状态码时,则认为上游服务器存活 需要注意,检查时间间隔不能太短,否则可能因为心跳检查包太多造成上游服务器挂掉,同时要设置合理的超时时间
- 域名上游服务器
upstream backend{
server c0.3.cn;
server c1.3.cn;
}
在nginx社区版中,是在nginx解析配置文件阶段将域名解析成IP地址并记录到upstream上,当域名对应IP变化时,upstream不会更新。nginx商业版支持动态更新。不过,使用proxy_pass http://c0.3.cn是支持动态域名解析的
- 备份上游服务器
upstream backend{
server 192.168.61.1:9080 weight 1;
server 192.168.61.1:9090 weight 1 backup;
}
将9090服务器设置为备份上游服务器,当所有主上游服务器不存活时,请求转发给备份上游服务器。
- 不可用上游服务器
upstream backend{
server 192.168.61.1:9080 weight 1;
server 192.168.61.1:9090 weight 1 down;
}
HTTP反向代理示例:反向代理除了实现负载均衡外,还提供如缓存来减少上游服务器的压力
- 全局配置(proxy cache)
proxy_buffering on; proxy_buffer_size 4k; proxy_buffers 512 4k; proxy_busy_buffers_size 64k; proxy_temp_file_write_size 256k; proxy_cache_lock on; proxy_cache_lock_timeout 200ms; proxy_temp_path /tmpfs/proxy_temp; proxy_cache_path /tmpfs/proxy_cache levels=1:2 keys_zone=cache:512m inactive=5m max_size=8g; proxy_connect_timeout 3s; proxy_read_timeout 5s; proxy_send_timeout 5s;
开放proxy buffer,缓存内容将存放在tmpfs以提升性能,设置超时时间。 对内容型数据建议开启gzip压缩,gzip_comp_level压缩级别根据实际压测来决定(带宽和吞吐量之间的抉择
- HTTP动态负载均衡:如上的负载均衡实现中,每次upstream列表有变更,都要到服务器进行修改,首先管理容易出现问题,而且upstream服务上线无法自动注册到Nginx upstream列表。因此,我们需要一种服务注册,可以将upstream动态注册到Nginx上,从而实现upstream服务的自动发现。
- Consul:开源的分布式服务注册与发现系统,通过HTTP API可以使得服务器注册与发现实现起来很简单。有如下特性
- 服务注册
- 服务发现
- 故障检测
- K/V存储
- 多数据中心
- Raft算法 通过Consul可以管理服务注册与发现,接下来需要有一个与Nginx部署在同一台机器的Agent来实现Nginx配置更改和Nginx重启功能。有Confd或者Consul-template两个选择,Consul-template是Consul官方提供的。除了Consul外,还有一个选择是etcd3,其使用了GRPC和protobuf可以说是一个亮点,不过etcd3没有提供多数据中心、故障检测、Web管理界面。
- Consul:开源的分布式服务注册与发现系统,通过HTTP API可以使得服务器注册与发现实现起来很简单。有如下特性
- Nginx四层负载均衡:目前四层软件负载均衡用的比较多的是HaProxy;而Nginx也支持四层负载均衡
- 静态负载均衡
默认情况下,ngx_stream_core_module是没有启用的,需要在安装Nginx时,添加--with-stream配置参数启用 ./configure --prefix-/usr/local/nginx --with-stream
- stream指令 我们配置HTTP负载均衡时,都是配置在http指令下,而四层负载均衡是配置在stream指令下
stream { upstream mysql_backend{ ... } server{ ... } }
- upstream配置:类似于http upstream配置
upstream mysql_backend{ server 192.168.0.10:3306 max_fails=2 fail_timeout=10s wieght=1; server 192.168.0.11:3306 max_fails=2 fail_timeout=10s wieght=1; least_conn; }
- servers配置
server { }
- stream指令 我们配置HTTP负载均衡时,都是配置在http指令下,而四层负载均衡是配置在stream指令下
- 静态负载均衡
- 动态负载均衡:nginx-stream-upsync-module有一个兄弟nginx-upsync-module,提供了HTTP七层动态负载均衡,动态更新上游服务器不需要reload nginx。
转载请注明:MitNick » 02-亿级流量网站架构核心技术-负载均衡与反向代理