写点什么

Linux 下玩转 nginx 系列(五)---nginx 实现负载均衡

作者:anyRTC开发者
  • 2022 年 5 月 17 日
  • 本文字数:5891 字

    阅读完需:约 19 分钟

Ngnix 负载均衡

  • 在多台服务器之间有效地分配客户端请求或网络负载

  • 通过仅向正常服务器发送请求确保高可用性和可靠性

  • 业务不中断地情况下,按需弹性分配服务器资源



使用 nginx 做负载均衡的三大模块:


  • upstream 定义负载节点池

  • location 模块 进行 URL 匹配

  • proxy 模块 发送请求给 upstream 定义的节点池

upstream 模块解读

nginx 的负载均衡功能依赖于 ngx_http_upstream_module 模块,所支持的代理方式有 proxy_pass(一般用于反向代理),fastcgi_pass(一般用于和动态程序交互),memcached_pass,proxy_next_upstream,fastcgi_next_pass,memcached_next_pass 。


upstream 模块应该放于 http{}标签内。模块写法:


upstream backend {    ip_hash;     server backend1.example.com       weight=5;    server backend2.example.com:8080;    server backup1.example.com:8080   backup;    server backup2.example.com:8080   backup;}
复制代码


实例一:


upstream dynamic {    zone upstream_dynamic 64k;
server backend1.example.com weight=5; server backend2.example.com:8080 fail_timeout=5s slow_start=30s; server 192.168.199.18 max_fails=3; server backend3.example.com resolve;
server backup1.example.com:8080 backup; server backup2.example.com:8080 backup;}
复制代码

语法解释

nginx 默认支持四种调度算法

  • 轮询(rr),每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器故障,故障系统自动清除,使用户访问不受影响

  • 轮询权值(weight),weight 值越大,分配到的访问几率越高,主要用于后端每个服务器性能不均的情况

  • ip_hash,每个请求按访问 IP 的 hash 结果分配,这样来自同一个 IP 的固定访问一个后端服务器,主要解决动态网站 session 共享的问题

  • url_hash,按照访问的 URL 的 hash 结果来分配请求,是每个 URL 定向到同一个后端服务器,可以进一步提高后端缓存服务器的效率,nginx 本身不支持,如果想使用需要安装 nginx 的 hash 软件包

  • fair,这个算法可以依据页面大小和加载时间长短智能的进行负载均衡,也就是根据后端服务器的响应时间来分配请求,相应时间短的优先分配,默认不支持,如果想使用需要安装 upstream_fail 模块

  • least_conn 最少链接数,那个机器连接数少就分发

server 模块的写法

server IP 调度状态 server 指令指定后端服务器 IP 地址和端口,同时还可以设定每个后端服务器在负载均衡调度中的状态。


  • down 表示当前的 server 暂时不参与负载均衡

  • backup 预留的备份服务器,当其他所有的非 backup 服务器出现故障或者忙的时候,才会请求 backup 机器,因为这台集群的压力最小

  • max_fails 允许请求失败的次数,默认是 1,当超过最大次数时,返回 proxy_next_upstream 模块定义的错误。0 表示禁止失败尝试。根据业务需求去配置

  • fail_timeout,在经历了 max_fails 次失败后,暂停服务的时间。根据业务需求配置。常规业务 2-3 秒合理


例:如果 max_fails 是 5,他就检测 5 次,如果五次都是 502.那么,他就会根据 fail_timeout 的值,等待 10 秒,再去检测。


server 如果接域名,需要内网有 DNS 服务器,或者在负载均衡器的 hosts 文件做域名解析。server 后面还可以直接接 IP 或 IP 加端口。

长连接 keepalive

upstream backend {    server backend2.example.com:8080;    server backup1.example.com:8080   backup;    keepalive 100;}
复制代码


通过该指令配置了每个 worker 进程与上游服务器可缓存的空闲连接的最大数量。当超出这个数量时,最近最少使用的连接将被关闭。keepalive 指令不限制 worker 进程与上游服务器的总连接。


location / {    # 支持keep-alive    proxy_http_version 1.1;    proxy_set_header Connection "";    proxy_pass http://backup;}
复制代码


  • 如果是 http/1.0 需要配置发送"Connection: Keep-Alive" 请求头

  • 上游服务器不要忘记开启长连接支持


连接池配置建议


  • 总长连接数是"空闲连接池"+"释放连接池"的长连接总数

  • 首先,长连接配置不会限制 worker 进程可以打开的总连接数(超了的作为短连接)。另外连接池一定要根据场景合理进行设置


1.空闲连接池太小,连接不够用,需要不断建连接。2.空闲连接池太大,空闲连接太多,还没使用就超时。3.建议只对小报文开启长连接。

location 模块解读

location 作用:基于一个指令设置 URI。基本语法:


Syntax:  location [ = | ~ | ~* | ^~ ] uri { ... }location @name { ... }Default:  —Context:  server, location
复制代码


  • = 精确匹配,如果找到匹配=号的内容,立即停止搜索,并立即处理请求(优先级最高)

  • ~ 区分大小写

  • ~* 不区分大小写

  • ^~ 只匹配字符串,不匹配正则表达式

  • @ 指定一个命名的 location,一般用于内部重定义请求,location @name {…}


匹配是有优先级的,不是按照 nginx 的配置文件进行。


官方例子:


location = / {    [ configuration A ]}location / {    [ configuration B ]}location /documents/ {    [ configuration C ]}location ^~ /images/ {    [ configuration D ]}location ~* \.(gif|jpg|jpeg)$ {    [ configuration E ]}
复制代码


结论:


  • / 匹配 A

  • /index.html 匹配 B

  • /documents/document.html 匹配 C

  • /images/1.gif 匹配 D

  • /documents/1.jpg 匹配的是 E


测试用的例子:


location / {           return 401;        }        location = / {            return 402;        }        location /documents/ {            return 403;        }        location ^~ /images/ {            return 404;        }        location ~* \.(gif|jpg|jpeg)$ {            return 500;        }
复制代码


测试结果:


[root@skyline conf]# curl -I -s -o /dev/null -w "%{http_code}\n" http://192.168.199.7/402[root@skyline conf]# curl -I -s -o /dev/null -w "%{http_code}\n" http://192.168.199.7/index.html401[root@skyline conf]# curl -I -s -o /dev/null -w "%{http_code}\n" http://192.168.199.7/documents/document.html 403[root@skyline conf]# curl -I -s -o /dev/null -w "%{http_code}\n" http://192.168.199.7/images/1.gif404[root@skyline conf]# curl -I -s -o /dev/null -w "%{http_code}\n" http://192.168.199.7/dddd/1.gif  500
复制代码


结果总结:匹配的优先顺序,=>^~(匹配固定字符串,忽略正则)>完全相等>~*>空>/ 。工作中尽量将'='放在前面。

proxy_pass 模块解读

proxy_pass 指令属于 ngx_http_proxy_module 模块,此模块可以将请求转发到另一台服务器。


写法:


proxy_pass http://localhost:8000/uri/; 
复制代码


实例一:


 upstream proxy_real_servers {         server 192.168.199.9:80  weight=5;         server 192.168.199.10:80  weight=10;         server 192.168.199.19:82  weight=15;    }    server {       listen       80;       server_name  www.xxx.org;       location / {          proxy_pass http:// proxy_real_servers;          proxy_set_header host $host;  proxy_set_header X-Forwarded-For $remote_addr;       }    }
复制代码


  • proxy_set_header:当后端 Web 服务器上也配置有多个虚拟主机时,需要用该 Header 来区分反向代理哪个主机名,proxy_set_header host $host;

  • proxy_set_header X-Forwarded-For :如果后端 Web 服务器上的程序需要获取用户 IP,从该 Header 头获取。proxy_set_header X-Forwarded-For $remote_addr

proxy_pass 相关的优化参数

  • client_max_body_size 10m; 允许客户端请求的最大的单个文件字节数

  • client_body_buffer_size 128k; 缓冲区代理缓冲用户端请求的最大字节数 可以理解为先保存到本地再传给用户

  • proxy_connect_timeout 600; 跟后端服务器连接的超时时间_发起握手等候响应超时时间

  • proxy_read_timeout 600; 连接成功后_等候后端服务器响应时间_其实已经进入后端的排队之中等候处理

  • proxy_send_timeout 600; 后端服务器回传数据时间,就是在规定时间之内后端服务器必须传完所有的数据

  • proxy_buffer_size 8k; 代理请求缓存区,这个缓存区间会保存用户的头信息以供 Nginx 进行规则处理,一般只要设置能保存下头信息即可

  • proxy_buffers 4 32k; 同上 告诉 Nginx 保存单个页面使用的空间大小,假设网页大小平均在 32k 以下的话

  • proxy_busy_buffers_size 64k; 如果系统很忙的时候可以申请更大的 proxy_buffers 官方推荐(proxy_buffers*2)

  • proxy_max_temp_file_size 1024m; 当 proxy_buffers 放不下后端服务器的响应内容时,会将一部分保存到硬盘的临时文件中,这个值用来设置最大临时文件大小,默认 1024M,它与 proxy_cache 没有关系。大于这个值,将从 upstream 服务器传回。设置为 0 禁用

  • proxy_temp_file_write_size 64k; proxy 缓存临时文件的大小 proxy_temp_path(可以在编译的时候)指定写到哪那个目录

健康检查

Nginx 提供了 health_check 语句来提供负载(upstream)时的键康检查机制(注意:此语句需要设置在 location 上下文中)。


支持的参数有:


  • interval=time:设置两次健康检查之间的间隔值,默认为 5 秒

  • fails=number:设置将服务器视为不健康的连续检查次数,默认为 1 次

  • passes=number:设置一个服务器被视为健康的连续检查次数,默认为 1 次

  • uri=uri:定义健康检查的请求 URI,默认为”/“

  • match=name:指定匹配配置块的名字,用记测试响应是否通过健康检测。默认为测试返回状态码为 2xx 和 3xx


一个简单的设置如下,将使用默认值:


location / {    proxy_pass http://backend;    health_check;}
复制代码


对就应用,我们可以专门定义一个 API 用于健康检查:/api/health_check,并只返回 HTTP 状态码为 200。并设置两次检查之间的间隔值为 1 秒。这样,health_check 语句的配置如下:


health_check uri="/api/health_check" interval;
复制代码


匹配 match 的方法


http {    server {    ...        location / {            proxy_pass http://backend;            health_check match=welcome;        }    }
match welcome { status 200; header Content-Type = text/html; body ~ "Welcome to nginx!"; }}
复制代码


match 例子举例


  • status 200;: status 等于 200

  • status ! 500;: status 不是 500

  • status 200 204;: status 是 200 或 204

  • status ! 301 302;: status 不是 301 或 302

  • status 200-399;: status 在 200 到 399 之间

  • status ! 400-599;: status 不在 400 到 599 之间

  • status 301-303 307;: status 是 301, 302, 303, 或 307

  • header Content-Type = text/html;: “Content-Type” 得值是 text/html

  • header Content-Type != text/html;: “Content-Type” 不是 text/html

  • header Connection ~ close;: “Connection” 包含 close

  • header Connection !~ close;: “Connection” 不包含 close

  • header Host;: 请求头包含 “Host”

  • header ! X-Accel-Redirect;: 请求头不包含 “X-Accel-Redirect”

  • body ~ "Welcome to nginx!";: body 包含 “Welcome to nginx!”

  • body !~ "Welcome to nginx!";: body 不包含 “Welcome to nginx!”

完整 nginx 实例

[root@skyline conf]# cat nginx.confworker_processes  2;events {    worker_connections  65536;}http {    include       mime.types;    default_type  application/octet-stream;    sendfile        on;    keepalive_timeout  65;    #upstream    upstream proxy_real_servers {     server   192.168.199.9:80 weight=1 max_fails=1 fail_timeout=10s;     server   192.168.199.10:80 weight=1 max_fails=2 fail_timeout=20s;    }    server {       listen       80;       server_name  www.xxx.org;       location / {        proxy_pass http:// proxy_real_servers;        include proxy.conf;       }    }}[root@skyline conf]# cat proxy.conf         proxy_set_header Host $host;        proxy_set_header X-Forwarded-For $remote_addr;        proxy_connect_timeout 90;                proxy_send_timeout 90;        proxy_read_timeout 90;        proxy_buffer_size 4k;        proxy_buffers 4 32k;        proxy_busy_buffers_size 64k;  proxy_temp_file_write_size 64k;
复制代码

扩展补充

只允许使用指定方法请求(GET,HEAD,POST)

   ## Only allow these request methods ##        if ($request_method !~ ^(GET|HEAD|POST)$ ) {            return 444;       }
复制代码

根据 URI 及 location 实现动静分离

最终实现:1./static/的 URL 都去访问 192.168.199.9。2./dynamic/的 URL 都去访问 192.168.199.10。3.图片这些静态文件去访问 192.168.199.9。4./upload/的 URL 都去访问 192.168.199.10。


[root@skyline conf]# cat nginx.confworker_processes  1;events {    worker_connections  1024;}http {    include       mime.types;    default_type  application/octet-stream;    sendfile        on;    keepalive_timeout  65;    upstream static_pools {      server 192.168.199.9:80;    }    upstream dynamic_pools {      server 192.168.199.10:80;    }     upstream upload_pools {      server 192.168.199.9:80;    }
server { listen 80; server_name www.xxx.com;
location / { proxy_pass http://static_pools; include proxy.conf; }
location /static/ { proxy_pass http://static_pools; include proxy.conf; } location ~* \.(gif|jpg|jpeg)$ { proxy_pass http://static_pools; include proxy.conf; }
location /dynamic/ { proxy_pass http://dynamic_pools; include proxy.conf; } location /upload/ { proxy_pass http://upload_pools; include proxy.conf; } }}
复制代码

实现苹果手机和安卓手机访问不同地址

server {       listen       80;       server_name  www.xxxx.com;       location / {          if ($http_user_agent ~* "android")          {             proxy_pass http://android_pools;          }          if ($http_user_agent ~* "iphone")          {              proxy_pass http://iphone_pools;          }          proxy_pass http://pc_pools;          include extra/proxy.conf;       }        access_log off; }
复制代码


参考文档nginx-proxy_pass官网Nginx-负载均衡Full Example Configuration



发布于: 刚刚阅读数: 4
用户头像

实时交互,万物互联! 2020.08.10 加入

实时交互,万物互联,全球实时互动云服务商领跑者!

评论

发布
暂无评论
Linux下玩转nginx系列(五)---nginx实现负载均衡_nginx_anyRTC开发者_InfoQ写作社区