Nginx入门篇(六)之反向代理和负载均衡
-
一、Nginx负载均衡集群 介绍
负载均衡(Load Balance)集群提供了一种行之有效的办法,来扩展网络设备和服务器负载、带宽和吞吐量,同时加强了网络数据处理能力,提供了网络的灵活性和可用性。
Nginx的负载均衡组件主要有2个:
ngx_http_proxy_module:proxy代理模块,用于把请求后端抛给服务器节点或upstream服务器池。
ngx_http_upstream_module:负载均衡模块,可以实现网站的负载均衡功能和几点的健康检查。
-
二、实现一个简单的负载均衡
(1)环境介绍
站点访问 访问主页 IP地址 角色 192.168.56.110:8081 welcome to bbs.abc.org 192.168.56.110 web1 192.168.56.111:8082 welcome to blog.abc.org 192.168.56.111 web2 www.abc.org 无 192.168.56.11 负载均衡
(2)配置bbs和blog站点并测试访问
[root@localhost vhosts]# vim bbs.abc.org.conf server { listen 8081; server_name 192.168.56.110; root /vhosts/html/bbs; index index.html index.htm index.php; } [root@localhost vhosts]# vim blog.abc.org.conf server { listen 8082; server_name 192.168.56.111; root /vhosts/html/blog; index index.html index.htm index.php; } [root@localhost vhosts]# curl 192.168.56.110:8081 welcome to bbs.abc.org [root@localhost vhosts]# curl 192.168.56.111:8082 welcome to blog.abc.org
(3)配置负载均衡
[root@localhost vhosts]# cat www.abc.org.conf upstream web_server{ //配置负载均衡池 server 192.168.56.110:8081 weight=1; server 192.168.56.111:8082 weight=1; } server { listen 80; server_name www.abc.org abc.org; root /vhosts/html/www; index index.html index.php index.htm; access_log logs/www.abc.org_access.log main; error_log logs/www.abc.org_error.log info; location /{ proxy_pass http://web_server; //反向代理到负载均衡池 } location ~ \.php$ { root /vhosts/html/www; fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } } [root@localhost vhosts]# nginx -t nginx: the configuration file /usr/local/nginx1.15.1/conf/nginx.conf syntax is ok nginx: configuration file /usr/local/nginx1.15.1/conf/nginx.conf test is successful [root@localhost vhosts]# nginx -s reload [root@localhost vhosts]# curl www.abc.org //测试访问是否实现轮询bbs和blog welcome to bbs.abc.org [root@localhost vhosts]# curl www.abc.org welcome to blog.abc.org [root@localhost vhosts]# curl www.abc.org welcome to bbs.abc.org [root@localhost vhosts]# curl www.abc.org welcome to blog.abc.org
-
三、Nginx负载均衡组件介绍
1、upstream模块
Nginx的负载均衡功能依赖于ngx_http_upstream_module模块,可支持代理的方式有:proxy_pass、fastcgi_pass、memcached_pass等。该模块允许Nginx定义一组或多组节点服务器组,使用时,通过proxy_pass代理方式把网站的请求发送到实现定义好的upstream组的名称上,具体的格式为"proxy_pass http://web_server_pools",其中web_server_pools为upstream节点服务器组名称。下面举例说明:
upstream web_server{ server 192.168.56.110:8081 weight=1 max_fails=1 fail_timeout=10s; server 192.168.56.111:8082 weight=1 max_fails=1 fail_timeout=10s;
server 192.168.56.112:8083 weight=1 max_fails=1 fail_timeout=10s backup;
server 192.168.56.113:8084 weight=1 max_fails=1 fail_timeout=10s down; }
upstream参数说明:
server 192.168.56.110:8081 表示的是负载均衡后端的RS配置,可以是IP或者域名,如果端口不写,默认为80端口,高并发场景下,IP可以换成域名,通过DNS做负载均衡
weight=1 代表服务器的权重,默认为1。权重数字越大表示接受的请求比例越大
max_fails=1 表示Nginx尝试连接后端主机失败的次数,这个值是配置proxy_next_upstream、fastcgi_next_upstream和memcached_next_upstream这3个参数使用,当Nginx接收后端服务器返回这3个参数定义的状态码时,会把这个请求转发给正常工作的后端RS
fail_timeout=10s 在max_fails定义的的失败次数后,距离下一次检查的时间间隔,默认为10s
backup 热备配置(RS节点高可用)表示这个服务器作为备份服务器,当主服务器全部宕机,就会向这个服务器转发请求
down 表示该服务器永远不可用,这个参数可以配合ip_hash使用
2、upstream的调度算法
调度算法一般分为2类,一种是静态调度算法,例如:rr、wrr、ip_hash等,负载均衡器根据自身设定的规则进行分配,不考虑后端节点服务器的情况。
一种是动态调度算法,例如least_conn、fair等,负载均衡器会根据后端节点服务器的当前状态来决定是否分发请求。
(1)rr轮询(默认调度算法,静态调度算法)
按客户端请求顺序依次将客户端的请求逐一分配到不同的后端服务器节点,和LVS的rr算法一样,如果后端节点服务器宕机,宕机的服务器会从服务器池中剔除,保证用户访问的正常。
(2)wrr(权重轮询,静态调度算法)
在rr轮询的基础上增加权重,使用该算法时,权重和用户访问成比例,权重越大,请求数越多。
(3)ip_hash(静态调度算法)
每个请求按照客户端的ip的hash结果分配,当新的请求到达,先将客户端IP通过哈希算法哈希出一个值,在随后的客户端请求中,客户的IP哈希值只要相同,就会被分配到同一台服务器上。该调度算法可以解决动态网页的session共享问题,但也会导致请求分配不均匀。需要注意的是当负载均衡调度算法为ip_hash时,后端服务器在负载均衡调度中的状态不能使用weight和backup,即使配置了也不会生效。
(4)fair(动态调度算法)
该算法会根据后端服务器的响应时间来分配请求,响应时间较短的有限分配。这种算法更加的智能,可以根据页面大小和加载时长智能地进行负载均衡。Nginx本身不支持fair调度算法,如果需要使用这种算法,需要下载Nginx的相关模块upstream_fair
(5)least_conn
该算法会根据后端节点的连接数来决定分配请求,哪个机器的连接数少就优先分配。
(6)url_hash算法
根据访问的URL的hash结果来分配请求,让每个URL定向到同一个后端服务器,后端服务器为缓存服务器时效果显著,可以提高后端缓存服务器的命中率。Nginx本身不支持这种算法,需要安装hash模块软件包。
3、http_proxy_module模块和参数
proxy_pass指令属于ngx_http_proxy_module模块,此模块可以将请求转发到另一台服务器上,在实际的反向代理中,会通过location功能匹配指定的URI,然后把符合匹配规则的URI请求通过proxy_pass指向定义好的upstream池。
http_proxy模块的相关参数:
proxy_set_header 设置http请求header项传给后端服务器节点,例如:可以实现让代理后端的服务器节点获取访问客户端用户的真是ip地址 client_body_buffer_size 用于指定客户端请求主题缓冲区大小 proxy_connect_timeout 表示反向代理和后端节点服务器连接的超时时间,即发起三次握手等候响应的超时时间 proxy_send_timeout 表示代理后端服务器的数据回传时间,即在规定时间内后端服务器必须传完所有数据,否则,Nginx将会断开连接 proxy_read_timeout 设置Nginx从代理的后端服务器获取信息的时间,表示连接建立成功后,Nginx等待后端服务器的响应时间,其实是Nginx已经进入了后端的排队之中等待处理的时间 proxy_buffer_size 设置缓冲区大小,默认该缓冲区大小等于指令proxy_buffers设置的大小 proxy_buffers 设置缓冲区的数量和大小。Nginx从代理的后端服务器获取的响应信息,会放置到缓冲区 proxy_busy_buffers_size 用于设置系统繁忙时期可以使用的proxy_buffers大小,推荐大小为proxy_buffers*2 proxy_temp_file_write_size 指定proxy缓存临时文件的大小
举个简单的反向代理的例子:
[root@localhost vhosts]# !vim vim www.abc.org.conf server { listen 80; server_name www.abc.org abc.org; root /vhosts/html/www; index index.html index.php index.htm; access_log logs/www.abc.org_access.log main; error_log logs/www.abc.org_error.log debug; location /bbs { proxy_pass http://192.168.56.110:8081/; //配置当访问www.abc.org/bbs时,反向代理到192.168.56.110:8081这台服务器上 } location ~ \.php$ { root /vhosts/html/www; fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } } [root@localhost ~]# curl http://www.abc.org/bbs //测试访问 welcome to bbs.abc.org
-
四、Nginx负载均衡实际应用
1、环境说明
主机名 | IP地址 | 角色说明 |
web01 | 192.168.56.12 | nginx web01服务器 |
web02 | 192.168.56.13 | nginx web02服务器 |
lb | 192.168.56.11 | nginx负载均衡器 |
2、Nginx反向代理负载均衡实践
(1)在web01和web02上yum安装nginx,并同样修改nginx.conf
[root@web01 ~]# yum install -y nginx [root@web02 ~]# yum install -y nginx [root@web01 ~]# cat /etc/nginx/nginx.conf user nginx; worker_processes auto; error_log /var/log/nginx/error.log; pid /run/nginx.pid; include /usr/share/nginx/modules/*.conf; events { worker_connections 1024; } http { log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout 65; types_hash_max_size 2048; include /etc/nginx/mime.types; default_type application/octet-stream; include /etc/nginx/conf.d/*.conf; server { listen 80; server_name bbs.abc.org; root /application/html/bbs; index index.php index.html index.htm; } server { listen 80; server_name www.abc.org; root /application/html/www; index index.php index.html index.htm; } }
(2)配置web01和web02的host解析
[root@web01 ~]# cat /etc/hosts 192.168.56.12 bbs.abc.org www.abc.org [root@web02 ~]# cat /etc/hosts 192.168.56.13 bbs.abc.org www.abc.org
(3)配置主页index.html,并测试访问
root@web01 ~]# mkdir /application/html/{www,bbs} -pv [root@web01 ~]# echo "welcome to use bbs.abc.org 12" > /application/html/bbs/index.html [root@web01 ~]# echo "welcome to use www.abc.org 12" > /application/html/www/index.html [root@web02 ~]# mkdir /application/html/{www,bbs} -pv [root@web02 ~]# echo "welcome to use bbs.abc.org 13" > /application/html/bbs/index.html [root@web02 ~]# echo "welcome to use www.abc.org 13" > /application/html/www/index.html [root@web01 ~]# curl www.abc.org welcome to use www.abc.org 12 [root@web01 ~]# curl bbs.abc.org welcome to use bbs.abc.org 12 [root@web02 ~]# curl www.abc.org welcome to use www.abc.org 13 [root@web02 ~]# curl bbs.abc.org welcome to use bbs.abc.org 13
(4)配置负载均衡器
[root@lb vhosts]# vim www.abc.org.conf upstream web_server{ server 192.168.56.12:80 weight=1; server 192.168.56.13:80 weight=1; } server { listen 80; server_name www.abc.org abc.org; root /vhosts/html/www; index index.html index.php index.htm; access_log logs/www.abc.org_access.log main; error_log logs/www.abc.org_error.log debug; location /{ proxy_pass http://web_server; } } [root@lb vhosts]# nginx -t nginx: the configuration file /usr/local/nginx1.15.1/conf/nginx.conf syntax is ok nginx: configuration file /usr/local/nginx1.15.1/conf/nginx.conf test is successful [root@lb vhosts]# nginx -s reload
(5)lb上绑定hosts解析,测试访问
[root@localhost vhosts]# cat /etc/hosts 192.168.56.11 www.abc.org bbs.abc.org [root@lb vhosts]# curl www.abc.org welcome to use bbs.abc.org 12 [root@lb vhosts]# curl www.abc.org welcome to use bbs.abc.org 13
从上面的测试结果可以看到,正常地实现了反向代理和负载均衡,但是细致地看一看,发现在访问www.abc.org时,返回的的结果是welcome to use bbs.abc.org 12以及welcome to use bbs.abc.org 13,和我们想要访问到的结果:welcome to use www.abc.org 12以及welcome to use www.abc.org 13大相径庭,完全不一致!!这又是什么原因呢?
在配置虚拟主机时,在web01和web02分别配置了2个虚拟主机,一个是bbs.abc.org,一个www.abc.org。bbs虚拟主机放在了前面,这点很重要。那么当用户访问www.abc.org时,请求头部携带了www.abc.org主机头部请求Nginx的反向代理服务器,但是在反向代理服务器向后端服务器web01或web02重新发起请求时,默认并没有在请求头部信息告诉web01或web02要请求的是哪台虚拟主机。所以,web服务器接收到请求后发现并没有主机头信息,因此web01或web02就直接将第一个虚拟主机(bbs.abc.org)发给了反向代理服务器了。
那么这问题又该如何解决呢?就是当反向代理向后端服务器发起请求时,要携带主机头信息,以明确指明需要访问的虚拟主机。具体配置也简单,增加一行如下配置即可:
proxy_set_header Host $host;
在代理向后端发送请求时,在http请求头部加入了host字段信息后,如果后端配置了多个虚拟主机,它就可以识别代理的是哪个虚拟主机。重新配置后,访问如下:
[root@localhost vhosts]# vim www.abc.org.conf upstream web_server{ server 192.168.56.12:80 weight=1; server 192.168.56.13:80 weight=1; } server { listen 80; server_name www.abc.org abc.org; root /vhosts/html/www; index index.html index.php index.htm; access_log logs/www.abc.org_access.log main; error_log logs/www.abc.org_error.log debug; location /{ proxy_set_header Host $host; proxy_pass http://web_server; } } [root@localhost vhosts]# nginx -t nginx: the configuration file /usr/local/nginx1.15.1/conf/nginx.conf syntax is ok nginx: configuration file /usr/local/nginx1.15.1/conf/nginx.conf test is successful [root@localhost vhosts]# nginx -s reload [root@localhost vhosts]# curl www.abc.org welcome to use www.abc.org 12 [root@localhost vhosts]# curl www.abc.org welcome to use www.abc.org 13
可以看到最后的返回结果为:welcome to use www.abc.org 12以及welcome to use www.abc.org 13,这就是proxy_set_header参数的作用。
3、反向代理后后端服务器记录用户真实IP
在反向代理实现后,在windows客户端做hosts解析,并访问,在web01或web02上查看访问日志,如下:
[root@web01 ~]# cat /var/log/nginx/www.abc.org_access.log 192.168.56.11 - - [20/Jul/2018:05:51:53 -0400] "GET / HTTP/1.0" 200 30 "-" "curl/7.29.0" 192.168.56.12 - - [20/Jul/2018:05:52:50 -0400] "GET / HTTP/1.1" 200 30 "-" "curl/7.29.0" 192.168.56.11 - - [20/Jul/2018:05:53:17 -0400] "GET / HTTP/1.0" 200 30 "-" "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36" 192.168.56.11 - - [20/Jul/2018:05:53:40 -0400] "GET / HTTP/1.0" 200 30 "-" "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36"
可以看到对应的www.abc.org虚拟主机的访问日志记录的并不是客户端ip,而是反向代理服务器的ip,那么如何获取用户的真是ip呢?其实只需要增加以下参数即可:
proxy_set_header X-Forwarded-For $remote_addr;
表示在代理向后端服务器发送的http请求头中加入X-Forwarded-For字段信息,用于后端服务器程序、日志等接收记录真实用户的ip,而不是代理服务器的ip。在使用反向代理时,节点服务器获取用户真实ip的必要配置。
[root@localhost vhosts]# !vim //修改负载均衡器的配置 vim www.abc.org.conf upstream web_server{ server 192.168.56.12:80 weight=1; //此处删除了web02,作为测试机访问 } server { listen 80; server_name www.abc.org abc.org; location /{ proxy_pass http://web_server; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $remote_addr; //配置记录真实ip } } [root@web02 nginx]# curl www.abc.org //在web02上配置hosts解析访问www.abc.org welcome to use www.abc.org 12 [root@web01 ~]# tail -2 /var/log/nginx/www.abc.org_access.log 192.168.56.11 - - [20/Jul/2018:23:20:52 -0400] "GET / HTTP/1.0" 200 30 "-" "curl/7.29.0" "192.168.56.13" 192.168.56.11 - - [20/Jul/2018:23:21:45 -0400] "GET /index.html HTTP/1.0" 200 30 "-" "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36" "192.168.56.1"
配置完成后,重载访问,查看web01上的日志可以看到,第一段表示的是$remote_addr,属于代理服务器的ip,而最后一行才是用户的真是ip记录。