nginx简介
Nginx是一款是由俄罗斯的程序设计师Igor Sysoev所开发高性能的 Web和 反向代理 服务器,也是一个 IMAP/POP3/SMTP 代理服务器。在高连接并发的情况下,Nginx是Apache服务器不错的替代品。
-
nginx的优势
- 高并发高性能
- 可扩展性好,跨平台 - 模块拓展
- 高可靠性 - 宕机概率很小
- 热部署
- 开源许可
- 等等
-
nginx 的最重要的几个使用场景:
- 静态资源服务,通过本地文件系统提供服务;
- 反向代理服务,延伸出包括缓存、负载均衡等;
api接口服务
nginx和node.js 的很多理念类似,HTTP服务器、事件驱动、异步非阻塞等。nginx 擅长于底层服务器端资源的处理(静态资源处理转发、反向代理,负载均衡等),总之目前形式,在服务器上应用非常广泛
nginx架构之工作模式
-
nginx启动后,有一个master进程和多个相互独立的worker进程
-
- 每个
worker进程都有可能处理request连接
- 每个
-
master进程可以监控worker进程的运行状态,当worker进程异常退出,会自动启动新的worker进程
worker进程数,一般会设置成机器cpu核数。因为更多的worker数,只会导致进程相互竞争CPU,从而带来不必要的上下文切换- 使用多进程模式,不仅能提高并发率,而且进程之间相互独立,一个
worker进程挂了不影响其它woker进程的工作 CPU亲和,把CPU内核和nginx的worker进程绑定在一起,让每个worker进程固定在一个CPU上执行,从而减少CPU的切换并提高缓存命中率提高性能
nginx的安装
注意不同的linux的操作系统安装命令不同,以下全部在centos7.x环境运行
安装依赖
yum install -y gcc gcc-c++ autoconf pcre pcre-devel zlib zlib-devel openssl openssl-devel
添加安装源
创建nginx.repo文件
vi /etc/yum.repos.d/nginx.repo
添加如下内容
[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/centos/7/$basearch/
gpgcheck=0
enabled=1
安装nginx
yum install -y nginx
也有其他方式比如安装包直接安装,docker镜像安装...
nginx -v查看版本号nginx -V查看安装nginx配置的参数。查看可执行文件,配置文件,日志文件,第三方模块文件路径nginx -t检查配置是否正确rpm -ql nginx查看nginx安装文件的详细路径
启动/关闭命令
- 启动
systemctl start nginx.service - 重新加载配置
nginx -s reload或systemctl reload nginx.service - 停止
systemctl stop nginx.service或nginx -s stop - 重启
systemctl restart nginx.service或nginx -s reopen - 开启自启
systemctl enabled nginx.service - 关闭开机自启
systemctl disabled nginx.service
nginx模块介绍
nginx的所有功能都是以模块的形式累加形成,模块也非常多。这包括核心模块和功能模块,针对不同的应用场景,并非所有的功能模块都要被用到。模块可参考如下3个网站
nginx处理请求的流程
- 客户端请求
- 读取
http请求的请求行,请求头,请求体 - 根据域名确认使用哪个
server配置 server_rewrite(server内部的重写)- 匹配
location rewrite(location内部的重写)- 访问控制(每个
ip每秒的并发数) - 生成内容(
return, 硬盘, 反向代理) - 响应过滤(
gzip sub_filter) - 打印日志(错误和访问日志)
- 返回给客户端
nginx配置解读
内置变量
$http_host请求的主机名称$requet_uri请求的url地址$request_method请求的http方法$requesthttp的请求行$remote_addr客户端地址$remote_user客户端名称$http_referer$http_user_agent$http_x_forwarded_for转发客户端请求头的ip地址$proxy_add_x_forwarded_for通过(proxy_set_header X_Forwarded_For: $proxy_add_x_forwarded_for配置透传客户端合代理ip)$arg_[参数名称]http请求参数名称$http_[HEADER]http的请求头 如:$http_referer$http_user_agent$send_http_[HEADER]http的响应头 如:$send_http_cookie
核心配置示例
整体上的配置块如下所示
main {
...
http {
upstream { ... }
server {
if() {}
location { ... }
}
}
}
更详细的核心配置如下
cat /etc/nginx查看nginx配置如下
user root; # 用于配置worker进程的用户和用户组(如果指定的用户不存在,则报错)
worker_processes auto; # 配置 worker进程的个数,建议和CPU核数一样
error_log /var/log/nginx/error.log notice; # 配置错误日志存放路径 [日志级别]
pid /var/run/nginx.pid; # 配置master进程的进程号和进程号ID的文件路径,位于全局块
events {
worker_connections 1024; # 每个worker进程允许最大的连接数
}
http {
charset utf-8;
include /etc/nginx/mime.types; # 设定mime类型,类型由mime.types文件定义
default_type application/octet-stream; # 默认的mime类型,如果mime.types文件找不到使用默认的文件类型
# 日志格式(自定义输出内容) 和 日志的级别
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 /var/log/nginx/access.log main; # 访问日志路径
# 下方3个建议同时开启,静态资源服务器应用起到优化的作用
sendfile on; # 提高处理静态资源的性能,系统读取的文件数据直接发送给网络不再经过ng。如果配置反向代理不起作用
#tcp_nopush on; # 减少网络报文段的数量,可以在达到一定的数据后一起发送。仅在使用sendfile的时候使用
tcp_nodelay on; # 在keep-alive开启的情况生效,来提高网络包传输的'实时性'和tcp_nopush的作用相反
keepalive_timeout 65; # 配置 长连接超时时间
#keepalive_requests 120; # 配置 一个长连接 可以处理的请求的个数,超过这个个数就会断开该连接
#gzip on; # 是否开启gzip压缩
#gizp_comp_level 6; # 压缩级别
#gzip_min_length 1k; # 内容超过1k才参与gzip
#gzip_http_version 1.1; # 启用gzip压缩的最小http版本
#gzip_static on; # 如果是提前`gzip`过的需要启用此配置
#gzip_types text/css appliction/javascript text/html; # 压缩的文件类型
# 其它配置文件
include /etc/nginx/conf.d/*.conf;
server {
listen 80; # 服务监听端口
server_name test.222.com test1.222.com; # 服务使用的域名可以是ip/域名/localhost,可配置多个
#access_log /var/log/nginx/host.access.log main; # 单独 为该服务定义一个日志路径,而不是使用全局的
#ssl_certificate /root/nginx/ssl/test.222.com.pem; # 证书文件地址 https需要
#ssl_certificate_key /root/nginx/ssl/test.222.com.key; # 私钥文件地址 https需要
# 定义访问改服务URI的匹配规则
location / {
root /usr/share/nginx/html; # 根目录
index index.html index.htm; # 默认访问文件
}
#error_page 404 /404.html; # 404页面
error_page 500 502 503 504 /50x.html; # 状态码500 502 503 504重定向到/50x.html
# 精确匹配
location = /50x.html {
root /usr/share/nginx/html; # 根目录
}
}
}
上述配置日志格式log_format是含有访问ip,访问用户,时间,请求行,请求响应状态码,访问referer,访问客户端ua,转发的ip
执行/var/log/nginx/access.log可以实时在控制台查看日志,如下
上述是一个最简单的静态资源服务的nginx配置。当你访问test.222.com或者test1.222.com(前提是这两个域名已经备案并添加了解析)时,nginx就会访问匹配到上述配置的server,在server内部会根据访问路径命中location。上述只配置了/前缀命中所有路径,然后根据路径会访问/usr/share/nginx/html目录下的文件
server配置块
server 是配置服务的,可以理解成针对域名形式的路由匹配。
根据配置的server_name匹配优先级顺序如下所示
- 精准匹配
*在前*在后- 正则匹配
default_server
即优先级如下:
test.222.com > *.222.com > test.222.* > ~(\w+)\.test\.222\.com$ > default.conf文件的配置
location匹配规则
location仅匹配请求路径,忽略请求参数- 前缀字符串
- 常规(前缀)
=精准^~忽略正则的前缀匹配
- 正则匹配
~大小写敏感的正则匹配~*大小写不敏感的正则匹配
匹配的优先级顺序如图
=优先级最高;一旦成功不在查找其它项^~一旦匹配成功;不在查找其它项- 正则表达式的优先级次之,如果多个
location的正则匹配,则使用正则表达式最长的那个 - 常规字符串匹配类型按前缀匹配
location ~ /Test/$ {
return 200 "匹配到的第一个正则";
}
location ~* /Test/(\w+)$ {
return 200 "匹配到的最长的正则";
}
location ^~ /Test/ {
return 200 "忽略后续的正则";
}
location /Test/a {
return 200 "最长的前缀匹配";
}
location /Test {
return 200 "前缀匹配";
}
location = /Test {
return 200 "精确匹配"
}
访问下边4个地址分别得到的请求结果
/Test -> 精确匹配
/Test/ -> 忽略后续的正则
/Test/a -> 匹配到的最长的正则
/test/a -> 匹配到的最长的正则
rewrite使用
可以实现url的重写和重定向
rewrite 正则 replacement [flag]
作用域server/http
- 请求的地址如果匹配到了正则,会被后边的
replacement替换,然后通过[flag]标识符决定后一步的处理行为
示例
rewrite ^(.*)$ https://$host$1 permanent; # 可以让http重定向到https
使用场景
URL页面跳转http -> https,/a-> /b- 兼容旧版本
SEO优化(伪静态)/:id.html => /:id- 维护提示
[flag]标识符列举
last返回200 地址栏不发生变化break返回200 地址栏不发生变化redirect临时重定向; 返回302,地址栏发生变化permanent永久重定向; 返回301,地址栏发生变化
last和break的区别
- 当
rewrite规则在location{}外,break和last作用一样,遇到break或last后,其后续的rewrite/return语句不再执行。但后续有location{}的话,还会近一步执行location{}里面的语句,当然前提是请求必须要匹配该location - 当
rewrite规则在location{}里,遇到break后,本location{}与其他location{}的所有rewrite/return规则都不再执行。 - 当
rewrite规则在location{}里,遇到last后,本location{}里后续rewrite/return规则不执行,但重写后的url再次从头开始执行所有规则,哪个匹配执行哪个。
前端应用场景
监控nginx状态
stub_status on/off;
作用域范围server/location
配置示例:
location /status {
stub_status on;
}
访问该路径会看到nginx当前的处理状态
Active connections当前所有处于打开状态的连接数accepts总处理的连接数handled总成功创建握手数requests总处理的请求数Reading正在读取客户端的连接数Writing正在响应数据到客户端的数量Waiting正在等待下一次请求的驻留连接数
请求限制
需要先安装yum install -y httpd-tools
模拟请求ab -n 40 -c 20 http://127.0.0.1
-n总共请求的次数-c并发的请求数,每秒请求的数量
请求连接的限制
limit_conn_zone $binary_remote_addr zone=conn_zone:10m;
作用域范围http;定义共享区域大小
limit_conn conn_zone 1; # 指定限制域,请求连接每秒限制1个
limit_conn_status 500; # 限制拦截的状态返回500
limit_conn_log_level warn; # 失败的日志级别
limit_rate 50; # 每秒服务器只能给客户端50字节的数据
作用域范围http/server/location
请求数限制
limit_req_zone $binary_remote_addr zone=req_zone:10m rate=1r/s;
作用域范围http;定义共享域大小,每秒一个ip只能请求1次
limit_req zone=req_zone burst=3;
burst可以暂存的最大请求数;比如某一个客户端同时发送5个请求,那么这一秒处理1个,暂存3个,失败一个。暂存3个会在将来有序被处理
访问控制
- 基于
IP的访问控制-http_access_module - 基于用户登录信息的访问控制
-http_auth_basic_module
location = /admin.html {
deny ip;
allow all;
}
作用域范围http/server/location
设置缓存
注意缓存仅仅设置静态资源,不要设置动态资源
expires 1h; # 设置缓存时间
add_header Cache-Control no-cache / no-store / public / private; # 设置缓存策略 no-store不缓存,no-cache协商缓存 , public可以被任何对象缓存,private只能针对个人用户不能被代理服务器缓存
支持跨域
当服务端不支持跨域并且服务端也是经过nginx代理,可以在nginx配置cros跨域的支持,如下
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE,OPTIONS;
add_header Access-Control-Allow-Headers token,xxx;
add_header Access-Control-Allow-Credentials 'true';
add_header Access-Control-Max-Age 6h;
if ($request_method = 'OPTIONS') {
return 204;
}
可以配置http/server/location块内
防盗链
如果你的静态资源不希望被别的的站点访问,可以设置防盗链,仅仅只支持自己的站点访问,可以配置如下
location ~* \.(gif|jpg|png)$ {
valid_referers none blocked 域名/ip; # 没有refer 具体域名/ip可以访问
if ($invalid_referer) { # 上述配置后会得到一个内置变量$invalid_referer,该变量false直接返回403
return 403; # 无效的referer返回403状态
}
}
curl -e "ip" url模拟加referer访问具体url
正向代理
对于访问目标来说,代理的是客户端。对于公司局域网内往往会有一个代理来访问外网以进行局域网内网络访问控制,还有vpn,Charles等都是正向代理的应用。nginx配置正向代理如下:
resolver 114.114.114.114; # DNS解析
location {
proxy_pass http://$http_host$http_rui #
}
反向代理
反向代理,其实对客户端无感知的;因为客户端不需要任何配置就可以访问,只需要将请求发送到反向代理服务器,由反向代理服务器去选择目标服务器获取数据后,在返回给客户端。暴露的是代理服务器地址,隐藏了真实服务器IP地址。
- 保护了真实的
web服务器,web服务器对外不可见 - 节约了有限的
IP地址资源- 在所有的服务器之间使用私有地址(局域网内的地址)访问,不分配真正的外网的
ip
- 在所有的服务器之间使用私有地址(局域网内的地址)访问,不分配真正的外网的
- 减少
web服务器压力,提高响应速度- 可以适当在代理服务缓存结果
- 跨域
- 请求的统一控制(权限、过滤规则)
- 等等
location / {
proxy_pass http://127.0.0.1:3000; # 真实的服务
index index.html index.htm;
proxy_pass http://xxxxx.com;
proxy_set_header Host $http_host; # 向后传递host请求头
proxy_set_header X-Real_IP $remote_addr; # 向后传递前一个客户端请求的ip地址
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # 层层传递客户端和代理服务器ip
proxy_connect_timeout 90; # 连接超时时间
proxy_send_timeout 90; # 连接成功后等候服务器响应时间
proxy_read_timeout 90; # 服务器数据回传时间就是在规定时间之内服务器必须传完所有的数据
proxy_buffer_size 4k;
proxy_buffers 4 32k;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 64k;
...
}
注意事项
proxy_pass后的url最后加上/就是绝对路径,localtion中匹配的路径部分不走代理,也就是会被替换掉。
location /api/ {
proxy_pass http:/test.222.com/;
}
访问 http://xxxx/api/user -> http:/test.222.com/user
proxy_pass后的url最后如果没有/就是相对路径,location中匹配的路径会走代理也就是会保留location匹配的路径
location /api {
proxy_pass http:/test.222.com;
}
访问 http://xxxx/api/user -> http:/test.222.com/api/user
负载均衡
- 服务器的处理能力,存储空间不足,而扩容永远也满足不了实际的问题
- 集群可以解决高并发,流量过高导致服务器压力大的问题
upstream upName {
server xxx1.com;
server xxx2.com;
server xxx3.com;
}
location / {
proxy_pass http://upName;
}
分配策略
- 轮巡
- 权重轮巡
upstream upName {
server xxx1.com weight=1;
server xxx2.com weight=2;
server xxx3.com weight=3;
}
ip_hash相同的ip始终命中固定服务器
upstream upName {
ip_hash;
server xxx1.com;
server xxx2.com;
server xxx3.com;
}
least_conn哪个服务的连接数最小命中哪一个url_hash固定的url不变命中的服务器也会固定。需要安装第三方模块才可以使用
upstream upName {
url_hash;
...
}
fair按后端的响应时间划分,越快的服务被分配。需要安装第三方模块才可以使用
根据服务器的运行状态
upstream upName1 {
server xxx.com down/backup/max_conns/max_fair=3 max_fair_timeout=10s/
}
down服务器挂了,不参与分配backup备份服务,其它服务挂了才会使用该服务max_fair=3 max_fair_timeout=10s服务响应失败3次休眠10s,过了这个时间段恢复正常max_conns服务链接最大数
结语
以上介绍了nginx的知识点以及在前端的应用场景。运用到实际项目的生产环境还需针对实际问题做不同的nginx配置。ps:虽然在稍微大一点的公司nginx操作不属于前端职责,但我们也需要储存nginx知识,以备不时之需~