负载均衡与反向代理(Nginx/OpenResty)

服务器
我们使用Nginx时,大多数场景下使用的都是七层的HTTP负载均衡(ngx_http_upstream_module)。在1.9.0版本以后,Nginx也开始支持TCP(ngx_stream_upstream_module)四层负载均衡。

 我们使用Nginx时,大多数场景下使用的都是七层的HTTP负载均衡(ngx_http_upstream_module)。在1.9.0版本以后,Nginx也开始支持TCP(ngx_stream_upstream_module)四层负载均衡。

四层/七层负载均衡的区别

四层负载均衡,就是基于IP+端口的负载均衡(TCP/UDP)。七层负载均衡,就是基于URL等应用层协议(HTTP)的负载均衡。熟悉网络分层协议的同学就很容易推理到,还会有基于MAC地址的二层负载均衡和基于IP地址的三层负载均衡。二层负载均衡会通过一个虚拟的MAC地址接收请求,然后再分配到真实的MAC地址上去。三层负载均衡会通过一个VIP(虚拟IP)接收请求,然后再分配到真实的IP上去。四层负载均衡会通过IP+端口接收请求,然后再分配到真实的服务器。七层负载均衡通过虚拟的URL或者HOST接收请求,然后再分配到真实的服务器上去。

[[277073]]

所谓的四层到七层的负载均衡,就是依据四层及以下、七层及以下的信息来决定如何转发。比如四层的负载均衡,就是利用三层的VIP,然后加上四层的端口号,来决定流量如何来进行负载均衡。

对于负载均衡我们需要关注以下几点:

  • 上游服务器配置:使用upstream server配置上游服务器。
  • 负载均衡算法:配置多个上游服务器的负载均衡机制。
  • 失败重试机制:配置当超时或者上游服务器不存活时,是否需要重试其他服务器。
  • 服务器心跳检查:上游服务器的健康检查/心跳检查。

upstream 配置

upstream就是真实处理业务的服务器,upstream在http指令下:

upstream backend { 
 server 192.168.0.1:8080 weight=1; 
 server 192.168.0.2:8080 weight=2; 

  • 1.
  • 2.
  • 3.
  • 4.

upstream server 的配置如下:

  • IP地址和端口:配置上游服务器的IP地址和端口;
  • 权重:weight用来配置权重,默认1。权重越大,分发的请求越多。如上所示:3个请求:1个到192.168.0.1,2个到192.168.0.2。

配置完上游服务器(upstream)之后,就要配置proxy_pass来处理用户请求。

location / { 
 proxy_pass http://backend; 

  • 1.
  • 2.
  • 3.

负载均衡算法

负载均衡策略用来解决请求到来时,如何选择upstream server进行处理,默认采用的是round-robin(轮询)。

  • round-robin:轮询,默认负载均衡算法,通过配合weight配置实现基于权重的轮询。
  • ip_hash:根据客户IP进行负载均衡,相同的IP会被负载均衡到同一个upstream,配置如下:
upstream backend { 
 ip_hash; 
 server 192.168.0.1:8080 weight=1; 
 server 192.168.0.2:8080 weight=2; 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • hash_key [consistent]:对于一个key进行hash或者使用一致性哈希算法进行负载均衡。Hash算法存在的问题是:当增加/删除一台服务器时,将导致很多key被重新负载均衡到不同的服务器。从而有可能导致用户访问出问题。因此可以考虑一致性哈希,服务器横向扩展时,只有少部分机器会被重新分配。
  • 哈希算法:此处是根据uri进行负载均衡,可以使用Nginx变量,从而实现复杂的算法。
upstream backend { 
 hash $uri; 
 server 192.168.0.1:8080 weight=1; 
 server 192.168.0.2:8080 weight=2; 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

一致性哈希算法:consistent_key动态指定。

upstream nginx_local_server { 
 hash $consistent_key consistent; 
 server 192.168.0.1:8080 weight=1; 
 server 192.168.0.2:8080 weight=2; 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

下面看一下根据参数cat(类目),做的稍微复杂一点的负载均衡:

location / { 
 set $consistent_key $arg_cat; 
 if ($consistent_key = " ") { 
 set $consistent_key $request_uri; 
 } 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.

而在实际使用过程中,更多的是使用Lua脚本进行处理。

set_by_lua_file $consistent_key "lua_balancing.lua"
  • 1.

lua_balancing.lua

local consistent_key = args.cat 
if not consistent_key or consistent_key == '' then 
 consistent_key = ngx_var.request_uri 
end 
local 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 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.

如上所示,如果其中一个分类在60S内的请求过多,则可以通过以下改进来平滑请求。

local consistent_key = args.cat 
if not consistent_key or consistent_key == '' then 
 consistent_key = ngx_var.request_uri 
end 
-- 大于5000时,生成新key 
local value = balancing_cache:get(consistent_key) 
if value > 5000 then 
 consistent_key = consistent_key .. '_' .. value 
end 
if not value then 
 success, err = balancing_cache:set(consistent_key, 1, 60) 
else 
 newval, err = balancing_cache:incr(consistent_key, 1) 
end 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.

least_conn:将请求负载均衡到最小活跃连接的上游服务器。如果配置的服务器较少,则转为基于权重轮询的算法。

除了上面的负载均衡策略,商业版的Nginx还提供了least_time,就是基于最小平均响应时间进行负载均衡。

失败重试

失败重试主要包含两部分配置:upstream server和proxy_pass。

upstream backend { 
 server 192.168.0.1:8080 max_fails=2 fail_timeout=10s weight=1; 
 server 192.168.0.2:8080 max_fails=2 fail_timeout=10s weight=1; 

  • 1.
  • 2.
  • 3.
  • 4.

通过配置上游服务器的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; 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.

上述参数详情请参见:《分布式系统超时重试》

健康检查

Nginx对上游服务器的健康检查采用的是惰性策略。(Nginx商业版提供了health_check的主动检查)社区版的Nginx可以集成nginx_upstream_check_module进行主动健康检查。配置如下:

TCP 心跳检查

upstream backend { 
 server 192.168.0.1:8080 weight=1; 
 server 192.168.0.2:8080 weight=2; 
 check interval=3000 rise=1 fall=3 timeout=2000 type=tcp; 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • interval:检测间隔时间,此处配置了每隔3s检测一次。
  • fall:检测失败多少次后,上游服务器被标识为不存活。
  • rise:检测成功多少次后,上游服务器被标识为存活,并可以处理请求。
  • timeout:检测请求超时时间配置。

HTTP心跳检查

upstream backend { 
 server 192.168.0.1:8080 weight=1; 
 server 192.168.0.2:8080 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; 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.

HTTP心跳配置比TCP额外多了2个配置:

  • check_http_send:健康检查时所发送的请求内容。
  • check_http_expect_alive:当上游服务器返回匹配的状态码,就认为上游服务器存活。

这里面需要注意的是,健康检查的时间间隔不宜过短。否则有可能会造成拥堵,更甚至造成上游服务器挂掉。

长连接配置

可以使用 keepalive 指令配置Nginx与上游服务器可缓存的空闲连接的最大数量。当超出数量时,最近最少使用的连接将被关闭。keepalive指令不限制Worker进程与上游服务器的总连接数。

upstream backend { 
 server 192.168.0.1:8080 weight=1; 
 server 192.168.0.2:8080 weight=2 backup; 
 keepalive 100; 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

要想与上游服务器建立长连接,还需要如下配置:

location / { 
 # 支持 keep-alive 
 proxy_http_version 1.1; 
 proxy_set_header Connection ""
 proxy_pass http://backend; 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.

总长连接数=空闲连接池+释放连接池。首先,长连接配置不会限制Worker进程可以打开的总连接数(超出的作为短连接)。连接池需要根据不同的场景进行设置。

空闲连接池太小,连接不够用,就需要不断的重新建立连接;如果太大,就会造成还没用就超时了。

其他配置

域名上游服务器

upstream backend { 
 server c0.3.cn; 
 server c1.3.cn; 

  • 1.
  • 2.
  • 3.
  • 4.

上面的配置在加载时,host就会被解析成IP。但是当host的IP变更时,IP不会改变。但是商业版的Nginx是支持动态变更IP的。另外proxy_pass http://c1.3.cn是可以支持动态解析的,但是这样反向代理就只能配置一台了,比较尴尬。还有一种解决方案就是lua脚本动态解析。这里不再赘述了。

备份上游服务器

upstream backend { 
 server 192.168.0.1:8080 weight=1; 
 server 192.168.0.2:8080 weight=2 backup; 

  • 1.
  • 2.
  • 3.
  • 4.

上面192.168.0.2被配置为备份服务器,当所有上游主机都不存活时,请求就会被转发给备份服务器。

不可用服务器

upstream backend { 
 server 192.168.0.1:8080 weight=1; 
 server 192.168.0.2:8080 weight=2 down; 

  • 1.
  • 2.
  • 3.
  • 4.

当上游服务器出现故障时,可以通过该配置临时摘除机器。

配置示例

除了反向代理之外,还可以使用缓存来减少上游服务器的压力。

全局配置(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 /tmp/proxy_temp; 
proxy_cache_path /tmp/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; 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.

开启proxy buffer后,缓存内容将存放在文件系统中,从而提高系统性能。

location 配置

location ~ ^/backend/(.*)$ { 
 # 设置一致性哈希负载均衡key 
 set_by_lua_file $consistent_key "lua/balancing.lua"
 # 失败重试配置 
 proxy_next_upstream error timeout http_500 http_502 http_504; 
 proxy_next_upstream_timeout 2s; 
 proxy_next_upstream_tries 2; 
 # 请求上游服务器使用GET方法(无论客户端请求方法) 
 proxy_method GET; 
 # 不给上游服务器传递请求体 
 proxy_pass_request_body off
 # 不给上游服务器传递请求头 
 proxy_pass_request_headers off
 # 设置上游服务器哪些响应头不发送给客户端 
 proxy_hide_header Vary; 
 # 支持keep-alive 
 proxy_http_version 1.1; 
 proxy_set_header Connection ""
 # 给上游服务器传递Referer、Cookie和Host(按需传递) 
 proxy_set_header Referer $http_referer; 
 proxy_set_header Cookie $http_cookie; 
 proxy_set_header Host www.moguhu.com; 
 proxy_pass http://backend /$1$is_args$args; 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.

通常情况下,为了减少网络开销,一般会使用gzip来减少网络数据包的大小。

gzip on
gzip_min_length 1k; 
gzip_buffers 16 16k; 
gzip_http_version 1.1; 
gzip_proxied any
gzip_comp_level 2; 
gzip_types text/plain application/x-javascript text/css application/xml; 
gzip_vary on
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.

 

责任编辑:武晓燕 来源: 今日头条
相关推荐

2019-06-19 15:34:39

Nginx反向代理负载均衡

2017-12-18 12:04:02

Nginx代理均衡

2019-11-04 15:35:53

Nginx反向代理负载均衡

2020-07-28 15:10:34

Nginx反向代理负载均衡

2023-02-20 08:27:17

2015-06-05 11:26:58

nginx运维

2012-12-07 10:14:48

Nginx负载均衡

2019-07-09 15:10:02

Nginx反向代理负载均衡

2019-10-10 15:59:14

Nginx反向代理负载均衡

2018-10-14 08:39:52

NginxTomcat服务器

2018-11-05 09:34:43

2020-10-22 08:05:46

Nginx

2023-02-24 15:28:07

2019-05-20 14:55:05

Nginx反向代理负载均衡

2015-09-06 09:53:41

DockerWeave

2018-10-26 10:28:28

Nginx负载均衡HTTP服务器

2022-07-01 07:33:24

nginx反向代理测试

2023-12-05 09:14:54

2020-09-17 10:34:35

服务器开发 架构

2023-09-28 19:49:26

负载均衡API网关反向代理
点赞
收藏

51CTO技术栈公众号