文章目录
一、nginx简介
Nginx 是一个高性能的 web服务器和反向代理服务器(支持http、tcp、smtp等多种协议)
nginx优点:
(1)支持 epoll 模型,使得 nginx 可以支持高并发(静态小文件)。静态并发 1-2 万
(2)占用资源少。 2 万并发,开 10 个线程服务,内存消耗才几百 M
(3)功能种类比较多(web、 cache、 proxy)。但每个功能都不是特别强
(4)配置简单、灵活,支持不停机而更新配置文件使其生效、日志文件滚动、升级程序版本;
注意reload加载新配置文件时,客户端连接可能是会重置
(5)支持sendfile, sendfile64(更大文件的响应)何为sendfile? 即在磁盘IO完成数据进入内核内存后不返回给web进程而是直接构建成报文由内核中发送给网卡发送队列
二、nginx工作原理
master与worker
nginx在启动后,会有一个master进程和多个worker进程。master进程主要用来管理worker进程,包含:接收来自外界的信号,向各worker进程发送信号;监控worker进程的运行状态,当worker进程退出后(异常情况下),会自动重新启动新的worker进程。
而基本的网络事件,则是放在worker进程中来处理了。多个worker进程之间是对等的,他们同等竞争来自客户端的请求,各进程互相之间是独立的。
一个请求,只可能在一个worker进程中处理,一个worker进程,不可能处理其它进程的请求。worker进程的个数是可以设置的,一般我们会设置与机器cpu核数一致。
master与处理请求
那么我们该怎么操作ngnix呢?其实我们只需要通过与master进行通信(命令)就可以操作ngnix,master进程会接收来自外界发来的信号,再根据信号做不同的事情。
比如kill -HUP pid,我们一般用这个信号来重启nginx,或重新加载配置,因为是从容地重启,因此服务是不中断的。
首先master进程在接到信号后,会先重新加载配置文件,然后再启动新的worker进程,并向所有老的worker进程发送信号,告诉他们可以退出了。新的worker在启动后,就开始接收新的请求,而老的worker在收到来自master的信号后,就不再接收新的请求,并且在当前进程中的所有未处理完的请求处理完成后,再退出。
当然,直接给master进程发送信号,这是比较老的操作方式,nginx在0.8版本之后,引入了一系列命令行参数,来方便我们管理。
比如,./nginx -s reload,就是来重启nginx,./nginx -s stop,就是来停止nginx的运行。如何做到的呢?我们还是拿reload来说,我们看到,执行命令时,我们是启动一个新的nginx进程,而新的nginx进程在解析到reload参数后,就知道我们的目的是控制nginx来重新加载配置文件了,它会向master进程发送信号,然后接下来的动作,就和我们直接向master进程发送信号一样了。
worker与处理请求
前面有提到,worker进程之间是平等的,每个进程,处理请求的机会也是一样的。当我们提供80端口的http服务时,一个连接请求过来,每个进程都有可能处理这个连接。怎么做到的呢?
首先,每个worker进程都是从master进程fork过来,在master进程里面,先建立好需要listen的socket(listenfd)之后,然后再fork出多个worker进程。所有worker进程的listenfd会在新连接到来时变得可读。为保证只有一个进程处理该连接,所有worker进程在注册listenfd读事件前抢accept_mutex,抢到互斥锁的那个进程注册listenfd读事件,在读事件里调用accept接受该连接。
当一个worker进程在accept这个连接之后,就开始读取请求,解析请求,处理请求,产生数据后,再返回给客户端,最后才断开连接,这样一个完整的请求就是这样的了
nginx进程模型的好处
首先,对于每个worker进程来说,独立的进程,不需要加锁,所以省掉了锁带来的开销,同时在编程以及问题查找时,也会方便很多。
其次,采用独立的进程,可以让worker互相之间不会影响,一个worker退出后,其它worker还在工作,服务不会中断,master进程则很快启动新的worker进程。
当然,worker进程的异常退出,肯定是程序有bug了,异常退出,会导致当前worker上的所有请求失败,不过不会影响到所有请求,所以降低了风险。
好处是很多的,只能在使用中慢慢体会了。
nginx处理高并发(网络事件)
nginx采用了异步非阻塞的方式来处理请求,也就是说,nginx是可以同时处理成千上万个请求的。
同步与异步,重点在于消息通知的方式;
阻塞与非阻塞,重点在于等消息时候的行为。
所以,就有了下面4种组合方式
1. 同步阻塞:小明收到信息后,啥都不干,等着快递;
2. 同步非阻塞:小明收到信息后,边刷微博,边等着取快递;
3. 异步阻塞:小明收到信息后,啥都不干,一直等着快递员通知他取快递;
4. 异步非阻塞:小明收到信息后,边刷着微博,边等快递员通知他取快递。
nginx 的异步非阻塞是指worker进程。
每进来一个request,会有一个worker进程去处理。但不是全程的处理,处理到可能发生阻塞的地方。比如向后端服务器转发request,并等待请求返回。那么,这个处理的worker不会这么傻等着,他会在转发完请求后,注册一个事件:“如果upstream返回了,告诉我一声,我再接着干”。于是就休息等着下一个request 进来,再按这种方式处理。而一旦上游服务器返回了,就会触发这个事件,worker才会来接手,原来request才会接着往下走。
三、部署nginx和配置解析
3.1 编译安装nginx
编译安装的好处是可以关闭不需要功能,使nginx更精简稳定。使用nginx -V查看nginx编译内容。
(1)查看系统环境
[root@localhost tools]# cat /etc/redhat-release
CentOS Linux release 7.4.1708 (Core)
[root@localhost tools]# uname -r
3.10.0-693.el7.x86_64
[root@localhost tools]# uname -m
x86_64
(2)安装pcre、openssl依赖
pcre为正则依赖的库包文件,openssl在使用https时会用到
[root@localhost tools]# yum install -y pcre pcre-devel openssl openssl-devel
[root@localhost tools]# rpm -qa pcre pcre-devel
pcre-devel-8.32-17.el7.x86_64
pcre-8.32-17.el7.x86_64
[root@localhost tools]# rpm -qa openssl openssl-devel
openssl-devel-1.0.2k-12.el7.x86_64
openssl-1.0.2k-12.el7.x86_64
(3)下载nginx,并解压
[root@localhost tools]# wget http://nginx.org/download/nginx-1.15.1.tar.gz
[root@localhost tools]# tar -zxf nginx-1.15.1.tar.gz
(4)编译安装
[root@localhost tools]# useradd -s /sbin/nologin -M nginx
[root@localhost tools]# cd nginx-1.15.1
[root@localhost nginx-1.15.1]# ./configure --help
[root@localhost nginx-1.15.1]# ./configure \
--user=nginx \ #配置进程用户权限
--gourp=nginx \ #配置进程用户组权限
--prefix=/usr/local/nginx1.15.1 \ #指定安装路径
--with-http_stub_status_module \ #启用激活状态信息模块
--with-http_ssl_module #启用ssl功能模块
[root@localhost nginx-1.15.1]# make && make install
[root@localhost nginx-1.15.1]# ln -sv /usr/local/nginx1.15.1 /usr/local/nginx
‘/usr/local/nginx’ -> ‘/usr/local/nginx1.15.1’
(5)启动
[root@localhost ~]# /usr/local/nginx/sbin/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 ~]# /usr/local/nginx/sbin/nginx #启动nginx
3.2 nginx目录结构
[root@localhost ~]# tree /usr/local/nginx
/usr/local/nginx
├── client_body_temp
├── conf #Nginx主配置文件目录
│ ├── fastcgi.conf #fastcgi相关参数的配置文件
│ ├── fastcgi.conf.default #fastcig的原始备份文件
│ ├── fastcgi_params
│ ├── fastcgi_params.default
│ ├── koi-utf
│ ├── koi-win
│ ├── mime.types #媒体类型文件
│ ├── mime.types.default
│ ├── nginx.conf #Nginx默认主配置文件
│ ├── nginx.conf.default
│ ├── scgi_params #scgi相关参数文件,一般不用
│ ├── scgi_params.default
│ ├── uwsgi_params #uwsgi相关参数文件,一般不用
│ ├── uwsgi_params.default
│ └── win-utf
├── fastcgi_temp #fastcgi临时数据目录
├── html #Nginx编译安装默认站点目录
│ ├── 50x.html #错误页面优雅显示,当出现502时会调用该页面
│ └── index.html #默认的首页文件
├── logs #默认的日志目录
│ ├── access.log #访问日志
│ ├── error.log #错误日志
│ └── nginx.pid #nginx的pid文件,Nginx进程启动后,会把所有进程的ID号写到该文件
├── proxy_temp #临时目录
├── sbin #Nginx的命令目录
│ └── nginx
├── scgi_temp #临时目录
└── uwsgi_temp #临时目录
3.3 nginx.conf配置文件解析
user nginx nginx; #定义Nginx运行的用户和用户组
worker_processes auto; #指定nginx的work进程数,建议设置为等于CPU总核心数。
worker_cpu_affinity 0001 0010 0100 1000; #默认情况下,Nginx的多个进程可能都泡在某一个CPU或cpu某一核上,导致资源不均衡。可通过该参数令资源更均衡,此例子为4核
error_log /var/log/nginx/error.log info; #全局错误日志定义类型,可以是相对路径,也可以是绝对路径。除了可以在此处定义,还可以在http、server、location中定义[ debug | info | notice | warn | error | crit ]
pid /var/run/nginx.pid; #进程PID文件所在的路径,可以是相对路径,也可以是绝对路径。
worker_rlimit_nofile 65535; #定义nginx最多打开文件数限制。如果没设置的话,这个值为操作系统(ulimit -n)的限制保持一致。把这个值设高,nginx就不会有"too many open files"的问题
events
{
use epoll; #参考事件模型,use [ kqueue | rtsig | epoll | /dev/poll | select | poll ]; epoll模型是Linux 2.6以上版本内核中的高性能网络I/O模型,如果跑在FreeBSD上面,就用kqueue模型。
worker_connections 65535; #定义每个work_process同时开启的最大连接数,即允许最多只能有这么多连接。
accept_mutex on; #当某一个时刻只有一个网络连接请求服务器时,服务器上有多个睡眠的进程会被同时叫醒。这样会损耗一定的服务器性能。Nginx中的accept_mutex设置为on,将会对多个Ningx进程(worker processer)接收连接时进行序列化,防止多个进程争抢资源。默认就是on
multi_accept on; #nginx的worker进程可以做到同时接收多个新到达的网络连接,前提是把该参数设置为on。默认为off,即每个worker processer一次只能接收新到达的网络连接。
}
#设定web服务器,适用于HTTP协议
http
{
include mime.types; #Nginx支持的媒体类型库文件
default_type application/octet-stream; #默认媒体类型
#charset utf-8; #默认编码
server_names_hash_bucket_size 128; #服务器域名的hash表大小
client_header_buffer_size 32k; #客户端请求头部缓冲大小,如果请求头部大小大于指定缓冲区,则使用large_client_header_buffers指令分配更大的缓冲区
large_client_header_buffers 4 64k; #用于读取大型客户端请求头部的缓冲区的最大数量和大小,这些缓冲区仅在缺省缓冲区不足时按需分配。当处理请求或连接转换到保持活动状态时,释放缓冲区。
client_max_body_size 8m; #上传文件大小限制。设置nginx能处理最大请求主体大小,如果请求大于指定大小,则nginx会返回413错误。如果服务器处理大文件上传时,该指令尤为重要。
sendfile on; #开启高效文件传输模式,sendfile指令指定nginx是否调用sendfile函数来输出文件,对于普通应用设为 on,如果用来进行下载等应用磁盘IO重负载应用,可设置为off,以平衡磁盘与网络I/O处理速度,降低系统的负载。注意:如果图片显示不正常把这个改成off。
autoindex on; #开启目录列表访问,合适下载服务器,默认关闭。
tcp_nopush on; #防止网络阻塞
tcp_nodelay on; #防止网络阻塞
keepalive_timeout 120; #长连接超时时间,单位是秒
server_tokens off; #隐藏Nginx软件版本号信息,避免站点根据版本查找漏洞攻击
#FastCGI相关参数是为了改善网站的性能:减少资源占用,提高访问速度。下面参数看字面意思都能理解。
fastcgi_connect_timeout 75; #Nginx和后端FastCGI服务器连接超时时间,默认60s,通常不要超过75秒,因为建立的连接越多,消耗资源越多。
fastcgi_send_timeout 300; #Nginx允许FastCGI服务器返回数据的超时时间,即在规定时间内后端服务器必须传完数据,否则Nginx断开连接,默认60s。
fastcgi_read_timeout 300; #Nginx从FastCGI服务器端读取响应信息的超时时间,表示连接建立后,Nginx等待后端服务器的响应时间,是Nginx已经进入后端的排队之中等候处理的时间。
fastcgi_buffer_size 64k; #指定读取fastcgi应答第一部分需要的缓冲区大小,默认缓冲区大小为fastcgi_buffers指令中每块的大小
fastcgi_buffers 4 64k; #指定本地需要用多少或多大的缓冲区来缓冲fastcgi的应答请求,如果一个php脚本所产生的页面大小为256KB,那么回分配4个64KB的缓冲区来缓存,如果页面大小大于256KB,那么大于256KB的部分会缓存到fastcgi_temp_path指定的路径中。一般这个值应该为站点中php脚本所产生的页面大小的中间值,如果站点大部分脚本所产生的页面大小为256KB,那么这个值可以设置为"8 32K"、"4 64K"等。
fastcgi_busy_buffers_size 128k; #指定系统繁忙时期可以使用的缓冲区大小,建议设置为fastcgi_buffers的2倍。
fastcgi_temp_file_write_size 128k; #在写入fastcgi_temp_path时将用到多大的数据块,默认值为fastcgi_buffers的2倍,该数值设置过小,当负载过高时可能会出现502的错误。范围128-256KB
fastcgi_cache_path /data/ngx_fcgi_cache levels=2:2 keys_zone=ngx_fcgi_cache:512m inactive=1d max_size=40g; #配置缓存目录
#gzip模块设置
gzip on; #开启gzip压缩功能
gzip_min_length 1k; #最小压缩文件大小,页面字节数从header头部的Content-Length中获取,默认是0,不管页面多大,建议设置成大于1k,如果小于1k可能会越压越大
gzip_buffers 4 16k; #压缩缓冲区,表示申请4个单位为16k的内存作为压缩结果流缓存,默认值是申请和原始数据大小相同的内存空间来存储gzip压缩结果
gzip_http_version 1.0; #压缩版本(默认1.1,前端如果是squid2.5请使用1.0)
gzip_comp_level 2; #压缩等级,1压缩比最小,处理速度最快;9压缩比最大,但是处理慢,也比较消耗CPU资源
gzip_types text/plain application/x-javascript text/css application/xml; 默认压缩类型,text/html类型默认压缩
gzip_vary on; #varyhead支持,该选项可以让前端缓存服务器经过GZIP压缩页面,例如用Squid缓存经过nginx压缩的数据
limit_conn_zone $binary_remote_addr zone=addr:10m; #开启限制并发数
#limit_req_zone $binary_remote_addr zone=req_one:10m rate=1r/s; #开启限制ip的请求数
upstream bbs.abc.org {
#upstream的负载均衡,weight是权重,可以根据机器配置定义权重。weigth参数表示权值,权值越高被分配到的几率越大。
server 192.168.56.11:80 weight=3;
server 192.168.56.12:80 weight=2;
server 192.168.56.13:80 weight=3;
}
#虚拟主机的配置
server
{
#监听端口
listen 80;
#域名可以有多个,用空格隔开
server_name www.bbs.org;
index index.html index.htm index.php;
root /data/www/bbs;
location ~ .*\.(php|php5)?$
{
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi.conf;
fastcgi_cache ngx_fcgi_cache;
fastcgi_cache_valid 200 302 1h; #用于指定应答代码的缓存时间,实例中的值将200和302应答缓存1个小时
fastcgi_cache_valid 301 1d; #将301应答代码缓存1天
fastcgi_cache_valid any 1m; #将其他应答代码缓存1分钟
fastcgi_cache_min_uses 1; #设置请求几次之后响应将被缓存,1表示1次即被缓存
fastcgi_cache_use_stale error timeout invalid_header http_500; #定义在哪些情况下使用过期缓存
fastcgi_cache_key http://$host$request_uri; #定义fastcgi_cache的key,Nginx会取这个key的md5作为缓存文件
}
#图片缓存时间设置
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$
{
expires 10d; #缓存10天
access_log off; #不记录访问图片的日志
}
#JS和CSS缓存时间设置
location ~ .*\.(js|css)?$
{
expires 1h;
}
#日志格式设定
log_format access '$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 access;
#对 "/" 启用反向代理
location / {
proxy_pass http://127.0.0.1:88;
proxy_redirect off;
proxy_set_header X-Real-IP $remote_addr;
#后端的Web服务器可以通过X-Forwarded-For获取用户真实IP
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
#以下是一些反向代理的配置,可选。
proxy_set_header Host $host;
client_max_body_size 10m; #允许客户端请求的最大单文件字节数
client_body_buffer_size 128k; #缓冲区代理缓冲用户端请求的最大字节数,
proxy_connect_timeout 90; #nginx跟后端服务器连接超时时间(代理连接超时)
proxy_send_timeout 90; #后端服务器数据回传时间(代理发送超时)
proxy_read_timeout 90; #连接成功后,后端服务器响应时间(代理接收超时)
proxy_buffer_size 4k; #设置代理服务器(nginx)保存用户头信息的缓冲区大小
proxy_buffers 4 32k; #proxy_buffers缓冲区,网页平均在32k以下的设置
proxy_busy_buffers_size 64k; #高负荷下缓冲大小(proxy_buffers*2)
proxy_temp_file_write_size 64k;
#设定缓存文件夹大小,大于这个值,将从upstream服务器传
}
#设定查看Nginx状态的地址
location /NginxStatus {
stub_status on;
access_log on;
auth_basic "NginxStatus";
auth_basic_user_file conf/htpasswd;
#htpasswd文件的内容可以用apache提供的htpasswd工具来产生。
}
#本地动静分离反向代理配置
#所有jsp的页面均交由tomcat或resin处理
location ~ .(jsp|jspx|do)?$ {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://127.0.0.1:8080;
}
#所有静态文件由nginx直接读取不经过tomcat或resin
location ~ .*.(htm|html|gif|jpg|jpeg|png|bmp|swf|ioc|rar|zip|txt|flv|mid|doc|ppt|pdf|xls|mp3|wma)$
{ expires 15d; }
location ~ .*.(js|css)?$
{ expires 1h; }
}
}
四、nginx常用功能和配置
4.1 web的虚拟主机
所谓虚拟主机,在Web服务当中就是一个独立的网站站点,这个站点对应独立的域名(也有可能是IP或者端口),具有独立的程序和资源目录,可以独立地对外提供服务供用户访问。
这个独立的站点在配置里是由一定格式的标签进行标记,和apache相对比,apache的虚拟主机的标签段通常是以进行标注的,而Nginx则是以Server{}标签段来标示一个虚拟主机。一个Web服务中支持多个虚拟主机站点。
配置在在http{}断中
基于域名的虚拟主机
首先保证http请求的主机域名能解析到nginx上,通过http报文头部的中host来匹配server_name。
server_name的匹配优先级:
- server_name精确匹配
- 以星号开头的最长通配符(*.panks.com)
- 以星号结尾的最长通配符(www.panks.*)
- 第一个匹配的正则表达式(按配置文件中出现的顺序)
server {
listen 80;
server_name www.abc.org; #基于域名的虚拟主机
root /vhosts/html/www;
index index.html index.htm index.php;
}
基于端口的虚拟主机
server {
listen 8081; #基于端口的虚拟主机
server_name www.abc.org;
root /vhosts/html/www;
index index.html index.htm index.php;
}
基于IP的虚拟主机
server {
listen 192.168.2.5:80; #基于IP的虚拟主机
server_name www.abc.org;
root /vhosts/html/www;
index index.html index.htm index.php;
}
http请求已域名形式的优先域名匹配虚拟主机,然后考虑其他。
4.2 nginx状态页面
Nginx的模块当中有一个ngx_http_stub_status_module模块,这个模块主要记录Nginx的基本访问信息,要使用该模块,需要在编译的时候增加http_stub_status_module模块进行支持。之后才能在nginx进行配置,以供访问指定页面获取nginx 的访问信息
在某个server{}中配置如下:
location /nginx_status {
auth_basic "Please input your acount"; #添加认证提示
auth_basic_user_file /usr/local/nginx/conf/htpasswd; #指定basic的密码文件
stub_status on;
access_log off;
}
认证文件使用httppasswd生成
访问status页面,内容如下
Active connections: 2 #表示Nginx正在处理的活动连接
server accepts handled requests
27 27 29
Reading: 0 Writing: 1 Waiting: 1
status页面解释
第一个server表示Nginx启动到现在工处理了27个连接;
第二个accepts表示Nginx启动到现在工成功创建了27次握手;
请求丢失数 = (握手数 - 连接数),可以看出,本次状态显示没有请求丢失
第三个handled requested,表示总共处理了29次请求;
Reading为Nginx读取到客户端的Header信息数;
Writing为Nginx返回给客户端的Header信息数;
Waiting为Nginx已经处理完正在等候下一次请求指令的驻留连接。在开启keepalived的情况下,这个值等于active - (reading + writing)
4.3 nginx日志
Nginx会把自身运行的故障信息及用户访问的日志信息记录到指定的日志文件当中。分别是error_log和access_log。
error_log的语法格式及参数语法说明:
error_log file level;
关键字 日志文件 错误日志级别
其中,关键字error_log不能改变,日志文件可以指定任意存放日志的目录,错误日志级别常见的有[debug |info |notice|warn|error|crit|alert|emerg],级别越高,记录的信息越少,一般使用warn|error|crit这三个级别之一,注意不要配置info这种较低级别,会带来巨大的磁盘I/O消耗。
error_log,可以放在main区块中全局配置,也可以放在不同的虚拟主机进行单独记录。
access_log主要有2个参数控制:
- log_format:定义记录日志的格式
- access_log:指定日志子文件的路径以及使用哪种日志格式记录。
Nginx的默认日志格式如下:
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
日志中的变量说明:
$remote_addr:记录访问网站的客户端地址
$http_x_forwarded_for:当前端有代理服务器时,设置Web节点记录客户端地址的配置,此参数生效的前提是代理服务器上也进行了相关的x_forwarded_for设置
$remote_user:远程客户端用户名称
$time_local:记录访问时间和时区
$request:用户的http请求起始行信息
$status:http状态码,记录请求返回的状态,例如:200、503
$body_bytes_sents:服务器发送给客户端的响应主体字节数
$http_referer:记录此次请求是从哪个链接访问过来的,可以根据referer进行防盗链设置
$http_user_agent:记录客户端访问信息,例如:浏览器、手机客户端等
记录日志配置如下:
access_log logs/access.log main;
关闭日志的方法
access_log off
error_log off
默认的情况下Nginx会把所有的访问日志都输出到一个access.log的日志当中,时间久了,就会导致日志臃肿,不利于分析和处理,所以有必要地对日志进行按天或按小时进行切割保存。切割的方式Nginx并没有像apache一样自带日志切割工具(rotatelogs),所以只能使用脚本的方式对日志进行切割。脚本如下:
[root@localhost ~]# vim cut_nginx_log.sh
#!/bin/bash
Dateformat=$(date +%Y%m%d)
Basedir="/usr/local/nginx"
Nginxlogdir="$Basedir/logs"
Logname="access_www"
[ -d $Nginxlogdir ] && cd $Nginxlogdir || exit 1
[ -f ${Logname}.log || exit 1
/bin/mv ${Logname}.log ${Dateformat}_${Logname}.log
$Basedir/sbin/nginx -s reload
[root@localhost ~] crontab -e #定时任务实现每天00点执行日志切割脚本
00 00 * * * /bin/bash /root/cut_nginx_log.sh >/dev/null 2>&1
4.4 root path和alias
root path可设置在http{},server{},location{},if location{}中
设置资源路径映射;用于指明请求的URL所对应的资源在的文件系统上的起始路径;
location /images/ {
root "/vhosts/web1/";
}
#则该服务的url根目录/对应文件系统中的/vhosts/web1/
#www.magedu.com/images/a.jpg <-- /vhosts/web1/images/a.jpg
alias path
用于location配置段,定义路径别名
location /images/ {
alias "/www/pictures/";
}
#www.magedu.com/images/a.jpg <-- /www/picuter/a.jpg
注意,alias关键字会将location后所匹配的内容进行完整替换为alias后的值。
alias后面错漏/符号时,curl 127.0.0.1/images/1.png报错如下
[error] 1508#0: *4 open() "/www/pictures1.png" failed (2: No such file or directory)
4.5 localtion
根据用户请求的URI来匹配定义的各location;匹配到时,此请求将被相应的location配置块中的配置所处理,例如做访问控制等功能;
使用格式如下:
location [ = | ~ | ~* | ^~ ] uri
{
...
}
可设置在server{},location{},location @name { … }
=:精确匹配检查;必须与localtion后的uri值完全相同
~: 正则表达式模式匹配检查,区分字符大小写;
~*: 正则表达式模块匹配检查,不区分字符大小写;
^~:URI的前半部分内容做匹配,不支持正则表达式;
匹配的优先级从左到右:
精确匹配=, ^~, 正则匹配, 不带任何符号的location, location / 通用匹配。
正则匹配时从上到下依次匹配,一旦匹配成功,则结束检查,并就会使用这个location块处理此请求(~*和~属于同级同属于正则匹配)
同级匹配的情况下(正则匹配除外)选择最长匹配的localtion 来处理。
location = / {
#规则A
}
location = /login {
#规则B
}
location ^~ /static/ {
#规则C
}
location ~ \.(gif|jpg|png|js|css)$ {
#规则D
}
location ~* \.png$ {
#规则E
}
location !~ \.xhtml$ {
#规则F
}
location !~* \.xhtml$ {
#规则G
}
location / {
#规则H
}
那么产生的效果如下:
访问 http://localhost/ 将匹配规则A
访问 http://localhost/login 将匹配规则B,http://localhost/register 则匹配规则H
访问 http://localhost/static/a.html 将匹配规则C
访问 http://localhost/b.png 将匹配规则D和规则E,但是规则D在规则E之前出现,所以规则E不起作用,而http://localhost/static/c.png 则优先匹配到规则C
访问 http://localhost/a.PNG 则匹配规则E,而不会匹配规则D,因为规则E不区分大小写。
访问 http://localhost/a.xhtml 不会匹配规则F和规则G,http://localhost/a.XHTML不会匹配规则G,因为不区分大小写。规则F,规则G属于排除法,符合匹配规则但是不会匹配到,所以想想看实际应用中哪里会用到。
访问 http://localhost/category/id/1111 则最终匹配到规则H,因为以上规则都不匹配,这个时候应该是nginx转发请求给后端应用服务器,比如FastCGI(php),tomcat(jsp),nginx作为反向代理服务器存在。
4.6 rewrite
通过正则表达式的使用改变URI。可以同时存在一个或者多个指令,按照顺序依次对URL进行匹配和处理。语法如下:
rewrite regex replaement [flag];
regex, 用于匹配URI的正则表达式。可以使用"()"标记要截取的内容,在后面的配置中可以使用$1表示第一个()所匹配到的,$2表示第二个,依次进行。
注意:
1)rewrite 接受到的URL不包含HOST地址,因此regex不可能匹配到URI的HOST地址。若请求的的URL为 http://myweb.com/source ,此时rewrite指令接受到的URI 是 "/source", 而不包含"myweb.com"。
2)请求URL中的请求指令参数也是不包含在rewrite指令接收到的URI内容中。比如: 请求的**URL:HTTP://myweb.com/sourcearg1=value1&arg2=value2**
rewrite指令接受到的URI为 "/source" 而不包含 "?arg1=value1&arg2=value2"
replaement, 匹配成功后用于替换URI 中被截取内容的字符串。默认情况下,如果该字符串是由"http://" 或"https" 开头的, 则不会继续对URI 进行处理,而是直接将重写后的URI返回给客户端。
flag,有四类分别是break、last、permanent、redirect 。
1)使用 break 和 last 标记, 浏览器地址栏中的地址显示是不会变化的;而permanent 和 redirect 则会变化。
-
使用 break 和 last 标记, 只产生了一次网络请求;而permanent 和 redirect 产生了两次网络请求。
-
使用 break 和 last 标记的转发规则,只能在同一个域名下进行, 而permanent 和 redirect 却可以在不同域名之间
last和break比较
当 break 和 last 结合 rewrite 指令使用在location 块之外时两个功能一样,当匹配为last和break标记的rewrite时,跳过后面的rewrite逻辑匹配。
当 break 和 last 结合 rewrite 指令使用在location 块之内时功能不一样,当匹配为last标记的rewrite时,会将rewrite 规则后重写的URL 在进行新一轮的location 选择。而break标记的rewrite重写的规则不会,继续在原的location中运行。
permanent和redirect比较
permanent, 将重写后的URI 返回给客户端,返回状态码为301。告诉搜索引擎这个重定向是永久重定向。
redirect, 将重写后的URI 返回给客户端,返回状态码为302。告诉搜索引擎这个重定向是临时重定向。
两个没有太大的区别,只是在于邮搜引擎优化时有差距。
4.7 if指令和全局变量
语法:if (condition) {…}
应用环境:server{}, location{}
conditon可以是如下任何内容:
- 当表达式只是一个变量时,如果变量的值为空或任何以0开头的字符串都会当做false
- 比较变量和指定内容时,可以使用=或!=
- 变量与内容正则表达式匹配,正则表达式匹配,*不区分大小写的匹配,!~区分大小写的不匹配
- 用来判断变量的表达式:
-f和!-f用来判断是否存在文件
-d和!-d用来判断是否存在目录
-e和!-e用来判断是否存在文件或目录
-x和!-x用来判断文件是否可执行
举例
if ($http_user_agent ~ MSIE) {
rewrite ^(.*)$ /msie/$1 break;
} //如果UA包含"MSIE",rewrite请求到/msid/目录下
if ($http_cookie ~* "id=([^;]+)(?:;|$)") {
set $id $1;
} //如果cookie匹配正则,设置变量$id等于正则引用部分
if ($request_method = POST) {
return 405;
} //如果提交方法为POST,则返回状态405(Method not allowed)。return不能返回301,302
Nginx的常用变量
$args : 这个变量等于请求行中的参数,同$query_string
$content_length : 请求头中的Content-length字段。
$content_type : 请求头中的Content-Type字段。
$document_root : 当前请求在root指令中指定的值。
$host : 请求主机头字段,否则为服务器名称。
$http_user_agent : 客户端agent信息
$http_cookie : 客户端cookie信息
$limit_rate : 这个变量可以限制连接速率。
$status 请求状态
$body_bytes_sent 发送字节
$request_method : 客户端请求的动作,通常为GET或POST。
$remote_addr : 客户端的IP地址。
$remote_port : 客户端的端口。
$remote_user : 已经经过Auth Basic Module验证的用户名。
$request_filename : 当前请求的文件路径,由root或alias指令与URI请求生成。
$scheme : HTTP方法(如http,https)。
$server_protocol : 请求使用的协议,通常是HTTP/1.0或HTTP/1.1。
$server_addr : 服务器地址,在完成一次系统调用后可以确定这个值。
$server_name : 服务器名称。
$server_port : 请求到达服务器的端口号。
$request_uri : 包含请求参数的原始URI,不包含主机名,如:”/foo/bar.php?arg=baz”。
$uri : 不带请求参数的当前URI,$uri不包含主机名,如”/foo/bar.html”。
$document_uri : 与$uri相同。
4.8 防盗链
location ~.*.(gif|jpg|jpeg|png|bmp|swf|flv|rar|zip|gz|bz2)$
{
expires 30d; //配置图片缓存时间
access_log off; //表示不记录gif|jpg等类型文件
valid_referers none blocked servernames *.taobao.com *.baidu.com *.google.com;
if ($invalid_referer )
{
return 403;
rewirte ^/http://www.abc.org/nophoto.gif;
}
}
valid_referers是可用的来源链,
none bolocked server_names是不进行防盗的主机域名,加起来是对于这些可用的链接不进行拦截而是加入白名单。
$invalid_referer,这一个变量表示是不可用的来源链,和可用的正好相反
盗用我们图片的人访问这些图片时会跳转到http://www.abc.org/nophoto.gif,也可以直接显示403,这样更节省资源。
4.9 ssl安全访问
```c
server {
listen 443 ssl; #监听443端口,启用ssl
keepalive_timeout 70; #启用保持活动连接
ssl_protocols TLSv1 TLSv1.1 TLSv1.2; #ssl写协议配置
ssl_ciphers AES128-SHA:AES256-SHA:RC4-SHA:DES-CBC3-SHA:RC4-MD5; #ssl加密方式
ssl_certificate /usr/local/nginx/conf/cert.pem; #指定证书文件
ssl_certificate_key /usr/local/nginx/conf/cert.key; #指定私钥文件
ssl_session_cache shared:SSL:10m; #启用共享会话缓存
ssl_session_timeout 10m; #ssl会话延时配置
......
}
五、nginx作为反向代理服务器
简单例子
server {
listen
server_name
location / {
proxy_pass http://192.16.3.7:80/;
##设置代理的后端服务,nginx构建新的报文请求
proxy_set_header Host $host;
##设置自定义首部Host,记录客户端请求目标
proxy_set_header X-Real-IP $remote_addr;
##设置自定义首部X-Real-IP,记录真实的客户端IP
}
}
常用格式
uri理解为地址后面的所有字符
格式一:
location /uri {
proxy_pass http://back_server:port/newuri;
}
此格式下:nginx重构请求报文时将客户请求的url换成newurl写入重构报文中
Nginx的配置文件如下
客户端请求URL
后端服务器收到的nginx代理请求的URL
格式二:
location ~/uri {
proxy_pass http://back_server:port;
}
此格式下:nginx重构请求报文时将被location正则表达式匹配到的客户请求url补充在proxy_pass设置的后,成为/url写入重构报文中。
举例验证,nginx部分配置内容如下:
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
root /usr/share/nginx/html;
location ~ /1.png {
proxy_pass http://127.0.0.1:8081;
}
}
server {
listen 8081;
server_name _;
root /alias;
access_log /var/log/nginx/access1.log main;
}
当客户端请求curl 127.0.0.1/1.png时会有两次日志输出
80虚拟主机日志输出内容
127.0.0.1 - - [13/Feb/2020:11:34:33 +0800] "GET /1.png HTTP/1.0" 200 13 "-" "curl/7.29.0" "-"
8081虚拟主机日志输出内容
127.0.0.1 - - [13/Feb/2020:11:34:33 +0800] "GET /1.png HTTP/1.0" 200 13 "-" "curl/7.29.0" "-"
证明80虚拟主机重构报文,是将匹配的uri补充在proxy_pass所设置内容后
格式三:
location /uri {
rewrite /url2
proxy_pass http://back_server:port;
}
此格式下:nginx重构请求报文时将客户请求的url先进程rewrite转换为url2,然后补充在成newurl后,成为/newurl/url2写入重构报文中
特别提醒:在proxy_pass指令后URL对于/的使用要特别仔细。
location /pks {
proxy_pass http://127.0.0.1:8081/;
}
如上,修改80虚拟主机的location部分,在proxy_pass地址后面加了/就视为uri,属于格式一的情况;
发起请求curl 127.0.0.1/pks/1.png,80虚拟主机报文重构成127.0.0.1//1.png发给后端服务器。8081虚拟主机日志输出
127.0.0.1 - - [13/Feb/2020:11:48:10 +0800] "GET //1.png HTTP/1.0" 200 13 "-" "curl/7.29.0" "-"
常用的proxy反向代理配置
Proxy_connect_timeout
定义与后端服务建立连接的超时时间,即nginx发起握手等候服务器的响应超时时间。默认60s
Proxy_read_timeout
定义连接建立后,等待后端服务开始传送响应报文的时间,而不是后端服务把整个响应报文传送完毕
proxy_send_timeout
定义后端服务器数据回传时间_就是在规定时间之内后端服务器必须传完所有的数据的超时时间
Proxy_hide_header
定义nginx将哪些响应首部header不传递给客户端
Proxy_pass_header
定义nginx将那些响应首部header传递给客户端
Proxy_pass_request_body
定义是否将原始请求报文body部分传递给后端的服务器
Proxy_pass_request_header
定义是否将原始请求报文的header部分传递给后端服务器
Proxy_buffering
定义是否开启nginx代理时的缓冲功能。
一旦开启缓冲功能,nginx代理会尽可能快的接受并读取后端服务的响应报文,如果响应报文超过缓冲池的大小,会将报文的一部分存放在磁盘上的临时文件目录。临时文件目录的使用有其他参数设置。
一旦关闭缓冲功能,Nginx不会尝试获取到后端服务器所有响应数据之后才返回给客户端,Nginx 会尽快把数据传给客户端,在数据传完之前,Nginx 接收到的最大缓存大小不能超过 proxy_buffer_size 。
注意一旦proxy_buffering off,nginx的cache就不会工作,后面设置的一段cache参数统统无效!
Proxy_buffers
对nginx代理与后端服务器的单次连接传输 ,设置缓冲的数量和大小,默认缓冲大小等于一个内存页面,4K或8K
Proxy_busy_buffers_size
当nginx的缓冲功能开启,且nginx还没有完全读取后端服务的响应报文时,设定一个缓冲池里能用于传递给用户的响应报文最大空间。与此同时,缓冲池里空闲的空间将继续用于读取后端服务发来的响应报文,也可以用到磁盘上的临时文件来读取后盾的服务响应报文。
Proxy_cache_path
Nginx在内存中使用一对对hash键值的方式建立缓存,内存中的值均为系统中的文件路径。
该参数的配置形式:
proxy_cache_path path [levels=levels] [use_temp_path=on|off] keys_zone=name:size [inactive=time] [max_size=size] [manager_files=number] [manager_sleep=time] [manager_threshold=time] [loader_files=number] [loader_sleep=time] [loader_threshold=time] [purger=on|off] [purger_files=number] [purger_sleep=time] [purger_threshold=time];
path选项用于指定缓存文件的跟目录
level=缓存根目录下有几层子目录
以levels=1:3举例
:用于区分几层,其中的数字1和3用于指明每层目录的目录名有几位字符 1表示一位 3表示3位。
key_zone 在内存中划定用于存放缓存hash键值的空间
以keys_zone=my_cache:10m举例
使用的内存空间名为my_cache 10m表示有10mb,1MB的内存空间可以存储大约8000个key
Inactive
设置数据多长时间没有被访问将删除
max_size
设置硬盘缓存空间大小
Proxy_cache zone
表示使用哪个缓存空间
Proxy_cache_methods
仅在客户端使用某种请求方法时才用nginx的缓存资源响应
Proxy_cache_min_uses
配置客户端请求发送的次数,当相同请求达到设置次数后才会缓存该请求的响应数据,默认为1
Proxy_cache_purge
用于主动清理缓存空间中的缓存条目。及时缓存资源未过期
Proxy_cache_revalidate
用于缓存到期后,与后端服务器进行校验,如果检验结果后端服务器资源未变更,则对缓存资源续期
Proxy_cache_use_stale
定义后端服务器发生某种情况时,使用与之对应的过期的缓存条目进行响应
例如服务端报404或者502等错误时,使用nginx之前过期的缓存响应客户端。
Proxy_cache_calid
根据后端服务的不同响应码定义各自响应报文的缓存时间
Proxy_redirect
Nginx响应重新构建响应报文时,将后端服务器的域名替换为指定值,掩藏后端服务的信息。
六、nginx作为负载均衡时的配置
Nginx作为负载均衡使用(依赖upstream模块),需要与各类反向代理模块共同使用。实现原理:将多个后端服务器归为一个服务器组,反向代理功能引用该组。
负载均衡的配置方式
Upstream name {
调度算法;
Server address [parameters];
}
注意:nginx的负载均衡自带对后端服务器的健康状态检查
调度算法
1、默认为轮询算法,按客户端请求顺序依次将客户端的请求逐一分配到不同的后端服务器节点,如果后端节点服务器宕机,宕机的服务器会从服务器池中剔除,保证用户访问的正常。
2、Ip_hash:根据客户端IP进行分配,类似LVS的SH算法;当新的请求到达,先将客户端IP通过哈希算法哈希出一个值,在随后的客户端请求中,客户的IP哈希值只要相同,就会被分配到同一台服务器上
3、hash URL:根据客户端请求的url进行调度
4、hash $key:根据客户请求url的某个字段进行调度
5、least_conn:根据后端最少连接+权重进行派发
6、least_time:根据后端最少响应时间+权重进行派发
address:
ip[:port]
域名[:port]
Parameters:
weight=number 设定后端服务的权重值,权重越大分配的次数越多。
max_conns=number 设定对后端服务最多的有效连接值
max_fails=number
fail_timeout=time
max_fails和fails_timeout都是配合使用的。在fails_timeout的时间内,连接失败的次数超过max_fails的值就视为该服务为down。被判定down后会在fail_timeout后再对该服务进行判定。
backup 设为备用服务器
down 手动设为不可用服务
举例根据URL的某个字段进行调度