Nginx
做为 web 服务器
以低内存,高扩展,而且轻松单机支持 1-3w
(听说能够单机 10w,但没有看到具体的机器配置)的并发连接的特性广受开发人员的青睐。javascript
推荐在 linux
系统上使用 Nginx
,这会充分利用 linux
的特性,性能比在 windows
上会更好。css
本文主要内容:html
后续章节,我会使用 ab
压测来一步一步优化 Nginx
的配置,Nginx 知道原理,懂得经常使用配置便可。有的性能优化须要了解 linux 内核
、http
、tcp
相关的东西,若是你不想了解,能够记录一份本身的配置便可,没必要纠结为何。java
本文内容在 nginx 1.16.1
上测试,Centos 7
4核 8g 内存的虚拟机。linux
根据 阿里 CentOS 镜像 配置 yum
源,提升下载速度。webpack
阿里 epel 镜像 配置咱们经常使用软件的包,Nginx
也在其中。nginx
# 运行一下命令,更新 yum 源 yum clean all yum makecache
刷新 yum
仓库信息以后,运行如下命令就能够找到 nginx
web
yum list | grep nginx
安装 nginx
正则表达式
sudo yum install nginx
配置 nginx
开机启动json
sudo systemctl enable nginx
启动 nginx
sudo systemctl start nginx
检查 nginx
是否启动
sudo systemctl status nginx
若是想查看 nginx
包都安装了哪些文件,可使用
rpm -qvl nginx
# 强制当即关闭,不建议作 nginx -s stop # 正常关闭,会处理已经接到的请求,但不会接受新的请求 nginx -s quit # 从新加载配置文件 nginx -s reload # 从新打开日志文件 nginx -s reopen # 检查配置文件是否有误 nginx -t # 检查配置文件是否有误,会将配置文件内容打印 nginx -T # 查看 nginx 版本 nginx -v # 查看 nginx 版本和编译配置致残 nginx -V
sudo systemctl enable nginx sudo systemctl start nginx sudo systemctl restart nginx sudo systemctl stop nginx sudo systemctl status nginx
部署的 Nginx
使用一个 master
进程管理多个 worker
进程。master
进程不处理请求,提供管理服务,包括启动、中止、重载配置文件等服务,一般以 root
用户启动, worker
进程进行请求的处理,通常用非管理员帐户启用,worker
进程数量和 cpu 核心设置一直,下降进程切换带来的 cpu
切换。
http
上下文中的配置是咱们重点须要知道的,其他的了解会配置便可。
http { include /etc/nginx/mime.types; default_type application/octet-stream; server { listen 80 ; server_name _; root /usr/share/nginx/html; location / { } } }
Server
既配置一个服务。
listen 80
用于配置监听 80
端口的服务。
root
指定静态资源存放的位置。
location 进行资源匹配。location / {}
匹配全部的资源。
listen
和 server_name
配置匹配规则:
listen
再匹配 server_name
server_name
匹配请求头中的 Host
default_server
的处理server { listen 9099 default_server; server_name "localhost"; location / { return 200 "server_name 为 localhost"; } } server { listen 9099; server_name 127.0.0.1; location / { return 200 "server_name 为 127.0.0.1"; } } server { listen 9099; server_name "localhost77"; location / { return 200 "server_name 为 localhost77"; } }
在 Postman
中设置请求头 Host
模拟访问。
http://localhost:9099
Host:127.0.0.1
返回 server_name 为 127.0.0.1
http://localhost:9099
Host:localhost
返回 server_name 为 localhost
http://localhost:9099
Host:localhost77
返回 server_name 为 localhost77
http://localhost:9099
Host:localhost779
返回 server_name 为 localhost
再添加一个配置
server { listen localhost:9099 default_server; server_name "localhost"; location / { return 200 "server_name 为 localhost:9099"; } }
当 listen
访问 localhost:9099
的时候,返回 server_name 为 localhost:9099
,由于只有这一个匹配上了。
若是想禁止没有 Host
请求头的访问。
server { listen 80; server_name ""; # 表示 nginx 会关闭链接 return 444; }
return
配置return
用于定义返回的状态码,或者内容。
介绍 return
主要是为了好描述 location
配置
- | 说明 |
---|---|
语法 | return code [text];<br/>return code URL;<br/>return URL ; |
默认 | - |
上下文 | server、location、if |
code
为状态码。text
为字符串。
location /a { default_type application/json; return 200 "访问 9088/a"; }
# 重定向 location = /b { return 301 http://www.baidu.com; }
location
配置location
用于匹配资源。
<font color=red>数字越小,优先级越高。</font>
规则符号 | 描述 | 优先级 |
---|---|---|
location = /a{} |
精准彻底匹配,匹配到以后 | 1 |
location ^~ /a{} |
前缀匹配,匹配到以后 | 2 |
location ~ /a.*{} | 正则匹配,区分大小写,检查到以后,还会检查有没有优先级跟高的 | 3 |
location ~* /a.* | 正则匹配,不区分字母大小写,检查到以后,还会检查有没有优先级跟高的 | 4 |
location /a {} | 也表示前缀匹配,可是优先级低于 正则匹配。 /a 和 ^~/a 会冲突,报错 |
5 |
location / {} | 任何没有匹配成功的,都会匹配这里处理 | 6 |
server { listen 9088 default_server; server_name _ ; location = /a { default_type application/json; return 200 "= /a,优先级第一"; } location ^~ /a { default_type application/json; return 200 "^~ /a 匹配 /a 开头的路径,优先级第二"; } location ~ /a\.* { default_type application/json; return 200 " /a\.* 匹配 /a...路径,优先级第三"; } location ~* /a\.* { default_type application/json; return 200 "~* /a\.* 匹配 /a...路径,优先级第四"; } # /a 会和 ^~ /a 冲突 location /a/ { default_type application/json; return 200 "/a/ 匹配 /a/...路径,优先级第五"; } }
访问 http://localhost:9088/a
,依次注释优先级较高的,能够验证这个规律。
还有一类特殊的 location
用于配置跳转的,以 @
开头
location @pass { }
- | 说明 |
---|---|
语法 | add_header name value [always]; |
默认 | - |
上下文 | http、server、location、location 中的 if |
若是响应代码等于 200、20一、20四、20六、30一、30二、30三、30四、307或 308,则将指定的字段添加到响应报头中。
加上 always
无论什么状态码都加上。
location ~ /a\.* { default_type application/json; add_header test1 "asdfasdf" always; return 200 " /a\.* 匹配 /a...路径,优先级第三"; }
- | 说明 |
---|---|
语法 | error_page code …[=[response code]] uri; |
默认 | - |
上下文 | http、server、location、location 中的 if |
配置错误状态码跳转页面。
error_page 404 /404.html; error_page 500 502 503 504 /50x.html;
以上不会改变响应状态码。
# 改变响应状态吗。 error_page 404 =200 /404.html;
server { location / { error_page 404 = @ops-coffee; } location @ops-coffee { rewrite .* / permanent; } }
alias
理解为:路径替换,location 以 /
结尾,alias 必须以 /
结尾。严格匹配。alias
替换掉 location
路径。
# /bieming/ 替换 /usr/local/var/www/alias2/ # 访问 /bieming/1.jpg 去寻找 /usr/local/var/www/alias2/1.jpg location /bieming/ { alias /usr/local/var/www/alias2/; }
root
理解为:root 路径加上 + location
路径。会将两个或更多个 /
压缩成一个。
# 当 location 和 root 路径的最后一部分匹配时,更好的方式是使用 root ## 如下配置均可以。 # 访问 /data2/1.jpg 去寻找 /usr/local/var/www/data2/1.jpg location /data2/ { root /usr/local/var/www; } location /data2/ { root /usr/local/var/www/; } location /data2 { root /usr/local/var/www; } location /data2 { root /usr/local/var/www/; } location /data2/ { root /usr/local/var/www////; }
经过内置变量,咱们能够经过判断请求头、query string
等值来转发或者拒绝访问。
$arg_name
获取请求参数获取请求query string
中的 name
参数。
location /arg/ { default_type application/json; return 200 "$arg_q1"; }
/arg/a?q1=334
返回的内容为 334
。
$args
获取请求 query_string
参数location /arg/ { default_type application/json; return 200 "$arg_q1 _ $args"; }
浏览器访问 /arg/a?q1=3334&aa=2&bb=33
返回的内容为 3334 _ q1=3334&aa=2&bb=33
$cookie_name
获取cookie的值获取请求中的名称为 name
的 cookie。
$http_name
获取请求头name
为请求头中的字段名称,请求头名称所有小写,并将破折号-
替换为下划线 _
$http_user_agent
获取请求头中的 User-Agent
字段。
$uri
获取请求路径中的 path
path
为端口后面的路径,不包括 query string
。优化以后的路径,特殊字符转译及 /
压缩。
http://localhost:8888/arg/a?q1=q1canshu&bb=2323
中的 path
为 /arg/a
$host
获取请求的 ip
首先会获取请求头 Host
,若是没有请求头中没有 Host
请求头,那么获取的是 url
中的 ip
。
$request_uri
获取 path
和 query string
访问 http://localhost:8888/arg/a/?q1=q1canshu&bb=2323
$request_uri
为/arg/a/?q1=q1canshu&bb=2323
$scheme
获取请求协议值为 http
或 https
$request_method
获取请求方法得到的值字母全大写。GET,POST,DELETE,PUT 等
- | 描述 |
---|---|
$content_length |
获取 Content-Length 请求头字段。 |
$content_type |
获取 Content-Type 请求头字段 |
$https |
若是链接以 SSL 模式运行,则为 on ,不然为空字符串 |
$is_args |
若是请求行有参数则为 ? ,不然为空字符串 |
$pid |
获取处理当前请求的 worker pid |
$nginx_version |
获取 nginx 的版本 |
- | 说明 |
---|---|
语法 | if (condition ){} |
默认 | - |
上下文 | server、location |
指定的 condition 求值以后,若是为 true ,则执行在大括号内指定的该模块的指令,并在 if 指令内为该请求分配配置。 if 指令内的配置继承自上一层的配置级别。
condition 能够是如下任何一种:
变量名,若是变量的值为空字符串或 0 ,则为 false
使用 = 和 != 运算符比较变量和字符串
使用 ~ (区分大小写的匹配)和 ~* (不区分大小写的匹配)运算符,变量将与正则表达式进行匹配。正则表达式能够包含可供之后在 $1
..$9
变量中重用的捕获。
反操做符 !~ 和 !~* 也可用。若是正则表达式包含 } 或 ; 字符,则整个表达式应使用单引号 或双引号包围起来。
使用 -f 和 !-f 运算符检查文件是否存在
使用 -d 和 !-d 运算符检查目录是否存在
使用 -e 和 !-e 运算符检查文件、目录或符号连接是否存在
使用 -x 和 !-x 运算符检查是否为可执行文件
<font color=red>if
与小括号之间须要有空格</font>
location = /a { default_type application/json; if ($request_uri ~* "/(a).*") { return 200 "正则表达式捕获的值:$1"; } return 200 "= /a,优先级第一"; }
- | 说明 |
---|---|
语法 | rewrite regex replacement [flag]; |
默认 | - |
上下文 | server、location、if |
flag
可选参数:
中止匹配,发送一个新的请求去匹配 location
。
中止匹配,在当前 location
去搜索资源。
临时重定向。返回状态码 302
。
永久重定向。返回状态码 301
。
指定的 regex
能匹配,uri 将根据 replacement
来处理。
如下三张图片都存在,可是内容不同。
/Users/zhangpanqin/stduy_app/break2/test/1.jpg
/Users/zhangpanqin/stduy_app/last2/test/1.jpg
/Users/zhangpanqin/stduy_app/test/1.jpg
location /break2 { root /Users/zhangpanqin/stduy_app/break2; rewrite /break2/(.*) /test/$1 break; } location /last2 { root /Users/zhangpanqin/stduy_app/last2; rewrite /last2/(.*) /test/$1 last; } location /test/ { root /Users/zhangpanqin/stduy_app; }
当访问 /break2/1.jpg
实际匹配第一个 location
,而后在当前上下文处理 。
/break2/1.jpg
被替换为 /test/1.jpg
来处理了,而后和 root
指定的路径相结合,返回 /Users/zhangpanqin/stduy_app/break2/test/1.jpg
数据。
当访问 /last2/1.jpg
,uri 被替换为 /test/1.jpg
去匹配新的 location 进行处理。
返回 /Users/zhangpanqin/stduy_app/test/1.jpg
的内容。
redirect
和 permanent
location /redirect2 { rewrite ^/redirect2 http://www.baidu.com redirect; } location /permanent2 { rewrite ^/permanent2 http://www.baidu.com permanent; }
两者匹配成功以后,都会改变浏览器地址栏地址。浏览器根据响应头 Location
跳转对应地址。
两者的区别在于,永久重定向 (permanent
),浏览器会保存记录,当再访问 http://localhost:9088/permanent2
而不会询问 nginx
直接跳转。
临时重定向,浏览器每次都要询问 nginx
须要跳转到哪里。能够关闭 nginx
就知道验证结果了。
- | 说明 |
---|---|
语法 | try_files file … uri; <br/>try_files file … =code ; |
默认 | - |
上下文 | server、location |
以指定顺序检查文件是否存在,并使用第一个找到的文件进行请求处理。若是找不到内容内部转发到最后一个参数 uri
。文件位置为 root
+ file
。
location /try/ { root /usr/local/var/www/data2/data2/; try_files $uri $uri/ @pass2; } location @pass2 { default_type application/json ; return 200 "没到到页面代理的数据" ; }
访问 /try/1.jpg
时,$uri
为 /try/1.jpg
。
root
+ $uri
为 /usr/local/var/www/data2/data2/try/1.jpg
找到返回,没有找到继续匹配返回。都没有匹配内部转发至 @pass2
。
如想验证跳转使用 /try/test
之类的,不要使用后缀名,由于使用后缀名的话,浏览器会返回 content-type
,致使内容与解析不一致,图片出不来。
# 开启 gzip gzip on; # 在响应头中增长,Vary: Accept-Encoding gzip_vary on; # gzip压缩级别1-9,数字越大压缩效果越好,压缩所用时间也就越长,占用CPU越高 gzip_comp_level 6; # 申请内存时大小,若是源文件 9k,超过了 8K,那会申请 16*8K。 gzip_buffers 16 8k; gzip_min_length 2K; gzip_proxied any; gzip_disable "msie6"; gzip_http_version 1.1; # 文本(js、text、css、xml、json)压缩比较好,图片已经进行过压缩,在压缩,效果不是很明显,还浪费 cpu gzip_types text/plain text/css text/xml text/javascript application/javascript application/json application/xml+rss application/rss+xml application/atom+xml image/svg+xml;
gzip 压缩对文本效果比较好,推荐只对文本之类的压缩。
为了减轻服务器压力,节省带宽,能够配置缓存。
memory cache
:它是将资源文件缓存到内存中,缓存有效直接从内存加载。
disk cache
: 它是将资源文件缓存到硬盘中,缓存有效直接从硬盘中加载。
先从 memory cache
找,找不到从 disk cache
找,再找不到,请求网络资源。
缓存分为 协商缓存
和 强缓存
。
协商缓存
每次都要去服务器询问缓存是否过时,没有过时使用本地的缓存。
强缓存
会有缓存过时时间,在有效期内不会去服务端校验缓存,直接使用本地缓存。
如今的 webpack
能够根据文件内容的 hash
生产相似 app.asdfa21342.js
这样的文件。其实就是想使用强缓存,当网站更新,新的页面会解析加载不同的资源,从而下降缓存校验对服务器性能的损耗。
协商缓存有:ETag/if-None-Match
和 Last-Modified/if-Modify-Since
两种。
http 协议规定,当这两种响应头都存在的时候,必须都要知足,才能使用缓存。
ETag/if-None-Match
- | 说明 |
---|---|
语法 | etag on|off; |
默认 | etag on; |
上下文 | http、server、location |
nginx
有个 etag 配置属性,会给每一个静态资源生成 Etag
响应头,值为文件内容 hash
。
当浏览器第一次访问资源的时候,返回的响应头中携带 Etag
。
后续的正常访问(不强制刷新缓存)相同的资源,都会带上请求头 if-None-Match
,值为 Etag
去 nginx
校验是否同样,同样说明缓存没有过时,返回状态码 304
,直接访问浏览器中的缓存,不然从浏览器返回资源,返回状态码 200。
Last-Modified/if-Modify-Since
- | 说明 |
---|---|
语法 | if_modified_since off|exact|before; |
默认 | if_modified_since exact; |
上下文 | http、server、location |
指定如何比较文件的修改时间与请求头 If-Modified-Since 进行比较:
忽略 If-Modified-Since 请求头字段(0.7.34)
彻底匹配
资源的修改时间小于或等于 If-Modified-Since 请求头字段中的时间
浏览器第一次访问一个资源的时候,响应头 Last-Modified
返回,标识文件的最后修改时间。
当浏览器再次正常访问(不强制刷新资源)相同资源,请求头会加上 If-Modified-Since
,该值为以前返回的 Last-Modified
。nginx
收到 If-Modified-Since
后,根据配置 if_modified_since
属性比较资源的最后修改时间(Last-Modified
)和该值If-Modified-Since
进行比较,匹配成功,则命中缓存,返回304,不然返回 资源,状态码为 200,并更新缓存时间。
Expires
是 http1.0
的规范,它的值是一个绝对时间的GMT格式的时间字符串。这个时间表明的该资源的失效时间,若是在该时间以前请求的话,则都是从缓存里面读取的。若是服务端和客户端时区不一致会致使判断不许确。
Cache-Control
是 http1.1
的规范,它是利用该字段 max-age
值进行判断的。该值是一个相对时间,好比 Cache-Control: max-age=3600
表明该资源的有效期是3600秒。除了该字段外,咱们还有以下字段能够设置:
no-cache: 须要进行协商缓存,发送请求到服务器确认是否使用缓存。
**no-store:**禁止使用缓存,每一次都要从新请求数据。
**public:**能够被全部的用户缓存,包括终端用户和 CDN 等中间代理服务器。
**private:**只能被终端用户的浏览器缓存,不容许 CDN 等中继缓存服务器对其缓存。
location ~* \.(css|js|png|jpg|jpeg|gif|gz|svg|mp4|mp3|ogg|ogv|webm|htc|xml|woff)$ { # 关闭访问日志记录 access_log off; # 强缓存,时间为一年,浏览器和 cdn 中间件能够缓存 add_header Cache-Control "max-age=31536000"; }
推荐:值组词