Nginx
轻量级、高性能的web服务器
模块化
一、研究前的准备工作
Nginx的特点
- 更快,单次请求很快,高峰期可以获得比其他Web服务器更快的相应速度。
- 高扩展性,模块化的设计。Nginx是由多个不同功能、不同层次、不同类型且耦合度极低的模块组成。
- 高可靠性,worker进程相对独立,master进程在1个worker进程出错时,可以快速拉起一个新的worker进程提供服务
- 低内存消耗,一般情况下,1w个非活跃的HTTP Keep-Alive连接在Nginx中仅消耗2.5M的内存,这是Nginx支持高并发的基础
- 单机支持10w+的并发连接
- 热部署,master进程与worker进程分离
- 最自由的BSD许可协议
除上述几点之外,Nginx还有很多的官方功能模块,第三方功能模块,有些模块支持Perl、Lua等脚本语言集成工作。
准备工作
-
linux 2.6+
- 因为linux2.6+内核才支持epoll,而在linux上使用select和poll来解决事件的多路复用,是无法解决高并发压力问题的。
-
必备软件
- GCC编译器
- PCRE库(用于解析正则表达式,如url重写)
- zlib库(用于压缩文件,减少网络传输内容大小,提高相应时间)
- zlib-devel是二次开发所需要的库
- OpenSSL开发库(https用)
具体需要安装哪些软件,视实际需要来定。
默认安装的部分模块
- http_gzip_module # 执行gzip压缩文件
- http_rewrite_module # 提供http请求在nginx内部重定向
- http_proxy_module # 提供基本的http反向代理功能
- http_fastcgi_module # 提供fastCGI模块
- http_upstream_ip_hash_module # 用于计算客户端与哪个上游主机通信,实现负载均衡
- …
在编译的时候,加上参数 --without-http_xxx 可以不安装对应模块
默认不安装的部分模块
-
http_ssl_module # 支持ssl协议
-
http_dav_module # 支持PUT/DELETE/COPY/MOVE/MKCOL等restful请求方式
-
…
在编译的时候,加上参数 --without-http_xxx 可以不安装对应模块
常用命令
- 默认方式启动,直接执行Nginx二进制程序,如:
/usr/local/nginx/sbin/nginx
- 另行指定配置文件的启动方式,如:
nginx -c /etc/nginx/nginx.conf
- 在不启动nginx的情况下,仅测试配置文件是否有错误
nginx -t
- 显示版本
nginx -v
- 显示版本及编译阶段的参数
nginx -V
- 快速停止服务
nginx -s stop
- 优雅地停止服务
nginx -s quit
,区别就是会先关闭监听,然后等所有的正在处理的连接全部处理完在退出进程 - 重载配置
nginx -s reload
二、Nginx的配置
通常在生产环境下,Nginx使用一个master进程来管理多个worker进程,worker进程数一般和服务器的CPU核心数一致。
Apache的每个进程在同一时刻只能处理一个请求,如果需要处理高并发,需要把Apache的进程数设置得很高,通常能达到一台机器有几百个工作进程,大量的进程间切换将带来大量的系统资源消耗。而Nginx则不然,一个worker进程可以同时处理的请求数只取决于内存大小,在架构设计上,不同的worker进程之间处理并发请求时几乎没有同步锁的限制,worker进程通常不会进入睡眠状态,故当Nginx上的进程数与CPU核心数相等时(最好每隔worker进程都绑定特定的CPU核心),进程间切换的代价是最小的。
Nginx配置的通用语法
- 块配置项,由一个块配置项名和一对大括号组成。块配置项可以嵌套,内层块直接继承外层块,但内外层的配置项名相同时,具体以哪一层为准,取决于具体的模块。
- 配置项的语法格式,
name value1 value2 ...;
空格分隔,分号结尾,不得出现不支持的模块配置项名。 - #号注释
- 变量,某些模块提供一些变量,并非通用。
- 每个配置项都有对应的配置块,放错了位置可能会报语法错误。
基本配置
user nginx;
注意不要把启动用户设置为root,因为worker进程出问题后,master进程需要有权限停止、启动worker进程error_log /path/file level;
,默认为error_log logs/error.log error;
如果设置为debug
等级,会输出所有的日志,导致log文件巨大。- include /path/file; 嵌入其他配置文件
- include mime.types;
- include conf.d/*.conf;
pid logs/nginx.pid;
保存master进程id的文件,要确保Nginx有权在相应的目标路径中创建pid文件的权限,否则Nginx将无法运行worker_processes number;
worker进程数量,一般情况下,与CPU核心数保持一致
用HTTP核心模块配置一个静态web服务器
-
listen 监听端口
listen 80; listen 127.0.0.1:8000; listen 127.0.0.1; # 不加端口时,默认监听80端口 listen *:8000; listen www.example.com:8000;
若服务器使用IPv6地址,使用下面方式
listen [::]:8000; listen [fe80::1]; listen [::a8c9:1234]:80;
在地址和端口后,还可以加其他参数,如:
listen 443 default_server ssl; listen 127.0.0.1 default_server accept_filter=dataready backlog=1024
default和default_server:将所在的块作为整个web服务的默认server块,若没有设置这个参数,那么将会以nginx.conf中找到的第一个server块作为默认server。当一个请求无法匹配配置文件中的所有主机域名时,就会选用默认的虚拟主机。
backlog:TCP中backlog队列的大小,默认为-1,表示不予设置。
ssl:在当前监听的端口上建立的连接必须基于SSL协议。
-
server_name 主机名称
server_name yourdomain.com 123.123.123.123;
server_name与Host的匹配优先级如下:
1)首先选择所有字符串完全匹配的server_name,如www.testweb.con。
2)其次选择通配符在前面的server_name,如*.testweb.com
3)再次选择通配符在后面的server_name,如www.testweb.*
4)最后选择使用正则表达式才匹配的server_name,如~^\testweb.com$
如果以上都匹配不到,就
5)选择在listen配置项后加入[default|default_server]的server块
6)找到匹配端口的第一个server块
-
location
location [=|~|~*|^|@] /uri/ {...}
location会根据请求的URI来匹配上面的/uri表达式,如果可匹配,就选择location {}块中的配置来处理该请求1)=表示把URI作为字符串,与参数中的uri做完全匹配,如:
location = / { # 只有当用户请求是/时,才会使用该location下的配置 ... }
2)~表示匹配URI时是字母大小写敏感的
3)~*表示匹配URI时忽略字母大小写问题
4)^~表示匹配URI时只需前半部分与URI参数匹配即可,如:
location ^~ /images/ { # 以/images/开始的请求会匹配上,可做防盗链 ... }
location是有顺序的,如果一个请求可以匹配多个location,那么会被第一个location处理
location / {}
可以匹配所有的HTTP请求,如果不能匹配此location之前的所有项,就会由这个来处理,相当于switch的default,可以用来实现,如果不匹配xxx则xxx的需求。 -
root 设置资源路径,可置于http,server,location,if块下,定义资源文件相对于HTTP请求的根目录,
location /download/ { root /opt/web/html; }
若一个请求的URI是/download/index/test.html,那么web服务器会返回/opt/web/html/download/index/test.html文件的内容。
-
alias 也是设置文件资源路径,只能放在location块下,与root的区别在于,如:有个请求的URI是/conf/nginx.conf,而实际想访问的文件在/usr/local/nginx/conf/nginx.conf,用alias和root分别设置的方式如下:
# alias方式 location /conf { alias /usr/local/nginx/conf/; } # root方式 location /conf { alias /usr/local/nginx/; }
1)使用alias是,在URI向实际文件路径的映射过程中,已经把location后配置的/conf这部分字符丢弃掉,故/conf/nginx.conf请求将根据alias path映射为path/nginx.conf
2)而root则根据完整的URI请求来映射,故/conf/nginx.conf会根据root path映射为path/conf/nginx.conf
3)这也是root可以放到http,server,location,if块下,而alias只能放置于location块下的原因
4)alias后还可以添加正则表达式,如:
location ~ ^/test/(\w+)\.(\w+)$ { alias /usr/local/nginx/$2/$1.$2; }
这样,请求在访问/test/nginx.conf时,Nginx会返回/usr/local/nginx/conf/nginx.conf文件的内容。
-
index 访问首页
index index.php html/index.php index.html
当访问的URI是/时,Nginx将会根据index配置的顺序,从左往右去查找这些文件,找到就立马返回。
如:当root目录下同时包含
index.php
和index.html
时,会使用index.php
文件 -
sendfile on;
开启后,nginx可以把硬盘中的文件不载入内存就直接发送出去 -
error_page 错误码重定向
# 将返回码为xxx的请求重定向到新的URI error_page 500 502 503 504 /50x.html; # 上面的重定向,不会修改返回的HTTP错误码,想改错误码可以通过 = 来指定 error_page 404 =200 /empty.gif # 也可以不指定具体的错误码,而是让重定向后实际处理的真实结果来决定 error_page 404 = /empty.gif # 若不想修改URI,只是想让这样的请求重定向到另一个location中进行处理 location / { error_page 404 @fallback } location @fallback { proxy_pass http://backend; } 这样,404的请求就会被反向代理到http://backend的上游服务器中处理
-
try_files path1 [path2] uri;
try_files后要跟若干路径,最后必须要有URI参数,意义如下:
1)尝试按照顺序访问每一个path,若可有效读取,就直接向用户返回这个path对应的文件结束请求,否则继续向下访问。
2)若所有的path都找不到有效的文件,就重定向到最后的参数URI上,所以最后的URI参数是必须存在的,且应该是有效的。
laravel的推荐配置为
try_files $uri $uri/ /index.php?$query_string;
即:- 先按路由的uri部分找对应的 r o o t / root/ root/uri文件是否存在;
- 若不存在,则去寻找是否存在 r o o t / root/ root/uri/这样的目录;
- 若仁不存在,则将请求重新转到 r o o t / i n d e . p h p ? root/inde.php? root/inde.php?query_string作为请求发出去
-
autoindex on;
在没有设置index的时候,可以作为一个静态资源共享盘使用,如果开启的话,并且没有对应的index文件,会报403 Forbiddenautoindex on; # 索引 autoindex_exact_size off; # 显示文件大小 # 默认为on,显示出文件的确切大小,单位是bytes。 # 改为off后,显示出文件的大概大小,单位是kB或者MB或者GB autoindex_localtime on; # 显示文件时间 # 默认为off,显示的文件时间为GMT时间。 # 改为on后,显示的文件时间为文件的服务器时间 auth_basic "输入用户名密码"; auth_basic_user_file /etc/nginx/passwd.db.conf; # auth_basic_user_file需要Apache的一个软件htpasswd生成,需要安装Apache或者下载独立的htpasswd脚本执行
-
gzip 可以对指定的文件进行gzip压缩,浏览器接收到response header信息(content-type:gzip)后会进行解压缩,提高相应速度
gzip on; # 开启gzip压缩,可压缩传输的文件大小,提示响应速度 gzip_min_length 1024; # 进行压缩的最小文件尺寸,单位byte字节 gzip_types text/plain text/css application/javascript application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/vnd.ms-fontobject application/x-font-ttf font/opentype image/svg+xml image/x-icon;
-
keepalive_timeout 超时时间,默认75
keepalive_timeout 75;
-
limit_except method …{…} 按HTTP方法名限制用户请求,方法名可取值包括:GET,HEAD,POST,PUT,DELETE,MKCOL,COPY,MOVE,OPTIONS,PROPFIND,PROPPATCH,LOCK,UNLOCK或者PATCH。如:
# 禁止GET方法(GET方法包含HEAD方法)和HEAD方法,其他方法是允许的
limit_except GET {
allow 192.168.1.0/32;
deny all;
}
-
client_max_baody_size 1m; HTTP请求包体的最大值,过滤HTTP请求头中的Content-Length字段超过定义值的请求,在收到包头之后,直接返回413响应(文件过大),而不会去接收包体。
-
limit_rate_spped 0; 限制对客户端每秒传输的字节数,0表示不限速,可对不同客户端采用不同限速策略。
-
resolver address …; 设置DNS名字解析服务器的地址,如:
resolver 127.0.0.1 192.0.2.1;
-
set $limit_rate 1k; 设置响应速度为1kb/s
-
在配置文件的http{}段增加一行配置
server_names_hash_bucket_size 64;
如果64还不够,那么就按32的倍数往上加。下面是在中文wiki上摘抄的一段说明:
保存服务器名字的hash表是由指令 server_names_hash_max_size 和 server_names_hash_bucket_size所控制的。参数hash bucket size总是等于hash表的大小,并且是一路处理器缓存大小的倍数。在减少了在内存中的存取次数后,使在处理器中加速查找hash表键值成为可能。如果 hash bucket size等于一路处理器缓存的大小,那么在查找键的时候,最坏的情况下在内存中查找的次数为2。第一次是确定存储单元的地址,第二次是在存储单元中查找键值。因此,如果Nginx给出需要增大 hash max size 或 hash bucket size的提示,那么首要的是增大前一个参数的大小.
用HTTP proxy module配置一个反向代理服务器
Nginx的反向代理,在client发来HTTP请求时,会先把用户的请求(包含HTTP包体)完整的接收到Nginx所在的服务器的硬盘或内存中,然后再向上游服务器(真实响应工作的机器)发起连接,把缓存的client请求发到上游服务器。这种特点的缺点是延长了一个请求的处理时间,并增加了用于缓存的请求内容的内存和磁盘空间,而优点则是降低了上游服务器的负载,尽量把压力放在Nginx服务器上。
之所以能减低上游服务器的负载,主要是因为通常client和服务器走的是公网,网速平均下来较慢,而代理服务器和上游服务器一般走内网,网速较快,所以Nginx在接收完了client的请求内容后,转发给上游服务器的速度很快,这样,一个client请求占用上游服务器的连接时间会非常短,这种代理方案降低了上游服务器的并发压力。
-
upstream块,配置在http块下,与server同级
upstream backend { server backend1.example.com; server backend2.example.com; server backend3.example.com; } server { location / { proxy_pass http://backend; } }
-
server块,配置在upstream块下,server配置项指定一台上游服务器的名字,可以是域名、ip地址端口、UNIX句柄等,还可以在后面跟以下参数:
1)weight=number 设置这台上游服务器的权重,默认为1 2)max_fails=number 与fail_timeout配合使用,指在fail_timeout时间段内,如果向当前上游服务器的转发次数超过number,则认为当前的这台上游服务器不可用,max_fails默认为1,0表示不检查失败次数 3)fail_timeout 默认10秒 4)down 表示所在的上游服务器永久下线,只在使用ip_hash配置时才有效 5)backup 在使用ip_hash配置时无效。表示所在的上游服务器只是备份服务器,只有所有的非备份上游服务器都失效后,才会向他所在的上游服务器转发请求
-
ip_hash 配置在upstream块下,在有些场景下,希望某一个用户的请求固定落在某一台上游服务器上,可以使用此功能,它会根据用户的ip计算出一个key,将key按照upstream集群里的上游服务器数量进行取模,然后以取模的结果把请求转发到相应的服务器上,ip_hash与weight配置不可同时使用。如果upstream集群中有一台服务器暂时不可用,不能直接删除该配置,而是要down参数标识,确保转发策略的一贯性,如:
upstream backend { ip_hash; server backend1.example.com; server backend2.example.com; server backend3.example.com down; server backend4.example.com; } # ip_hash与weight同时使用时,ip_hash的优先级更高
-
proxy_pass URL; 配置在location、if块下,将当前请求反向代理到URL参数指定的服务器上,URL可以是主机名或IP地址加端口的形式,也可以是UNIX句柄,也可以是负载均衡的upstream块名
默认情况下,反向代理不会转发请求中的Host头部,需加上
proxy_set_header Host $host;
才可以。有些情况下,$host的端口不是80,还需要在后面追加端口 $host:8080以下为一个简单的例子,让10.0.150.171:8083/代理到https://www.baidu.com
server { listen 8083; server_name 10.0.150.171; location / { proxy_pass https://www.baidu.com; } }
但上面这种代理方式,会丢失原请求的部分头部信息,可在proxy_pass后加上以下内容
# 可以通过手动指定这些参数,模拟任意客户端ip访问 proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
-
mmm
注意事项
error_log /path/file level;
,默认为error_log logs/error.log error;
如果设置为debug
等级,会输出所有的日志,导致log文件巨大。- nginx配置文件里的大小单位默认为字节,还有k,K,m,M,g ,G