nginx反向代理+负载均衡+url重写+ssl认证
Nginx (engine x) 是一个高性能的HTTP和反向代理服务器,也是一个IMAP/POP3/SMTP服务器。Nginx是由伊戈尔·赛索耶夫为俄罗斯访问量第二的Rambler.ru站点(俄文:Рамблер)开发的,第一个公开版本0.1.0发布于2004年10月4日。
其将源代码以类BSD许可证的形式发布,因它的稳定性、丰富的功能集、示例配置文件和低系统资源的消耗而闻名。2011年6月1日,nginx 1.0.4发布。
Nginx是一款轻量级的Web 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器,并在一个BSD-like 协议下发行。其特点是占有内存少,并发能力强,事实上nginx的并发能力确实在同类型的网页服务器中表现较好,中国大陆使用nginx网站用户有:百度、京东、新浪、网易、腾讯、淘宝等。
介绍
nginx功能:提供web服务,http反向代理 ,缓存功能,负载均衡配置,支持SSL,nginx动静分离,URL重写,日志分割
一般nginx只服务静态页面,nginx基于cgi工作的场景并不是特别的多,而且性能伐善可陈,所以通常会把nginx与mysql、PHP结合,配成为LNMP
使用nginx服务静态页面时有apache无法比拟的性能优势,如果用不到apache某些功能的特性的话,并且nginx能满足我们当前的所有需要,建议使用nginx当做web服务器(web服务器只能服务静态页面)
nginx官方站点 www.nginx.org 是有俄罗斯一个程序员编写的程序,是专门用来为公司做内部站点反向代理
在国内有很多的门户站点都开始使用nginx做门户站点的服务器了
nginx相对于apache的优点:
轻量级,同样起web 服务,比apache 占用更少的内存及资源
抗并发,nginx 处理请求是异步非阻塞的,而apache 则是同步阻塞型的,在高并发下nginx 能保持低资源低消耗高性能
(非堵塞:现在在进行I/O操作时,无需等到数据的返回,可以接着往下执行代码命令,cpu得到充分的利用; 堵塞:在执行I/O操作获取数据时,这个IO可能会需要一定的时间才能得到数据返回,才能接着执行接下来的命令,而cpu不能得到充分的利用)
(同步:是指当线程进行IO操作请求操作时,是你主动关心数据的返回; 异步:时至线程无需关心数据是否返回,当数据返回时,会有相关的时间通知你)
高度模块化的设计,编写模块相对简单,只能在安装的时候进行编译,但是不能在线添加,阿里已经解决这种问题了,开发了tenginx
apache 相对于nginx 的优点:
rewrite(URL重写功能),比nginx 的rewrite 强大
模块超多,基本想到的都可以找到,能够在线添加模块
少bug ,nginx 的bug 相对较多
为什么nginx性能要比apache高?
这要得益于nginx是使用了最新的epoll网络I/O模型(列队处理),而apache使用的是传统的select网络I/O模型(轮询处理)
内容,假设你在上大学
所以在高并发的服务器中轮询I/O是最耗时的操作之一
nginx中文参考文档:http://www.nginx.cn/doc/
nginx软件下载地址:http://nginx.org/en/download.html
Mainline version:Mainline 是 Nginx 目前主力在做的版本,可以说是开发版
Stable version:最新稳定版,生产环境上建议使用的版本
Legacy versions:遗留的老版本的稳定版
开始安装
安装依赖包
yum -y install gcc gcc-c++ autoconf automake zlib zlib-devel openssl openssl-devel pcre pcre-devel gd-*
创建用户
groupadd nginx
useradd -g nginx -s /sbin/nologin nginx
nginx解压安装
cd /usr/local/src
mkdir -p /usr/local/nginx
tar -zxvf nginx-1.10.1.tar.gz
cd nginx-1.10.1
./configure \
--prefix=/usr/local/nginx \
--lock-path=/usr/local/nginx/nginx.lock \
--user=nginx \
--group=nginx \
--with-http_ssl_module --with-http_flv_module \
--with-http_stub_status_module --with-http_gzip_static_module \
--http-client-body-temp-path=/usr/local/nginx/client/ \
--http-proxy-temp-path=/usr/local/nginx/proxy/ \
--http-fastcgi-temp-path=/usr/local/nginx/fcgi/ \
--http-uwsgi-temp-path=/usr/local/nginx/uwsgi \
--http-scgi-temp-path=/usr/local/nginx/scgi --with-pcre \
--with-file-aio --with-http_image_filter_module
make
make install
以下是http功能模块类中常见的模块。
http类模块名 | 模块功能说明 | |
ngx_http_core_module | http核心模块,对应配置文件中的http段,包含很多指令,如location指令 | |
ngx_http_access_module | 访问控制模块,控制网站用户对nginx的访问,对应于配置文件中的allow和deny等指令 | |
ngx_http_auth_basic_module | 通过用户名和密码认证的访问控制,如访问站点时需要数据用户名和密码,指令包括auth_basic和auth_basic_user_file | |
ngx_http_charset_module | 设置网页显示字符集。指令之一为charset,如charset utf-8 | |
ngx_http_fastcgi_module | fastcgi模块,和动态应用相关。该模块下有非常多的子模块。 | |
ngx_http_flv_module | 支持flv视频流的模块,如边下边播 | |
ngx_http_mp4_module | 同flv模块 | |
ngx_http_gzip_module | 压缩模块,用来压缩nginx返回的响应报文。一般只压缩纯文本内容,因为压缩比例非常大,而图片等不会去压缩 | |
ngx_http_image_filter_module | 和图片裁剪、缩略图相关模块,需要安装gd-devel才能编译该模块 | |
ngx_http_index_module | 定义将要被作为默认主页的文件,对应指令为index。"index index.html,index.php" | |
ngx_http_autoindex_module | 当index指令指定的主页文件不存在时,交给autoindex指令,将自动列出目录中的文件autoindex {on/off} | |
ngx_http_log_module | 和访问日志相关的模块,指令包括log_format和access_log | |
ngx_http_memcached_module | 和memcached相关的模块,用于从memcached服务器中获取相应响应数据 | |
ngx_http_proxy_module | 和代理相关,允许传送请求到其它服务器 | |
ngx_http_realip_module | 当nginx在反向代理的后端提供服务时,获取到真正的客户端地址,否则获取的是反向代理的IP地址 | |
ngx_http_referer_module | 实现防盗链功能的模块 | |
ngx_http_rewrite_module | 和URL地址重写相关的模块,需要安装pcre-devel才能编译安装该模块 | |
ngx_http_scgi_module | simple cgi,是cgi的替代品,和fastcgi类似,但更简单 | |
ngx_http_ssl_module | 提供ssl功能的模块,即实现HTTPS | |
ngx_http_stub_status_module | 获取nginx运行状态信息 | |
ngx_http_upstream | 和负载均衡相关模块 |
这些模块共同组成了nginx的http功能。
Nginx的基本操作
验证Nginx的配置文件是否正确
[root@nginx sbin]# /usr/local/nginx/sbin/nginx -t
重加载Nginx
[root@nginx sbin]# /usr/local/nginx/sbin/nginx -s reload
关闭Nginx
[root@nginx sbin]# /usr/local/nginx/sbin/nginx -s stop
启动Nginx
[root@nginx sbin]# /usr/local/nginx/sbin/nginx
性能测试
开启nginx监控
location /nginx_status {
stub_status on;
access_log off;
allow all; 访问IP
#deny all;
}
#active connections – 活跃的连接数量
#server accepts handled requests — 总共处理了11989个连接 , 成功创建11989次握手, 总共处理了11991个请求
#reading — 读取客户端的连接数.
#writing — 响应数据到客户端的数量
#waiting — 开启 keep-alive 的情况下,这个值等于 active – (reading+writing), 意思就是 Nginx 已经处理完正在等候下一次请求指令的驻留连接.
日志分割
日志格式
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 logs/access.log main;
这段内容什么意思呢?我们来理解下。
$remote_addr:客户端的ip地址(如果中间有代理服务器那么这里显示的ip就为代理服务器的ip地址)
$remote_user:用于记录远程客户端的用户名称(一般为“-”)
$time_local:用于记录访问时间和时区
$request:用于记录请求的url以及请求方法
$status:响应状态码
$body_bytes_sent:给客户端发送的文件主体内容大小
$http_referer:可以记录用户是从哪个链接访问过来的
$http_user_agent:用户所使用的代理(一般为浏览器)
$http_x_forwarded_for:可以记录客户端IP,通过代理服务器来记录客户端的ip地址
通常web服务器放在反向代理的后面,这样就不能获取到客户的IP地址了,通过$remote_add拿到的IP地址是反向代理服务器的iP地址。反向代理服务器在转发请求的http头信息中,可以增加x_forwarded_for信息,用以记录原有客户端的IP地址和原来客户端的请求的服务器地址。
Nginx日志按天切割
编写Shell脚本splitLog.sh(记住为splitLog.sh添加可执行权限):
# /bin/bash # 日志保存位置
base_path='/opt/nginx/logs'
# 获取当前年信息和月信息
log_path=$(date -d yesterday +"%Y%m")
# 获取昨天的日信息
day=$(date -d yesterday +"%d")
# 按年月创建文件夹
mkdir -p $base_path/$log_path
# 备份昨天的日志到当月的文件夹
mv $base_path/access.log $base_path/$log_path/access_$day.log
# 输出备份日志文件名 #
echo $base_path/$log_path/access_$day.log
# 通过Nginx信号量控制重读日志
kill -USR1 `cat /opt/nginx/logs/nginx.pid`
添加Linux定时任务
crontab -e
# 每天0时1分进行日志分割(建议在02-04点之间,系统负载小)
01 00 * * * /opt/nginx/logs/splitLog.sh
重启Linux定时任务
crond restart
如果提示以下错误
crond: can't lock /var/run/crond.pid, otherpid may be 4141: 资源暂时不可用
删除/var/run/crond.pid 重新执行命令即可
反向代理
反向代理应该是 Nginx 做的最多的一件事了,什么是反向代理呢,以下是百度百科的说法:反向代理(Reverse Proxy)方式是指以代理服务器来接受 internet上 的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给 internet 上请求连接的客户端,此时代理服务器对外就表现为一个反向代理服务器。简单来说就是真实的服务器不能直接被外部网络访问,所以需要一台代理服务器,而代理服务器能被外部网络访问的同时又跟真实服务器在同一个网络环境,当然也可能是同一台服务器,端口不同而已。
开启日志分隔
log_format main '$remote_addr "$http_x_real_ip" - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
server {
listen 80;
server_name localhost;
client_max_body_size 1024M;
location / {
proxy_pass http://localhost:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
保存配置文件后启动 Nginx,这样当我们访问 localhost 的时候,就相当于访问 localhost:8080 了。
proxy_set_header参数解释
proxy_set_header Host $host;
允许重新定义或添加字段传递给代理服务器的请求头。该值可以包含文本、变量和它们的组合。在没有定义proxy_set_header时会继承之前定义的值。
默认情况下,只有两个字段被重定义:
proxy_set_header Host $proxy_host;
proxy_set_header Connection close;
实例说明:
nginx对于upstream默认使用的是基于IP的转发,如下配置:
[root@localhost nginx]# cat test.conf
upstream backend {
server 127.0.0.1:8080;
}
upstream china {
server china.wangshibo.com;
}
server {
listen 80;
server_name www.wangshibo.com;
proxy_set_header Host $http_host;
proxy_set_header x-forwarded-for $remote_addr;
proxy_buffer_size 64k;
proxy_buffers 32 64k;
charset utf-8;
access_log logs/host.access.log main;
location = /50x.html {
root html;
}
location / {
proxy_pass backend ;
}
location = /customer/straightcustomer/download {
proxy_pass http://china;
proxy_set_header Host $proxy_host;
}
}
当匹配到/customer/straightcustomer/download时,使用china处理,到upstream就匹配到china.wangshibo.com,这里直接转换成IP进行转发了。
假如china.wangshibo.com是在另一台nginx下配置的,ip为10.22.10.116,则$proxy_host则对应为10.22.10.116。
此时相当于设置了Host为10.22.10.116。如果想让Host是china.wangshibo.com,则进行如下设置:
proxy_set_header Host china.wangshibo.com;
如果不想改变请求头“Host”的值,可以这样来设置:
proxy_set_header Host $http_host;
但是,如果客户端请求头中没有携带这个头部,那么传递到后端服务器的请求也不含这个头部。 这种情况下,更好的方式是使用$host变量——它的值在请求包含“Host”请求头时为“Host”字段的值,在请求未携带“Host”请求头时为虚拟主机的主域名:
proxy_set_header Host $host;
此外,服务器名可以和后端服务器的端口一起传送:
proxy_set_header Host $host:$proxy_port;
如果某个请求头的值为空,那么这个请求头将不会传送给后端服务器:
proxy_set_header Accept-Encoding "";
3)有了下面三行配置,就可以在web的后端节点服务器端获得客户端用户的真实ip。
proxy_set_header X-Real-IP $remote_addr; //后端节点机器获取客户端真实ip的第一种方案
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; //后端节点机器获取客户端真实ip的第二中方案。当然这两种方案也可以一起配置!
其中这个X-real-ip是一个自定义的变量名,名字可以随意取,这样做完之后,用户的真实ip就被放在X-real-ip这个变量里了,然后,在web端可以这样获取:
request.getAttribute("X-real-ip")
remote_addr 代表客户端的ip,但它的值不是由客户端提供的,而是服务器端根据客户端的ip指定的,当你的浏览器访问某个网站时,假设中间没有任何代理,那么网站的web服务器(比如nginx)就会把remote_addr设置为
你的机器ip;如果你使用了代理,那么你的浏览器会先访问这个代理,然后再由这个代理转发到网站,这样web服务器就会把remote_addr设为这台代理机器的ip。
x_forwarded_for 正如上面所述,当你使用了代理时,web服务器就不知道你的真实ip了。为了避免这个情况,代理服务器通常会增加一个叫做x_forwarded_for的头消息,把连接它的客户端ip(即你的上网机器的ip)
加到这个头消息里,这样就能保证网站的web服务器能获得真实ip。
使用haproxy做反向代理
通常网站为了支撑更大的访问,会增加很多web服务器,并在这些服务器前面增加一个反向代理(如haproxy)它可以把负载均衡的分布到这些服务器上。你的浏览器访问的首先是这台反向代理服务器,它再把
你的请求转发到后面的web服务器上,这就使得web服务器会把remote_addr设为这台反向代理服务器的ip,为了能让你的程序获得真实的客户端ip,就需要给haproxy增加下面的配置:
option forwardfor
它的作用就像上面说的,增加一个x_forwarded_for的头信息,把你上网机器的ip添加进去。
-----------------------------------------------------------
实际上要获得用户的真实ip,不是只有这一个方法,下面我们继续看
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
这里有个X-Forwarded-For变量,这是一个squid开发的,用于识别通过HTTP代理或负载平衡器原始IP一个连接到Web服务器的客户机地址的非rfc标准,如果有做X-Forwarded-For设置的话,
每次经过proxy转发都会有记录,格式就是client1, proxy1, proxy2,以逗号隔开各个地址,由于他是非rfc标准,所以默认是没有的,需要强制添加,在默认情况下经过proxy转发的请求,
在后端看来远程地址都是proxy端的ip 。也就是说在默认情况下我们使用request.getAttribute("X-Forwarded-For")获取不到用户的ip,如果我们想要通过这个变量获得用户的ip,
这样配置的意思是:
增加一个$proxy_add_x_forwarded_for到X-Forwarded-For里去,注意是增加,而不是覆盖,当然由于默认的X-Forwarded-For值是空的,所以我们总感觉X-Forwarded-For的值就等于$proxy_add_x_forwarded_for的值,
实际上当你搭建两台nginx在不同的ip上,并且都使用了这段配置,那你会发现在web服务器端通过request.getAttribute("X-Forwarded-For")获得的将会是客户端ip和第一台nginx的ip。
那么$proxy_add_x_forwarded_for又是什么?
$proxy_add_x_forwarded_for变量包含客户端请求头中的"X-Forwarded-For",与$remote_addr两部分,他们之间用逗号分开。
举个例子,有一个web应用,在它之前通过了两个nginx转发,www.linuxidc.com 即用户访问该web通过两台nginx。
在第一台nginx中,使用
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
现在的$proxy_add_x_forwarded_for变量的"X-Forwarded-For"部分是空的,所以只有$remote_addr,而$remote_addr的值是用户的ip,于是赋值以后,X-Forwarded-For变量的值就是用户的真实的ip地址了。
到了第二台nginx,使用
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
现在的$proxy_add_x_forwarded_for变量,X-Forwarded-For部分包含的是用户的真实ip,$remote_addr部分的值是上一台nginx的ip地址,于是通过这个赋值以后现在的X-Forwarded-For的值就变成了“用户的真实ip,
第一台nginx的ip”,这样就清楚了吧。最后我们看到还有一个$http_x_forwarded_for变量,这个变量就是X-Forwarded-For,由于之前我们说了,默认的这个X-Forwarded-For是为空的,
所以当我们直接使用proxy_set_header X-Forwarded-For $http_x_forwarded_for时会发现,web服务器端使用request.getAttribute("X-Forwarded-For")获得的值是null。如果想要通过request.getAttribute("X-Forwarded-For")获得用户ip,就必须先使用proxy_set_header
X-Forwarded-For $proxy_add_x_forwarded_for;这样就可以获得用户真实ip。
proxy_redirect off
语法:proxy_redirect [ default|off|redirect replacement ]
默认值:proxy_redirect default
使用字段:http, server, location
proxy_redirect功能比较强大,其作用是对发送给客户端的URL进行修改。
如果需要修改从被代理服务器传来的应答头中的"Location"和"Refresh"字段,可以用这个指令设置。
设置为off,表示禁止所有的proxy_redirect指令.
假设被代理服务器返回Location字段为:http://localhost:8000/two/some/uri/
这个指令:
proxy_redirect http://localhost:8000/two/http://frontend/one/;
将Location字段重写为http://frontend/one/some/uri/。
在代替的字段中可以不写服务器名:
proxy_redirect http://localhost:8000/two/ /;
这样就使用服务器的基本名称和端口,即使它来自非80端口。
如果使用“default”参数,将根据location和proxy_pass参数的设置来决定。
例如下列两个配置等效:
location /one/ {
proxy_pass http://upstream:port/two/;
proxy_redirect default;
}
location /one/ {
proxy_pass http://upstream:port/two/;
proxy_redirect http://upstream:port/two/ /one/;
}
在指令中可以使用一些变量:
proxy_redirect http://localhost:8000/ http://$host:$server_port/;
这个指令有时可以重复:
proxy_redirect default;
proxy_redirect http://localhost:8000/ /;
proxy_redirect ;
/;
参数off将在这个字段中禁止所有的proxy_redirect指令:
proxy_redirect off;
proxy_redirect default;
proxy_redirect http://localhost:8000/ /;
proxy_redirect ;
/;
利用这个指令可以为被代理服务器发出的相对重定向增加主机名:
---------------------------------------------------------------------------------------------------
实例说明:
比如在做nginx反向代理时出了一点点问题,原来后端节点用的端口是8080,通过反向代理后,使用wireshark抓包发现location头域数值为http://192.168.1.154:8080/huihui/,
如果把这个返回给客户端肯定是不可以的,看起来别扭而且还暴露了后端节点的具体信息。所以在这里用到了nginx的proxy_redirect指定修改被代理服务器返回的响应头中的location头域跟refresh头域数值。
前期配置(暴露了后端节点信息)
[root@localhost nginx]# cat test.conf
server {
listen 80;
server_name www.wangshibo.com;
location / {
proxy_pass http://192.168.1.154:8080;
proxy_redirect off;
}
}
此时我们通过curl查看结果得出
[root@localhost nginx]# curl -I http://www.wangshibo.com/huihui
HTTP/1.1 301 Moved Permanently
Server: nginx
Date: Thu, 24 Dec 2015 12:02:00 GMT
Content-Type: text/html; charset=iso-8859-1
Connection: keep-alive
Location: http://192.168.1.154:8080/huihui/
这里location为带有后端服务器实际地址跟端口的响应头信息,这样在实际线上是不允许的。
所以这里需要通过proxy_redirect将被代理服务器的响应头中的location字段进行修改后返回给客户端
修改后的配置:
[root@localhost nginx]# cat test.conf
server {
listen 80;
server_name www.wangshibo.com;
location / {
proxy_pass http://192.168.1.154:8080;
proxy_redirect http://192.168.1.154:8080/huihui/ http://www.wangshibo.com/huihui/;
}
server {
listen 80;
server_name www.wangshibo.com;
location / {
proxy_pass http://192.168.1.154:8080;
proxy_redirect ~^http://192.168.1.154:8080(.*) http://www.wangshibo.com$1;
}
则curl查看返回结果
[root@localhost nginx]# curl -I http://www.wangshibo.com/huihui
HTTP/1.1 301 Moved Permanently
Server: nginx
Date: Thu, 24 Dec 2015 12:08:34 GMT
Content-Type: text/html; charset=iso-8859-1
Connection: keep-alive
Location: http://www.wangshibo.com/huihui/
此时查看location已经变成了我们想要的结果了。 此时通过replacement 301重定向到了我们新的页面
负载均衡
负载均衡也是 Nginx 常用的一个功能,负载均衡其意思就是分摊到多个操作单元上进行执行,例如:Web服务器、FTP服务器、企业关键应用服务器和其它关键任务服务器等,从而共同完成工作任务。简单而言就是当有2台或以上服务器时,根据规则随机的将请求分发到指定的服务器上处理,负载均衡配置一般都需要同时配置反向代理,通过反向代理跳转到负载均衡。而Nginx目前支持自带3种负载均衡策略,还有2种常用的第三方策略。
1、RR(默认)
每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器down掉,能自动剔除。
简单配置
upstream test {
server localhost:8080;
server localhost:8081;
}
server {
listen 81;
server_name localhost;
client_max_body_size 1024M;
location / {
proxy_pass http://test;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
这里配置了2台服务器,当然实际上是一台,只是端口不一样而已,而8081的服务器是不存在的,也就是说访问不到,但是我们访问 http://localhost 的时候,也不会有问题,会默认跳转到http://localhost:8080 具体是因为Nginx会自动判断服务器的状态,如果服务器处于不能访问(服务器挂了),就不会跳转到这台服务器,所以也避免了一台服务器挂了影响使用的情况,由于 Nginx 默认是RR策略,所以我们不需要其他更多的设置。
2、权重
指定轮询几率,weight和访问比率成正比,用于后端服务器性能不均的情况。 例如
upstream test {
server localhost:8080 weight=9 max_fails=2 fail_timeout=2;
server localhost:8081 weight=1 max_fails=2 fail_timeout=2;
}
那么10次一般只会有1次会访问到8081,而有9次会访问到8080。
3、ip_hash
上面的2种方式都有一个问题,那就是下一个请求来的时候请求可能分发到另外一个服务器,当我们的程序不是无状态的时候(采用了session保存数据),这时候就有一个很大的很问题了,比如把登录信息保存到了session中,那么跳转到另外一台服务器的时候就需要重新登录了,所以很多时候我们需要一个客户只访问一个服务器,那么就需要用iphash了,iphash的每个请求按访问ip的hash结果分配,这样每个访客固定访问一个后端服务器,可以解决session的问题。
upstream test {
ip_hash;
server localhost:8080;
server localhost:8081;
}
4、fair(第三方)
按后端服务器的响应时间来分配请求,响应时间短的优先分配。
upstream backend {
fair;
server localhost:8080;
server localhost:8081;
}
5、url_hash(第三方)
按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器,后端服务器为缓存时比较有效。 在upstream中加入hash语句,server语句中不能写入weight等其他的参数,hash_method是使用的hash算法。
upstream backend {
hash $request_uri;
hash_method crc32;
server localhost:8080;
server localhost:8081;
}
以上5种负载均衡各自适用不同情况下使用,所以可以根据实际情况选择使用哪种策略模式,不过fair和url_hash需要安装第三方模块才能使用,由于本文主要介绍Nginx能做的事情,所以Nginx安装第三方模块不会再本文介绍。
nginx负载均衡是ngx_http_upstream_module模块的功能,需要在配置文件http块上下文中定义upstream块,指定一组负载均衡的后端服务器,然后在proxy_pass中引用,就可以反向代理时实现负载均衡了
语法:server address [parameters];
paramerters:
weight:负载均衡策略权重,默认为1;
max_fails:在一定时间内(这个时间在fail_timeout参数中设置)检查这个服务器是否可用时产生的最多失败请求数
fail_timeout:在经历了max_fails次失败后,暂停服务的时间。max_fails可以和fail_timeout一起使用,进行对后端服务器的健康状态检查;
backup:当所有后端服务器都宕机时,可以指定代理服务器自身作为备份,对外提供维护提示页面
down:永久不可用
缓存功能
nginx实现缓存是通过代理缓存proxy-cache,这也是ngx_http_proxy_module模块提供的功能,配置较多,常用的选项有;proxy_cache_path proxy_cache和proxy_cache_valid
1、proxy_cache_path
proxy_cache_path定义一个完整的缓存空间,指定缓存数据的磁盘路径、索引存放的内存空间以及一些其他参数。如缓存策略。该选项只能定义在http块上下文中
例如:proxy_cache_path /data/cache levels=1:2 keys_zone=web:10m max_size=1G inactive=10;
2、proxy_cache
proxy_cache用来引用上面proxy_cache_path定义的缓存空间,现时打开缓存功能
例如:proxy_cache web; #引用上面定义上的缓存空间,同一缓存空间可以在几个地方使用
3、proxy_cache_valid
proxy_cache_valid设置不同响应代码的缓存时间
例如:proxy_cache_valid 200 302 10m;
proxy_cache_path /data/cache levels=1:2 keys_zone=web:10m max_size=1G inactive=10m;
定义一个完整的缓存空间;缓存数据存储在/data/cache目录中,配置在该目录下再分两层目录,名称为web,10m内存空间大小,最大缓存数据磁盘空间的大小;10分钟未被访问的缓存数据将从缓存中删除
location / {
root e:\wwwroot;
proxy_cache web; 引用上面定义的缓存空间,同一缓存空间可以在几个地方使用
proxy_cache_valid 200 302 301 20m; 对代码200 302 301的响应设置10分钟的缓存
proxy_pass http://test; 引用上面定义的upstream负载均衡组
proxy_connect_timeout 300; #跟后端服务器连接超时时间,发起握手等候响应时间
proxy_send_timeout 300; #后端服务器回传时间,就是在规定时间内后端服务器必须传完所有数据
proxy_read_timeout 600; #连接成功后等待后端服务器的响应时间,已经进入后端的排队之中等候处理
proxy_buffer_size 256k; #代理请求缓冲区,会保存用户的头信息以供nginx进行处理
proxy_buffers 4 256k; #同上,告诉nginx保存单个用几个buffer最大用多少空间
proxy_busy_buffers_size 256k; #如果系统很忙时候可以申请最大的proxy_buffers
proxy_temp_file_write_size 256k; #proxy缓存临时文件的大小
动静分离
动静分离是让动态网站里的动态网页根据一定规则把不变的资源和经常变的资源区分开来,动静资源做好了拆分以后,我们就可以根据静态资源的特点将其做缓存操作,这就是网站静态化处理的核心思路。
upstream test{
server localhost:8080;
server localhost:8081;
}
server {
listen 80;
server_name localhost;
location / {
root html;;
index index.html;
}
# 所有静态请求都由nginx处理,存放目录为html
location ~ \.(gif|jpg|jpeg|png|bmp|swf|css|js)$ {
root html;
expires 30d;
}
# 所有动态请求都转发给tomcat处理
location ~* \.(jsp|do)?$ {
proxy_pass http://test;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root e:\wwwroot;
}
}
这样我们就可以把HTML以及图片和css以及js放到wwwroot目录下,而tomcat只负责处理jsp和请求,
例如当我们后缀为gif的时候,Nginx默认会从wwwroot获取到当前请求的动态图文件返回,当然这里的静态文件跟Nginx是同一台服务器,我们也可以在另外一台服务器,然后通过反向代理和负载均衡配置过去就好了,只要搞清楚了最基本的流程,很多配置就很简单了,另外localtion后面其实是一个正则表达式,所以非常灵活。
Nginx URL重写(rewrite)介绍
和apache等web服务软件一样,rewrite的组要功能是实现RUL地址的重定向。Nginx的rewrite功能需要PCRE软件的支持,即通过perl兼容正则表达式语句进行规则匹配的。默认参数编译nginx就会支持rewrite的模块,但是也必须要PCRE的支持
rewrite语法格式及参数语法说明如下:
rewrite <regex> <replacement> [flag];
关键字 正则 替代内容 flag标记
关键字:其中关键字error_log不能改变
正则:perl兼容正则表达式语句进行规则匹配
替代内容:将正则匹配的内容替换成replacement
flag标记:rewrite支持的flag标记
flag标记说明:
last #本条规则匹配完成后,继续向下匹配新的location URI规则
break #本条规则匹配完成即终止,不再匹配后面的任何规则
redirect #返回302临时重定向,浏览器地址会显示跳转后的URL地址
permanent #返回301永久重定向,浏览器地址栏会显示跳转后的URL地址
regex 常用正则表达式说明
\ 将后面接着的字符标记为一个特殊字符或一个原义字符或一个向后引用。如“\n”匹配一个换行符,而“\$”则匹配“$”
^ 匹配输入字符串的起始位置
$ 匹配输入字符串的结束位置
* 匹配前面的字符零次或多次。如“ol*”能匹配“o”及“ol”、“oll”
+ 匹配前面的字符一次或多次。如“ol+”能匹配“ol”及“oll”、“oll”,但不能匹配“o”
? 匹配前面的字符零次或一次,例如“do(es)?”能匹配“do”或者“does”,"?"等效于"{0,1}"
. 匹配除“\n”之外的任何单个字符,若要匹配包括“\n”在内的任意字符,请使用诸如“[.\n]”之类的模式。
(pattern) 匹配括号内pattern并可以在后面获取对应的匹配,常用$0...$9属性获取小括号中的匹配内容,要匹配圆括号字符需要\(Content\)
一级目录
server {
listen 80;
server_name abc.com;
return 444;
rewrite ^/(.*) http://www.abc.com/$1 permanent;
}
server {
listen 80;
server_name www.abc.com;
location / {
root /data/www/www;
index index.html index.htm;
}
error_log logs/error_www.abc.com.log error;
access_log logs/access_www.abc.com.log main;
}
或者
server {
listen 80;
server_name abc.com www.abc.com;
if ( $host != 'www.abc.com' ) {
rewrite ^/(.*) http://www.abc.com/$1 permanent;
}
location / {
root /data/www/www;
index index.html index.htm;
}
error_log logs/error_www.abc.com.log error;
access_log logs/access_www.abc.com.log main;
}
二级目录
server {
listen 80;
server_name www.abc.com;
location /ns {
index index.html index.htm;
if (!-e $request_filename){
rewrite ^/ns(.*)$ /ns1$1 last;
}
}
location /ns1 {
alias /mnt/;
index index.html index.htm;
}
}
if ($http_user_agent ~ Firefox) {
rewrite ^/ns(.*)$ /firefox/$1 break;
}
if ($http_user_agent ~ MSIE) {
rewrite ^(.*)$ /msie/$1 break;
}
if ($http_user_agent ~ Chrome) {
rewrite ^(.*)$ /chrome/$1 break;
}
根据Referer信息防止盗链
ssl
生成证书
进入你想创建证书和私钥的目录
cd /usr/local/nginx/conf
创建服务器私钥,命令会让你输入一个口令
openssl genrsa -des3 -out server.key 1024
创建签名请求的证书(CSR)
openssl req -new -key server.key -out server.csr
openssl req -new -x509 -keyout server.key -out server.crt
在加载SSL支持的Nginx并使用上述私钥时除去必须的口令
cp server.key server.key.org
openssl rsa -in server.key.org -out server.key
配置nginx
最后标记证书使用上述私钥和CSR
openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt
修改Nginx配置文件,让其包含新标记的证书和私钥
server {
listen 443;
server_name localhost;
ssl_certificate /usr/local/nginx/conf/server.crt;
ssl_certificate_key /usr/local/nginx/conf/server.key;
ssl on;
# ssl_session_cache shared:SSL:1m;
# ssl_session_timeout 5m;
# ssl_ciphers HIGH:!aNULL:!MD5;
# ssl_prefer_server_ciphers on;
location / {
root html;
index index.html index.htm;
}
}
下面我们对nginx配置文件进行修改,并一一讲述nginx功能的使用
# 使用指定的用户和组
user nginx nginx
#指定工作衍生进程数。这个数值和物理机的CPU数量一致
worker_processes 1; l's
#可以在下方直接使用 [ debug | info | notice | warn | error | crit ] 参数
error_log /var/log/nginx.error_log info;
#指定pid存放的路径
pid /usr/local/nginx/nginx.pid;
events {
#允许的连接数,这里指的是单进程的连接数
worker_connections 1024;
#nginx版本中默认就是epoll模型,#use [ kqueue | rtsig | epoll | /dev/poll | select | poll ] ;
use kqueue;
}
http {
include mime.types;
default_type application/octet-stream;
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 logs/access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#开启数据压缩功能
gzip on;
server {
listen 80;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location /nginx_status {
stub_status on;
access_log off;
allow all; 访问IP
#deny all;
#active connections – 活跃的连接数量
#server accepts handled requests — 总共处理了11989个连接 , 成功创建11989次握手, 总共处理了11991个请求
#reading — 读取客户端的连接数.
#writing — 响应数据到客户端的数量
#waiting — 开启 keep-alive 的情况下,这个值等于 active – (reading+writing), 意思就是 Nginx 已经处理完正在等候下一次请求指令的驻留连接.
}
location / {
root html;
index index.html index.htm;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
location / {
root html;
index index.html index.htm;
proxy_pass http://cluster.com;
#设置主机头和客户端真实地址,以便服务器获取客户端真实IP
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
autoindex on; #开启目录浏览功能
autoindex_exact_size off; #显示目录的详细大小
autoindex_localtime on; #显示目录的详细时间
allow 192.168.147.136;
deny 192.168.147.0/32
deny all;
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
# root html;
# fastcgi_pass 127.0.0.1:9000;
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
# include fastcgi_params;
#}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}
# another virtual host using mix of IP-, name-, and port-based configuration
#
#server {
# listen 8000;
# listen somename:8080;
# server_name somename alias another.alias;
# location / {
# root html;
# index index.html index.htm;
# }
#}
# HTTPS server
#
#server {
# listen 443 ssl;
# server_name localhost;
# ssl_certificate cert.pem;
# ssl_certificate_key cert.key;
# ssl_session_cache shared:SSL:1m;
# ssl_session_timeout 5m;
# ssl_ciphers HIGH:!aNULL:!MD5;
# ssl_prefer_server_ciphers on;
# location / {
# root html;
# index index.html index.htm;
# }
#}
}