当前位置: 首页 > 科技观察

负载均衡和反向代理(Nginx-OpenResty)

时间:2023-03-18 19:50:49 科技观察

我们在使用Nginx的时候,大部分场景使用的是七层HTTP负载均衡(ngx_http_upstream_module)。在1.9.0版本之后,Nginx也开始支持TCP(ngx_stream_upstream_module)四层负载均衡。第4层/第7层负载均衡的区别第4层负载均衡是基于IP+端口的负载均衡(TCP/UDP)。七层负载均衡是基于URL等应用层协议(HTTP)的负载均衡。熟悉网络分层协议的同学很容易推断,还会有基于MAC地址的二层负载均衡和基于IP地址的三层负载均衡。二层负载均衡会通过一个虚拟的MAC地址接收请求,然后分发到真实的MAC地址。三层负载均衡会通过VIP(虚拟IP)接收请求,然后分配给真实IP。四层负载均衡会通过IP+端口接收请求,然后分发到真实的服务器上。Layer-7负载均衡通过虚拟URL或HOST接收请求,然后分发到真实服务器。所谓四层到七层的负载均衡,就是根据四层及以下、七层及以下的信息来决定如何转发。比如第四层的负载均衡就是使用第三层的VIP,然后加上第四层的端口号来决定流量如何负载均衡。对于负载均衡,需要注意以下几点:上游服务器配置:使用upstreamserver配置上游服务器。负载均衡算法:配置多个上游服务器的负载均衡机制。失败重试机制:配置超时或上游服务器不存活时是否重试其他服务器。ServerHeartbeatCheck:上游服务器的健康检查/心跳检查。Upstream配置Upstream是真正处理业务的服务器。上游在http命令下:upstreambackend{server192.168.0.1:8080weight=1;server192.168.0.2:8080weight=2;}上游服务器配置如下:IP地址和端口:配置IP地址和端口上游服务器;weight:weight用于配置权重,默认为1。权重越大,分发的请求越多。如上所示:3个请求:1到192.168.0.1,2到192.168.0.2。配置上游服务器(upstream)后,还需要配置proxy_pass来处理用户请求。location/{proxy_passhttp://backend;}负载均衡算法负载均衡策略用于解决请求到来时如何选择上游服务器进行处理。默认是循环法(round-robin)。round-robin:Roundrobin,默认的负载均衡算法,配合权重配置实现基于权重的轮循。ip_hash:根据客户IP负载均衡,同一个IP会负载均衡到同一个upstream,配置如下:upstreambackend{ip_hash;server192.168.0.1:8080weight=1;server192.168.0.2:8080weight=2;}hash_key[consistent]:哈希一个key或者使用一致的哈希算法进行负载均衡。Hash算法的问题在于,在添加/删除服务器时,许多键会重新平衡到不同的服务器。这可能会导致用户访问出现问题。因此,可以考虑一致性哈希。服务器横向扩展时,只会重新分配少量机器。哈希算法:这里是基于uri的负载均衡,可以使用Nginx变量实现复杂的算法。upstreambackend{hash$uri;server192.168.0.1:8080weight=1;server192.168.0.2:8080weight=2;}一致性哈希算法:consistent_key是动态指定的。upstreamnginx_local_server{hash$consistent_keyconsistent;server192.168.0.1:8080weight=1;server192.168.0.2:8080weight=2;}下面看一下稍微复杂一点的基于参数cat(category):location/{set$consistent_key$arg_cat;if($consistent_key=""){set$consistent_key$request_uri;}}在实际使用中,更多的是使用Lua脚本来处理。set_by_lua_file$consistent_key"lua_balancing.lua";lua_balancing.lualocalconsistent_key=args.catifnotconsistent_keyorconsistent_key==''thenconsistent_key=ngx_var.request_uriendlocalvalue=balancing_cache:get(consistent_key)ifnotvaluethensuccess,err=balancing_cache:set(consistent_key,1,60,er=relsenewval)balancing_cache:incr(consistent_key,1)end如上所示,如果某个类别在60S内请求过多,可以通过以下改进来平滑请求。localconsistent_key=args.catifnotconsistent_keyorconsistent_key==''thenconsistent_key=ngx_var.request_uriend--大于5000时,生成新keyconsistent_key,1,60)elsenewval,err=balancing_cache:incr(consistent_key,1)endleast_conn:负载均衡请求到具有最少活动连接的上游服务器。如果配置的服务器较少,则切换到基于权重的循环算法。除了上面的负载均衡策略,Nginx商业版还提供了least_time,即根据最小平均响应时间进行负载均衡。失败重试失败重试主要包括两部分配置:upstreamserver和proxy_pass。upstreambackend{server192.168.0.1:8080max_fails=2fail_timeout=10sweight=1;server192.168.0.2:8080max_fails=2fail_timeout=10sweight=1;}通过配置上游服务器的max_fails和fail_timeout来指定每个上游服务器,当fail_timeout时间如果max_fails个请求在指定时间内失败,则认为上游服务器不可用。然后移除该服务器,并在fail_timeout时间后重新将该服务器添加到存活列表中进行重试。location/test{proxy_connect_timeout5s;proxy_read_timeout5s;proxy_send_timeout5s;proxy_next_upstreamererrortimeout;proxy_next_upstream_timeout10s;proxy_next_upstream_tries2;proxy_passhttp://backend;add_headerupstream_addr$upstream_addr;}以上参数的详细说明请参考:gin。(Nginx商业版提供health_check主动检查)Nginx社区版可以集成nginx_upstream_check_module进行主动健康检查。配置如下:TCPheartbeatcheckupstreambackend{server192.168.0.1:8080weight=1;server192.168.0.2:8080weight=2;checkinterval=3000rise=1fall=3timeout=2000type=tcp;}interval:检测间隔,配置这里是每3s检测一次。fall:检测失败多少次后,将upstream服务器标记为notalive。rise:多少次检测成功后,upstream服务器被标记为alive,可以处理请求。timeout:检测请求超时配置。HTTP心跳检测upstreambackend{server192.168.0.1:8080weight=1;server192.168.0.2:8080weight=2;checkinterval=3000rise=1fall=3timeout=2000type=http;check_http_send"HEAD/statusHTTP/1.0\r\n\r\n";check_http_expect_alivehttp_2xxhttp_3xx;}HTTP心跳配置比TCP多了2个配置:check_http_send:健康检查时发送的请求内容。check_http_expect_alive:当上游服务器返回一个匹配的状态码时,上游服务器被认为是存活的。这里需要注意的是,健康检查的时间间隔不能太短。否则可能造成拥塞,甚至导致上游服务器挂掉。长连接配置可以使用keepalive命令配置Nginx与上游服务器之间可以缓存的最大空闲连接数。当超过该数量时,最近最少使用的连接将被关闭。keepalive命令不限制Worker进程与上游服务器的连接总数。upstreambackend{server192.168.0.1:8080weight=1;server192.168.0.2:8080weight=2backup;keepalive100;}与上游服务器建立长连接,还需要配置如下:location/{#supportkeep-aliveproxy_http_version1.1;proxy_set_headerConnection"";proxy_passhttp://backend;}总长连接=空闲连接池+释放连接池。首先,长连接的配置不限制Worker进程可以打开的连接总数(超过的视为短连接)。连接池需要根据不同的场景进行设置。如果空闲连接池太小,连接不够用,需要不断重新建立连接;如果它太大,会导致在使用之前超时。其他配置域名upstreamserverupstreambackend{serverc0.3.cn;serverc1.3.cn;}以上配置加载时,host会解析成IP。但是当主机的IP改变时,IP不会改变。但是商业版的Nginx是支持动态换IP的。另外proxy_passhttp://c1.3.cn可以支持动态解析,但是这样只能配置一个反向代理,比较尴尬。另一种解决方案是lua脚本的动态解析。这里我就不细说了。备份上游服务器upstreambackend{server192.168.0.1:8080weight=1;server192.168.0.2:8080weight=2backup;}上面192.168.0.2配置为备份服务器。当所有上游主机都不存活时,请求将被转发到备份服务器。Unavailableserverupstreambackend{server192.168.0.1:8080weight=1;server192.168.0.2:8080weight=2down;}当upstream服务器出现故障时,可以通过该配置临时下机。ConfigurationexampleInadditiontoreverseproxy,cachingcanalsobeusedtoreducethepressureonupstreamservers.全局配置(proxycache)proxy_bufferingon;proxy_buffer_size4k;proxy_buffers5124k;proxy_busy_buffers_size64k;proxy_temp_file_write_size256k;proxy_cache_lockon;proxy_cache_lock_timeout200ms;proxy_temp_path/tmp/proxy_temp;proxy_cache_path/tmp/proxy_cachelevels=1:2keys_zone=cache:512minactive=5mmax_size=8g;proxy_connect_timeout3s;proxy_read_timeout5s;proxy_send_timeout5s;启用代理缓冲区后,缓存的内容将存储在文件系统中,从而提高系统性能。location配置location~^/backend/(.*)${#设置一致性hash负载均衡keyset_by_lua_file$consistent_key"lua/balancing.lua";#配置失败重试proxy_next_upstreamererrortimeouthttp_500http_502http_504;proxy_next_upstream_timeout2s;proxy_next_upstream_tries2;#ET请求upstreamserver使用GMethod(不考虑客户端请求方式)proxy_methodGET;#不将请求体传递给上游服务器proxy_pass_request_bodyoff;#不向上游服务器传递请求头proxy_pass_request_headersoff;#设置上游服务器的哪些响应头不发送给客户端proxy_hide_headerVary;#支持keep-aliveproxy_http_version1。1;proxy_set_headerConnection"";#将Referer、Cookie和Host传递给上游服务器(按需传递)proxy_set_headerReferer$http_referer;proxy_set_headerCookie$http_cookie;proxy_set_headerHostwww.moguhu.com;proxy_passhttp://backend/$1$is_args$args;}通常其次,为了减少网络开销,一般会使用gzip来减少网络数据包的大小。gzipon;gzip_min_length1k;gzip_buffers1616k;gzip_http_version1.1;gzip_proxiedany;gzip_comp_level2;gzip_typestext/plainapplication/x-javascripttext/cssapplication/xml;gzip_varyon;