使用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{}标签内。
模块写法:
1 2 3 4 5 6 7 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; }
实例一:
1 2 3 4 5 6 7 8 9 10 11 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.0.2.1 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表示禁止失败尝试,企业场景:2-3.京东1次,蓝汛10次,根据业务需求去配置。
fail_timeout,在经历了max_fails次失败后,暂停服务的时间。京东是3s,蓝汛是3s,根据业务需求配置。常规业务2-3秒合理。
例:如果max_fails是5,他就检测5次,如果五次都是502.那么,他就会根据fail_timeout 的值,等待10秒,再去检测。
server 如果接域名,需要内网有DNS服务器,或者在负载均衡器的hosts文件做域名解析。server后面还可以直接接IP或IP加端口。
location 模块解读 location作用:基于一个指令设置URI。 基本语法:
1 2 3 4 Syntax: location [ = | ~ | ~* | ^~ ] uri { ... } location @name { ... } Default: — Context: server, location
=
精确匹配,如果找到匹配=号的内容,立即停止搜索,并立即处理请求(优先级最高)
~
区分大小写
~*
不区分大小写
^~
只匹配字符串,不匹配正则表达式
@
指定一个命名的location,一般用于内部重定义请求,location @name {…}
官方的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 location = / { [ configuration A ] } location / { [ configuration B ] } location /documents/ { [ configuration C ] } location ^~ /images/ { [ configuration D ] } location ~* \.(gif|jpg|jpeg)$ { [ configuration E ] }
测试用的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 location / { return 401; } location = / { return 402; } location /documents/ { return 403; } location ^~ /images/ { return 404; } location ~* \.(gif|jpg|jpeg)$ { return 500; }
测试结果(重点看):
1 2 3 4 5 6 7 8 9 10 [root@lb01 conf]# curl -I -s -o /dev/null -w "%{http_code}\n" http://10.0.0.7/ 402 [root@lb01 conf]# curl -I -s -o /dev/null -w "%{http_code}\n" http://10.0.0.7/index.html 401 [root@lb01 conf]# curl -I -s -o /dev/null -w "%{http_code}\n" http://10.0.0.7/documents/document.html 403 [root@lb01 conf]# curl -I -s -o /dev/null -w "%{http_code}\n" http://10.0.0.7/images/1.gif 404 [root@lb01 conf]# curl -I -s -o /dev/null -w "%{http_code}\n" http://10.0.0.7/dddd/1.gif 500
结果总结: 匹配的优先顺序,=
>^~
(匹配固定字符串,忽略正则)> 完全相等
>~*
>空
>/
。
proxy_pass 模块解读 proxy_pass 指令属于ngx_http_proxy_module 模块,此模块可以将请求转发到另一台服务器。
写法:
1 proxy_pass http://localhost:8000/uri/;
实例一:
1 2 3 4 5 6 7 8 9 10 11 12 13 upstream blog_real_servers { server 10.0.0.9:80 weight=5; server 10.0.0.10:80 weight=10; server 10.0.0.19:82 weight=15; } server { listen 80; server_name blog.etiantian.org; location / { proxy_pass http://blog_real_servers; proxy_set_header host $host; } }
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;
配置后端服务器接收前端真实IP 配置如下:
1 2 3 4 log_format commonlog '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"';
rs_apache节点的httpd.conf配置
1 2 3 4 LogFormat "\"%{X-Forwarded-For}i\" %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{U ser-Agent}i\"" combined修改日志记录 apache LogFormat "\"%{X-Forwarded-For}i\" %l %u %t \"%r\" %>s %b" common
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实例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 [root@lb01 conf]# cat nginx.conf worker_processes 1; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; #blog lb by oldboy at 201303 upstream blog_real_servers { server 10.0.0.9:80 weight=1 max_fails=1 fail_timeout=10s; server 10.0.0.10:80 weight=1 max_fails=2 fail_timeout=20s; } server { listen 80; server_name blog.etiantian.org; location / { proxy_pass http://blog_real_servers; include proxy.conf; } } }
1 2 3 4 5 6 7 8 9 [root@lb01 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方法去请求 1 2 3 4 # if ($request_method !~ ^(GET|HEAD|POST)$ ) { return 444; }
实战 根据URI及location实现动静分离。 最终实现:
/static/的URL都去访问10.0.0.9。
/dynamic/的URL都去访问10.0.0.10。
图片这些静态文件去访问10.0.0.9。
/upload/的URL都去访问10.0.0.10。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 [root@lb01 conf]# cat nginx.conf worker_processes 1; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; #blog lb by oldboy at 201303 upstream static_pools { server 10.0.0.9:80; } upstream dynamic_pools { server 10.0.0.10:80; } upstream upload_pools { server 10.0.0.9:80; } server { listen 80; server_name blog.biglittleant.cn; 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; } } }
实现苹果手机和安卓手机访问不同的地址 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 server { listen 80; server_name blog.etiantian.org; 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官网