Nginx反向代理与负载均衡
负载均衡和反向代理的概念
负载均衡
负载均衡是由多台服务器以对称的方式组成一个服务器集合,每台服务器都具有等价的地位,都可以单独对外提供服务而无需其它服务器辅助。通过某种负载均衡技术,将外部发送来的请求均匀分配到对称结构中的某一台服务器上,而接收到请求的服务器独立回应客户的请求。负载均衡能够平均分配客户请求到服务器阵列,做到快速获取数据,解决大量并发访问服务时响应慢问题。这种集群技术可以用最少的投资获得接近于大型主机的性能。
反向代理
反向代理(Reverse Proxy)是指以代理服务器来接受Internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给Internet上请求连接的客户端,此时代理服务器对外表现为一个服务器。
通常的代理服务器,只用于代理内部网络对Internet的连接请求,客户机必须指定代理服务器,并将本来要直接发送到Web服务器上的http请求发送到代理服务器中。由于外部网络上的主机并不会配置并使用这个代理服务器,普通代理服务器也被设计为在Internet上搜寻多个不确定的服务器,而不是针对Internet上多个客户机的请求访问某一个固定的服务器,因此普通的Web代理服务器不支持外部对内部网络的访问请求。
当一个代理服务器能够代理外部网络上的主机访问内部网络时,这种代理服务的方式称为反向代理服务。此时代理服务器对外就表现为一个Web服务器,外部网络就可以简单把它当做一个标准的Web服务器而不需要特定的配置。不同之处在于,这个服务器没有保存任何网页的真实数据,所有的静态网页或CGI程序,都保存在内部的Web服务器上。因此对反向代理服务器的攻击并不会使网页信息遭到破坏,这样就增强了Web服务器的安全性。
反向代理方式和包过滤方式或普通代理方式并无冲突,因此可以在防火墙设备中同时使用这两种方式,其中反向代理用于外部网络访问内部网络时使用,正向代理或包过滤方式用于拒绝其它外部访问方式并提供内部网络对外部网络的访问能力。因此可以结合这些方式提供最佳的安全访问方式。
常见Web负载均衡方法
负载均衡的方法有很多,例如:用户自动选择方式(一些软件下载网站一般使用这种方式,提供多个下载链接,供用户自主选择)、DNS轮询方式、四/七层负载均衡设备等方法。
Nginx负载均衡与反向代理的配置实例
完整的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 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 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
| user www www;
worker_processes auto;
error_log /home/wwwlogs/nginx_error.log crit;
pid /usr/local/nginx/logs/nginx.pid;
worker_rlimit_nofile 51200;
events { use epoll; worker_connections 51200; multi_accept on; }
http { include mime.types; default_type application/octet-stream;
server_names_hash_bucket_size 128; client_header_buffer_size 32k; large_client_header_buffers 4 32k;
sendfile on; tcp_nopush on;
keepalive_timeout 60;
tcp_nodelay on;
fastcgi_connect_timeout 300; fastcgi_send_timeout 300; fastcgi_read_timeout 300; fastcgi_buffer_size 64k; fastcgi_buffers 4 64k; fastcgi_busy_buffers_size 128k; fastcgi_temp_file_write_size 256k;
gzip on; gzip_min_length 1k; gzip_buffers 4 16k; gzip_http_version 1.1; gzip_comp_level 2; gzip_types text/plain application/javascript application/x-javascript text/javascript text/css application/xml application/xml+rss; gzip_vary on; gzip_proxied expired no-cache no-store private auth; gzip_disable "MSIE [1-6]\.";
server_tokens off; access_log off; client_max_body_size 300m; clinet_body_buffer_size 128k; proxy_connect_timeout 600; proxy_read_timeout 600; proxy_send_timeout 600; proxy_buffer_size 16k; proxy_busy_buffers_size 64k; proxy_temp_file_write_size 64k; upstream php_server_pool { server 192.168.1.10:80 weight=4 max_fails=2 fail_timeout=30s; server 192.168.1.11:80 weight=4 max_fails=2 fail_timeout=30s; server 192.168.1.12:80 weight=2 max_fails=2 fail_timeout=30s; } upstream message_server_pool { server 192.168.1.13:3245; server 192.168.1.14:3245 down; } upstream bbs_server_pool { server 192.168.1.15:80 weight=1 max_fails=2 fail_timeout=30s; server 192.168.1.16:80 weight=1 max_fails=2 fail_timeout=30s; server 192.168.1.17:80 weight=1 max_fails=2 fail_timeout=30s; server 192.168.1.18:80 weight=1 max_fails=2 fail_timeout=30s; }
server { listen 80; server_name www.yorudomain.com; location / { proxy_next_upstream http_504 error timeout invalid_header; proxy_pass http://php_server_pool; proxy_set_header Host www.yourdomain.com; proxy_set_header X-Forwarded-For $remote_addr; }
access_log /data1/logs/www.yourdomain.com_access.log; }
server { listen 80; server_name www1.yourdomain.com; location /message/ { proxy_pass http://message_server_pool; proxy_set_header Host $host; } location / { proxy_pass http://php_server_pool; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $remote_addr; } access_log /data1/logs/message.yourdomain.com_access.log; }
server { listen 80; server_name bbs.yourdomain.com *.bbs.yourdomain.com; location / { proxy_pass http://bbs_server_pool; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $remote_addr; } access_log off; } }
|
通过上述示例,我们已经看到Nginx对于多个域名的负载均衡是如何配置的。Upstream
指令用于设置一组可以在proxy_pass
和fastcgi_pass
指令中使用的代理服务器,默认负载均衡的方式为轮询。Upstream
模块中的Server
指令用于指定后端服务器的名称和参数,服务器的名称可以是一个域名、一个IP地址、端口号或UNIX Socket
。
而在server{...}
虚拟机内,可以通过proxy_pass
和fastcgi_pass
指令设置进行反向代理的upstream
服务器集群。
proxy_set_header
指令用于在向反向代理的后端Web服务器发起请求时添加指定的Header头信息。
当后端Web服务器上有多个基于域名的虚拟主机时,要通过添加Header头信息的Host,用于指定请求的域名,这样后端Web服务器才能识别该反向代理访问请求由哪一个虚拟主机来处理。
使用反向代理之后,后端Web服务器(以PHP为例)就不能直接通过$_SERVER["REMOTE_ADDR"]
变量来获取用户的真实IP了,通过$_SERVER["REMOTE_ADDR"]
获取的将是Nginx负载均衡服务器的IP。
这时,就要通过在Nginx反向代理时添加Header头信息X-Forwarded-For
,让后端Web服务器(以PHP为例)能够通过$_SERVER["HTTP_X_FORWARDED_FOR"]
获取用户的真实IP。
Nginx负载均衡与反向代理实现动、静态网页分离
Nginx负载均衡的HTTP Upstream模块
ip_hash指令
ip_hash
语法:ip_hash
默认值:none
使用环境:upstream
当对后端的多台动态应用服务器做负载均衡时,ip_hash
指令能够将某个客户端IP的请求通过哈希算法定位到同一台后端服务器上。这样,当来自某个IP的用户在后端Web服务器A上登录后,再访问该站点的其它URL,能够保证其访问的还是后端Web服务器A。如果不采用ip_hash
指令,假设来自某个IP的用户在后端Web服务器A上登录后,再访问该站点的其它URL,有可能被定向到后端Web服务器B,C,…上,由于用户登录后SESSION信息是记录在服务器A上的,B,C,…上没有,这时就会提示用户未登录。
使用ip_hash
指令无法保证后端服务器的负载均衡,可能有些后端服务器接收到的请求多,有些后端服务器接收到的请求少,而且设置后端服务器权重等方法将不起作用。所以,如果后端的动态应用服务器能够做到SESSION共享,还是建议采用后端服务器的SESSION共享方式来代替Nginx的ip_hash
方式。
如果后端服务器有时要从Nginx负载均衡(已使用ip_hash
)中摘除一段时间,你必须将其标记为“down”,而不是直接从配置文件中删掉或注释掉该后端服务器信息。代码示例如下:
1 2 3 4 5 6 7
| upstream backend { ip_hash; server backend1.example.com; server backend2.example.com; server backend3.example.com down; server backend4.example.com; }
|
这样,当原来为4台后端服务器时,摘除backend3.examole.com(标记为“down”)后,Nginx仍然会按4台服务器进行哈希。如果直接注释掉"server backend3.example.com;"
这行,Nginx就会按照3台服务器进行重新哈希,原来被哈希到backend1.example.com的客户端IP有可能被哈希到backend2.example.com服务器上,原有的SESSION就会失效。
server指令
server
语法:server name [parameters]
默认值:none
使用环境:upstream
该指令用于指定后端服务器的名称和参数。服务器的名称可以是一个域名、一个IP地址、端口号或UNIX Socket。
在后端服务器名称之后,可以跟以下参数:
weight=NUMBER 设置服务器的权重,权重数值越高,被分配到的客户端请求数越多。如果没有设置权重,则为默认权重1.
max_fails
=NUMBER 在参数fail_timeout
指定的时间内对后端服务器请求失败的次数,如果检测到后端服务器无法连接及发生服务器错误(404错误除外),则标记为失败。如果没有设置,则为默认值1.设为数值0则关闭这项检查。
fail_timeout
=TIME 在经理参数max_fails
设置的失败次数后,暂停的时间。
down 标记为服务器为永久离线状态,用于ip_hash
指令。
backup 仅仅在非backup服务器全部宕机或繁忙的时候才启用。
示例如下:
1 2 3 4 5
| upstream backend { server backend1.example.com weight=5; server 127.0.0.1:8080 max_fails=3 fail_timeout=30s; server unix:/tmp/backend3; }
|
upstream指令
upstream
语法:upstream name {…}
默认值:none
使用环境:http
该指令用于设置一组可以在proxy_pass
和fastcgi_pass
指令中使用的代理服务器,默认的负载均衡方式为轮询。示例如下:
1 2 3 4 5
| upstream backend { server backend1.example.com weight=5; server 127.0.0.1:8080 max_fails=3 fail_timeout=30s; server unix:/tmp/backend3; }
|
upstream相关变量
Nginx设置日志格式的log_format
指令中,可以使用变量,例如:
1 2 3 4 5 6
| log_format timing '$remote_addr - $remote_user [$time_local] $request ' 'upstream_response_time $upstream_response_time ' 'msec $msec request_time $request_time';
log_format up_head '$remote_addr - $remote_user [$time_local] $request ' 'upstream_http_content_type $upstream_http_content_type';
|
$upstream_addr
处理请求的upstream服务器地址。
$upstream_status
Upstream服务器的应答状态。
$upstream_response_time
Upstream服务器响应时间(毫秒),多个响应以逗号和冒号分隔。
$upstream_http_$HEADER
任意HTTP协议头信息,例如:$upstream_http_host
Nginx负载均衡的双机高可用