nginx,
nginx,
进程模型
nginx是基于URL等应用层信息的负载均衡,而四层就是基于IP+端口的负载均衡。
nginx是多进程、多路复用的,有一个master进程和n个worker进程,安装nginx后使用ps命令能够发现:
root@bogon:/server/deployment/apache-tomcat-8.5.39/webapps# ps -ef|grep nginx
root 1581 1 0 Apr05 ? 00:00:00 nginx: master process /data/program/nginx/sbin/nginx
nobody 2099 1581 0 00:04 ? 00:00:00 nginx: worker process
master进程充当整个进程组与用户的交互接口,接收外界信号并向各个worker进程发送信号,同时监控worker进程的运行状态。
master不处理网络事件,不负责业务的执行,只通过管理worker进程来实现服务的重启、平滑升级、配置文件实时生效等功能。
worker进程之间是相互独立的。主要处理客户端和服务器间的数据读写操作,进程阻塞点是在像select()、epoll_wait()等这样的I/O多路复用函数调用处,等待发生数据可读/写事件。
worker进程处理请求过程
master进程首先创建socket,bind并且listen在80端口(所以master进程需要root权限);
然后master进程再fork出多个worker进程,每个worker进程都去accept这个socket,当请求来时,使用锁机制,让抢到锁的worker进程去处理这个请求。
惊群处理
多个worker进程等待同一个socket的连接事件,当这个事件发生时,这些进程被同时唤醒,就是惊群。
nginx解决方案: 使用锁机制,让抢到锁的worker进程去处理这个请求,如果操作系统支持原子整型,会使用共享内存实现原子上锁,否则使用文件上锁。
配置文件
安装nginx后,初始配置文件如下:
#user nobody;
worker_processes 1;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
worker_connections 1024;
}
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 / {
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;
}
# 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;
# }
#}
}
配置文件分三段:
main;
events;
http;
main段
用于配置nginx全局指令:
user root root; #配置用户或者组,默认为nobody nobody
#worker_processes 1; #允许生成的进程数,默认为1,一般为CPU核心数或核心数-1
#pid /nginx/pid/nginx.pid; #指定nginx进程运行文件存放地址
error_log log/error.log debug; #指定日志路径,级别。可放入main段,http段,以及server块,常用级别:debug|info|warn|error
event 段
网络连接相关配置:
events {
accept_mutex on; #设置网路连接序列化,防止惊群现象发生,默认为on
multi_accept on; #设置一个进程是否同时接受多个网络连接,默认为off
#use epoll; #事件驱动模型,select|poll|kqueue|epoll|resig|/dev/poll|eventport,默认epoll
worker_connections 1024; #每个worker进程最大处理连接数,根据业务量可调
}
http段
定义web服务器相关配置。可嵌套多个server:
http {
# ssh相关配置
ssl_protocols TLSv1 TLSv1.1 TLSv1.2; #指定密码为openssl支持的格式,Dropping SSLv3, ref: POODLE
ssl_prefer_server_ciphers on; #依赖SSLv3和TLSv1协议的服务器密码将优先于客户端密码
ssl_ciphers RC4:HIGH:!aNULL:!MD5; #密码加密方式
#tcp_nopush on; #使用nagle算法,数据包不会立即传送出去,等到数据包最大时一次性的传输,有助于解决网络堵塞
#tcp_nodelay on; #是否禁用nagle算法,禁用后数据包将立即投递
client_max_body_size 256m; #上传文件限制,默认1mb,如果上传大文件必须修改此配置
sendfile on; #允许sendfile方式传输文件,默认为off,可配置在http块,server块,location块
sendfile_max_chunk 100k; #每个进程每次调用传输数量不能大于设定的值,默认为0,即不设上限
#access_log off; #取消服务日志
# 日志格式,可以根据该格式对日志进行分析
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 /server/logs/nginx-access.log; #访问日志
error_log /server/logs/nginx-error.log; # 错误日志
include /etc/nginx/mime.types; #文件扩展名与文件类型映射表
#default_type application/octet-stream; #默认文件类型,默认为text/plain
keepalive_timeout 65; #连接超时时间,默认为75s,可以在http,server,location块
gzip on; #开启Gzip
gzip_min_length 1k; #大于1K的才压缩
gzip_disable "msie6"; #IE6对Gzip不友好
#压缩文件类型,JavaScript两种写法都写上
gzip_types text/plain application/x-javascript text/css
application/xml text/javascript application/x-httpd-php
image/jpeg image/gif image/png;
gzip_buffers 4 16k; #Gzip buffer,以16k4倍为单位申请缓冲区内存
#gzip_http_version 1.0; #http版本,应为1.1
#gzip_comp_level 2; #压缩级别,1-10,数字越大压缩的越好
#gzip_vary off;# 给CDN和代理服务器使用,针对相同url,可以根据头信息返回压缩和非压缩副本
upstream test {
server 127.0.0.1:8080;
server 192.168.10.121:3333 backup; #热备
}
error_page 404 https://www.baidu.com; #错误页
server {
listen 9090; #监听端口
server_name 127.0.0.1; #主机名称,可以使用域名,例如:www.baidu.com
keepalive_requests 120; #单连接请求上限次数。
access_log /server/logs/www.test.net-access.log;
error_log /server/logs/www.test.net-error.log;
location ~*^.+$ { #请求的url过滤,正则匹配,~为区分大小写,~*为不区分大小写。
deny 127.0.0.1; #拒绝的ip
allow 172.18.5.54; #允许的ip
root html; #定义服务器的默认网站根目录位置
index index.php index.html index.htm; #定义首页索引文件的名称
proxy_pass http://test; #请求转向自定义服务器列表
}
}
}
location配置
location / 通用匹配
location = /uri 精准匹配
location ^~ /uri 正则:前缀匹配
location ~ /uri 正则匹配
规则的优先级:
1. 精准匹配是优先级最高
2. 普通匹配(最长的匹配)
3. 正则匹配
其他配置信息
proxy_next_upstream
语法:
proxy_next_upstream [error | timeout | invalid_header | http_500 | http_502 | http_503 | http_504 |http_404 | off ];
配置块:
http、server、location
默认情况下,上游服务器一旦开始发送响应数据,Nginx反向代理服务器会立刻把应答包转发给客户端。因此,一旦Nginx开始向客户端发送响应包,不允许切换到下一个服务器继续处理。目的是保证客户端只收到来自同一个服务器的应答。
默认值:
proxy_next_upstream error timeout;
以如下配置举例:
upstream tomcat {
server 192.168.47.128:8080;
server 192.168.47.129:8080;
server 192.168.47.130:8080;
}
例如请求在128执行,proxy_next_upstream默认值表示当128服务器转发出现错误或者超时时,会按照负载均衡策略切换到下一台服务器进行处理,例如129。
改为如下则表示当发生超时、错误、500、404时都切换服务器处理:
proxy_next_upstream error timeout http_500 http_404;
proxy_connect_timeout
用于设置nginx与upstream server的连接超时时间,如果无法在指定时间建立连接,就会报错。默认值:
proxy_connect_timeout 60s;
配置块:
http, server, location
proxy_send_timeout
向后端写数据的超时时间,过了指定时间后端还没有收到数据,连接会被关闭
proxy_read_timeout
从后端读取数据的超时时间,过了指定时间没有读取到数据,那么nginx和后端的连接会被关闭,如果一个请求的处理时间比较长,可以把这个值设置得大一些。
请求头处理
当使用nginx做反向代理时,后端获取的请求头信息实际是nginx的信息,如果需要获取原始请求息,需要在location中做些处理:
server {
listen 80;
server_name localhost;
location / {
proxy_redirect off;
proxy_pass_header Server; #指定转发的头部字段
proxy_set_header Host $http_host; #$http_host与$host表示请求的host头,区别在于$http_host会带有端口号(非80/443)
proxy_set_header X-Scheme $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://192.168.47.128:8080;
}
}
proxy_redirect
配置块:
http、server、location
当上游服务器返回的响应是重定向或刷新请求(如HTTP响应码是301或者302)时,proxy_redirect可以重设HTTP头部的location或refresh字段。
如果需要修改从被代理服务器传来的应答头中的"Location"和"Refresh"字段,这时候就可以用proxy_redirect这个指令设置。
假设被代理服务器返回Location字段为:
http://localhost:8000/test/uri/
proxy_redirect http://localhost:8000/test/ http://www.test.com/uri/;
将Location字段重写为:
http://www.test.com/uri/。
或者在代替的字段中不写服务器名:
proxy_redirect http://localhost:8000/test/ /;
这样就达到了代替的效果。
X-real-ip $remote_addr;
可以在web服务器端获得用户的真实ip
X-Forwarded-For $proxy_add_x_forwarded_for;
保存了请求经过流转所经过的服务器地址链。
例如,一个请求经过了两个nginx转发,假设这两台nginx都做了如下设置:
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for
到达第一台nginx时,$proxy_add_x_forwarded_for变量的"X-Forwarded-For"部分是空的,只有$remote_addr,$remote_addr的值是用户的ip,于是赋值后X-Forwarded-For的值就是用户的真实IP地址;
到达第二台nginx时,现在的$proxy_add_x_forwarded_for变量的X-Forwarded-For部分包含的是用户的真实IP,$remote_addr部分的值是上一台nginx的ip地址,于是通过这个赋值以后现在的X-Forwarded-For的值就变成了“用户的真实IP,第一台nginx的IP”,依次形成链条。
负载均衡
upstream模块通过简单的调度算法来实现客户端IP到后端服务器的负载均衡,默认算法为轮询。
轮询
upstream tomcat {
server 192.168.47.128:8080;
server 192.168.47.129:8080;
server 192.168.47.130:8080;
}
weight(权重)
指定轮询几率,weight值和访问概率成正比,用于后端服务器性能不均衡情况。
upstream tomcat {
server 192.168.47.128:8080 weight=2;
server 192.168.47.129:8080 weight=3;
server 192.168.47.130:8080 weight=5;
}
ip_hash
将请求的IP做hash,结果是每个请求都会固定发送到唯一的服务器,可以解决session共享问题。
upstream tomcat {
ip_hash;
server 192.168.47.128:8080 max_fails=2 fail_timeout=60s;
server 192.168.47.129:8080;
server 192.168.47.130:8080 backup;
}
属性配置
max_fails
请求失败的最大次数,当超过最大次数时,返回proxy_next_upstream模块定义的逻辑。
fail_timeout
max_fails次失败后。暂停的时间。
backup
其他全部的非backup机器down或者忙的时候,才会请求backup机器。
动静分离
通过location模块设置,将静态文件直接返回,而不是通过后端服务器处理,大大减少服务器处理请求的次数,例如对js、css、png等文件设置:
location ~ .*\.(js|css|png|svg|ico|jpg)$ {
root /server/deployments/static;
}
缓存配置
浏览器缓存将文件保存在客户端,好的缓存策略可以减少对网络带宽的占用,减小服务器的负担。Nginx通过expires设置缓存,格式:
expires 30s|m|h|d
示例:
location ~ .*.(jpg|jpeg|gif|bmp|png|js|css|ico)$ {
root /server/deployments/static;
expires 1d;
}
表示缓存过期时间为1天。
防盗链
Nginx配置防盗链语法:
valid_referers none | blocked | server_names | string ...;
配置块:
server, location
示例:
location ~ .*.(jpg|jpeg|gif|bmp|png|js|css|ico)$ {
valid_referers none blocked 192.168.47.128 www.test.com;
if ($invalid_referer) {
return 404;
}
root /server/deployments/static;
expires 1d;
}
跨域配置
location中添加如下配置:
add_header 'Access-Control-Allow-Origin' '*'; #允许来自所有的访问地址
add_header 'Access-Control-Allow-Methods' 'GET,PUT,POST,DELETE,OPTIONS'; #支持的请求方式
add_header 'Access-Control-Allow-Header' 'Content-Type,*'; #支持的媒体类型
示例:
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://192.168.47.128: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;
add_header 'Access-Control-Allow-Origin' '*'; #允许来自所有的访问地址
add_header 'Access-Control-Allow-Methods' 'GET,PUT,POST,DELETE,OPTIONS'; #支持的请求方式
add_header 'Access-Control-Allow-Header' 'Content-Type,*'; #支持的媒体类型
}
}
ssh配置
upstream test {
server 192.168.47.128:8080;
}
server {
listen 443 ssl;
server_name www.test.net;
# 服务端认证配置
ssl_certificate /etc/letsencrypt/live/www.test.net/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/www.test.net/privkey.pem;
ssl_client_certificate /root/.ssl/www.test.net-ca.crt; #客户端证书
ssl_verify_client on; #开启客户端认证
access_log /server/logs/www.test.net-access.log;
error_log /server/logs/www.test.net-error.log;
location / {
proxy_redirect off;
proxy_pass_header Server;
proxy_set_header X-Scheme $scheme;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header x-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://test;
}
}
关于证书生成链接。
附:nginx安装
官网下载安装包,解压后首先配置configure:
./configure --prefix=/data/program/nginx
期间会提示安装依赖包,安装:
apt-get install build-essential
apt-get install libpcre3 libpcre3-dev
apt-get install openssl libssl-dev
apt-get install zlib1g-dev
配置好后,make:
make && make install
到nginx安装目录:
cd /data/program/nginx/
启动和停止:
sbin/nginx
sbin/nginx -s stop
指令参数:
root@bogon:/data/program/nginx/sbin# ./nginx -h
nginx version: nginx/1.14.2
Usage: nginx [-?hvVtTq] [-s signal] [-c filename] [-p prefix] [-g directives]
Options:
-?,-h : this help
-v : show version and exit
-V : show version and configure options then exit
-t : test configuration and exit
-T : test configuration, dump it and exit
-q : suppress non-error messages during configuration testing
-s signal : send signal to a master process: stop, quit, reopen, reload
-p prefix : set prefix path (default: /data/program/nginx/)
-c filename : set configuration file (default: conf/nginx.conf)
-g directives : set global directives out of configuration file
访问:
http://192.168.47.128(nginx所在机器IP)
invalid PID number 处理
执行如下命令:
/usr/local/nginx/sbin/nginx -s reload
重新读取配置文件后,再启动nginx启动不起来:
root@iZ2ze0rydhf43s74zkmk2cZ:/server/tar# service nginx status
鈼[0m nginx.service - LSB: starts and stops the nginx web server
Loaded: loaded (/etc/init.d/nginx; bad; vendor preset: enabled)
Active: active (exited) since Tue 2019-03-26 14:47:14 CST; 30min ago
Docs: man:systemd-sysv-generator(8)
Process: 4987 ExecStop=/etc/init.d/nginx stop (code=exited, status=0/SUCCESS)
Process: 5837 ExecReload=/etc/init.d/nginx reload (code=exited, status=0/SUCCESS)
Process: 5020 ExecStart=/etc/init.d/nginx start (code=exited, status=0/SUCCESS)
Mar 26 15:10:58 iZ2ze0rydhf43s74zkmk2cZ nginx[5837]: Reloading nginx ...
Mar 26 15:10:58 iZ2ze0rydhf43s74zkmk2cZ nginx[5837]: nginx: [error] invalid PID number "" in "/var/run/nginx/nginx.pid"
Mar 26 15:10:58 iZ2ze0rydhf43s74zkmk2cZ nginx[5837]: nginx not running
Mar 26 15:10:58 iZ2ze0rydhf43s74zkmk2cZ nginx[5837]: -e .
Mar 26 15:10:58 iZ2ze0rydhf43s74zkmk2cZ nginx[5837]: done
Mar 26 15:10:58 iZ2ze0rydhf43s74zkmk2cZ systemd[1]: Reloaded LSB: starts and stops the nginx web server.
Mar 26 15:11:05 iZ2ze0rydhf43s74zkmk2cZ systemd[1]: Started LSB: starts and stops the nginx web server.
Mar 26 15:14:39 iZ2ze0rydhf43s74zkmk2cZ systemd[1]: Started LSB: starts and stops the nginx web server.
Mar 26 15:15:06 iZ2ze0rydhf43s74zkmk2cZ systemd[1]: Started LSB: starts and stops the nginx web server.
Mar 26 15:17:37 iZ2ze0rydhf43s74zkmk2cZ systemd[1]: Started LSB: starts and stops the nginx web server.
主要报错信息为:
nginx: [error] invalid PID number "" in "/var/run/nginx/nginx.pid"
查看nginx.pid,发现内容为空。解决方法为使用nginx -c重新set配置文件:
[root@localhost nginx] nginx -c /usr/local/nginx/conf/nginx.conf
评论暂时关闭