编译安装
可以自己上nginx官方网站下载安装包,解压之后用下面命令编译安装:
1
2
3
4
|
./configure --prefix='/opt/nginx' --with-http_ssl_module --with-http_gzip_static_module \
--with-http_stub_status_module --with-http_v2_module --with-stream
make && make install
|
安装过程中涉及到相应的依赖环境下载。安装完成之后,使用/opt/nginx/sbin/nginx -v
查看安全情况。
常规配置
Nginx是一个很强大的高性能Web和反向代理服务,它具有很多非常优越的特性。这里介绍下Nginx的常用配置方法。
下面看一段Nginx
的常用配置:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
|
user root root;
worker_processes 5;
error_log /home/xxx/_logs_/nginx_acc_err.log notice;
pid /home/xxx/tmp/nginx_api.pid;
worker_rlimit_nofile 500000;
events {
use epoll;
worker_connections 500000;
}
http {
include /opt/nginx/conf/mime.types;
default_type application/octet-stream;
tcp_nopush on;
keepalive_timeout 30;
tcp_nodelay on;
gzip on;
gzip_min_length 1024;
gzip_buffers 4 8k;
gzip_types text/plain text/css text/javascript application/javascript;
gzip_comp_level 9;
gzip_proxied any;
port_in_redirect off;
access_log off;
rewrite_log off;
client_max_body_size 6m;
client_body_buffer_size 128k;
client_header_buffer_size 4k;
# 公用证书
ssl_certificate /home/xxx/certificate/xxx.new.crt;
ssl_certificate_key /home/xxx/certificate/xxx.nopwd.key;
# -----------------------------
# 维护中...
#server {
# listen 80;
# root /home/xxx/www/;
# error_page 500 502 503 504 = /index.html;
# error_page 403 404 = /index.html;
#}
# -----------------------------
# 负载均衡 [API]
upstream up_user_center_keep_session {
server 10.10.11.31:11122;
server 10.10.11.31:11122 backup;
}
server {
listen 80;
listen 443 ssl;
server_name sss.yoursite.com;
location / {
proxy_pass http://up_user_center_keep_session/;
include _nc_proxy_env.conf;
}
}
# -------------------------------
# 服务器配置片段
include _nc_part_proxy_server.conf;
include _nc_part_apis.conf;
include _nc_part_apis_gm.conf;
}
|
Nginx片段的示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
log_format gm_main2 '[$time_local] $remote_addr $remote_user $request $upstream_addr '
'[$request_time] '
'[$request_length $bytes_sent $body_bytes_sent] ';
upstream up_api_gm_et {
ip_hash;
server 10.10.11.11:11111 weight=1;
server 10.10.11.12:11111 weight=3;
}
server {
listen 80;
listen 443 ssl;
server_name site.yoursite.com;
access_log /home/xxx/_logs_/nginx_acc_gm_et.log gm_main;
ssl_certificate /home/xxx/certificate/xxx.new.crt;
ssl_certificate_key /home/xxx/certificate/xxx.nopwd.key;
location / {
proxy_pass http://up_api_gm_et/;
include _nc_proxy_env.conf;
}
}
|
nginx可以热更新,修改好配置文件之后,热重启:
nginx -t
# 结果显示ok和success没问题,证明修改没有问题。便可重启
nginx -s reload
gzip压缩
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
# 打开gzip压缩
gzip on;
# 不压缩临界值,大于1K的才压缩,一般不用改
gzip_min_length 1k;
# 设置系统获取几个单位的缓存用于存储gzip的压缩结果数据流,这里设置以16k为单位的4倍申请内存
gzip_buffers 4 16k;
# 默认为http 1.1,现在99.99%的浏览器基本上都支持gzip解压了,所有无需设置此项
# gzip_http_version 1.0;
# gzip压缩比,1 最小处理速度最快,9 最大但处理最慢(传输快但比较消耗cpu)
gzip_comp_level 2;
# 要压缩的文件类型,注意"text/html"类型无论是否指定总是会被压缩的
gzip_types text/plain application/x-javascript text/css application/xml
text/javascript application/javascript application/x-httpd-php image/jpeg image/gif image/png;
# on的话会在Header里增加"Vary: Accept-Encoding",给代理服务器用的,有的浏览器支持压缩,
# 有的不支持,所以避免浪费不支持的也压缩,所以根据客户端的HTTP头来判断,是否需要压缩
# 我这里的浏览器肯定支持gzip压缩,所以就不开启此功能了
gzip_vary off;
# IE6对Gzip不怎么友好,不给它Gzip压缩了
gzip_disable "MSIE [1-6]\.";
|
参考阅读:
https://www.404bugs.com/details/1079434655764893696
error_log
Nginx的错误信息是调试Nginx服务的重要手段,属于核心功能模块(ngx_core_module)的参数,该参数的名字为error_log,可以放在Main区块中全局配置,也可以放在不同的虚拟主机中单独记录虚拟主机的错误信息。
1
2
3
4
5
6
7
|
# 关键字 日志文件 错误日志级别
error_log <FILE> <LEVEL>;
# 关键字:其中关键字error_log不能改变
# 日志文件:可以指定任意存放日志的目录
# 错误日志级别:常见的错误日志级别有[debug | info | notice | warn | error | crit | alert | emerg]
# 级别越高记录的信息越少;生产场景一般是 warn | error | crit 这三个级别之一
|
注意:不要配置info等级较低的级别,会带来大量的磁盘I/O消耗。
error_log参数的标签段位置:
main, http, server, location
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
# log_format格式是我们定义好一种日志的格式,并起个名字便于引用。
$binary_remote_addr 客户端请求的IP地址
$remote_addr: 记录客户端的ip地址;$http_x_forwarded_for也是这个意思
$remote_user: 记录客户端用户的名称;
$time_local: 访问时间及时区;
$request: 请求的URL与HTTP协议;
$status: 记录请求状态
$body_bytes_sent: 记录发送给客户端文件主体内容大小;
$http_referer: 用来记录从那个页面链接访问过来的;
$http_user_agent: 记录客户端浏览器的相关信息
$bytes_sent: 客户端发送的字节数
$request_length: 客户端请求的长度
$http_host: 客户端请求的地址,即浏览器中你输入的地址(IP或域名)
$upstream_status: upstream状态
$upstream_addr: 后台upstream的地址,即真正提供服务的主机地址
$request_time: 整个请求的总时间
$upstream_response_time: 请求过程中,upstream响应时间
$request_body: POST数据
|
负载均衡
第一种:加权轮询
按服务器的性能给予不同权重,本例是1:3分配。不加的话,默认权重都是1。
1
2
3
4
|
upstream up_api_gm_et {
server 10.10.11.11:11111 weight=1 fail_timeout=20s;
server 10.10.11.12:11111 weight=3 fail_timeout=20s;
}
|
第二种:ip_hash轮询
给服务器加不加权重都行。默认权重也都是1。
1
2
3
4
5
|
upstream up_api_gm_et {
ip_hash;
server 10.10.11.11:11111 fail_timeout=30s;
server 10.10.11.12:11111 fail_timeout=30s;
}
|
设置代理超时:
proxy_connect_timeout 60s; # 连接超时 默认为60秒
定义用于建立与代理服务器的连接超时。应当注意的是,此超时通常不能超过75秒。
proxy_read_timeout 60s; # 读取超时 默认为60秒
定义了从代理服务器读取响应超时。只是在两个连续的读取操作之间设置超时,而不是为整个响应的传输设置超时时间。如果代理服务器在这段时间内不发送任何东西,连接关闭。
proxy_send_timeout 60s; # 发送超时 默认为60秒
设置发送到代理服务器的请求的超时。只是在两个连续的写操作之间设置超时,而不是为整个请求的传输设置超时时间。如果代理服务器在这段时间内没有收到任何东西,连接关闭。
另外:max_fails和fail_timeout —— 这俩是关联的,如果某台服务器在fail_timeout时间内出现了max_fails次连接失败,那么nginx就会认为那个服务器已经挂掉,从而在 fail_timeout时间内不再去查询它,fail_timeout的默认值是10s,max_fails的默认值是1(这意味着一发生错误就认为服务器挂掉),如果把max_fails设为0则表示把这个检查取消。举个例子:server 192.168.1.11 max_fails=3 fail_timeout=30s; 这表示,如果服务器192.168.1.11在30秒内出现了3次错误,那么就认为这个服务器工作不正常,从而在接下来的30秒内nginx不再去访问这个服务器。
其它参数配置
1
2
3
4
5
6
7
|
upstream up_api_gm_et {
ip_hash;
server 10.10.11.11:11111;
server 10.10.11.12:11111 weight=2; (默认为1,weight越大负载的权重就越大)
server 10.10.11.13:11111 down; (单前的server暂时不参与负载)
server 10.10.11.14:11111 backup; (非backup机器down或者忙的时候,请求backup机器)
}
|
ip_hash只对IP地址的前三段取hash值,然后选择后台服务器处理。所有同样的网段ip/24过来的请求,会分发到同一个后台服务器。
根据我的实验,总结几个结论如下:
- ip_hash条件下后端服务器的配置顺序对分发是有意义的,某个客户端请求的IP会被算出一个服务器的索引,这个索引和upstream中服务器的顺序相关。
- fail_timeout=10s默认值是10s,Nginx通过策略找到后台服务器之后,如果这台服务器彻底失去响应,会自动选择其它后端服务器转发请求。而且在接下来的fail_timeout时间之内,都不会将请求转发给失联的服务器。超过这个时间之后才会再次尝试这台失联服务器。
- 如果后端服务器只是响应慢,默认timeout是60s,那么这段时间请求就卡死了,超时之前不会自动选取下一台服务器处理。建议把
proxy_read_timeout
适当调小尽快让下一台服务器处理请求。
这里有一个参考示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
upstream up_pg_agent_test_backup_api {
ip_hash;
server 127.0.0.1:5111 fail_timeout=20;
server 127.0.0.1:5112 fail_timeout=20;
}
server {
listen 8019;
location / {
#proxy_connect_timeout 30;
proxy_read_timeout 10;
#proxy_send_timeout 30;
proxy_pass http://up_pg_agent_test_backup_api/;
}
}
|
情况一:
如果我们把5112端口阻塞掉,永远不返回任何内容(模拟访问量巨大,一台服务器已经无法准时返回结果了)。再访问8019端口(如果恰好当前IP先被ip_hash匹配到5112端口),大家猜结果会如何?
- 第一次请求被阻塞10s之后直接返回5111对应的值。
- 之后的每一次都能正常返回5111的对应内容,而且这个正常的过程持续20s
- 接下来就开始重复1了。
为什么呢?因为proxy_read_timeout=10
意味着10秒以后nginx会自动完成后台负载均衡服务器的切换,都不用等正在阻塞中的5112。
情况二:
如果5112直接离线了,会如何表现呢?
- 第一次不用阻塞,直接返回5111对应的值。
- 之后的每一次都能正常返回5111的对应内容,而且这个正常的过程持续20s
- 接下来就开始重复1了。
为什么呢?因为nginx第一次肯定也会试图把处理请求转发给5112,可是马上就知道5112已经挂了,他会自动把请求转发下一个负载服务器。
情况三:
如果5111和5112都挂掉了,结果很简单,所有的请求都返回502 Bad Gateway
。
参考文章:
https://www.pianshen.com/article/3042395077/
https://www.cnblogs.com/lc0605/p/10444086.html
限流控制
限流不会提升性能,但使用好限流手段却可保障服务的稳定性、可靠性,使服务更为的健壮。再有限流很难比较好的解决业务逻辑上的问题,为了扛住用户的抢购,还是需要业务逻辑上实现类似排队的算法。
Nginx官方版本限制IP的连接和并发分别有两个模块:
ngx_stream_limit_conn_module
用来限制单位时间内的请求数,即速率限制,采用的漏桶算法 “leaky bucket”
ngx_http_limit_req_module
用来限制同一时间连接数,即并发限制
什么是漏桶算法?
我们假设系统是一个漏桶,当请求到达时,就是往漏桶里“加水”,而当请求被处理掉,就是水从漏桶的底部漏出。水漏出的速度是固定的,当“加水”太快,桶就会溢出,也就是“拒绝请求”。从而使得桶里的水的体积不可能超出桶的容量。主要目的是控制数据注入到网络的速率,平滑网络上的突发流量。漏桶算法提供了一种机制,通过它,突发流量可以被整形以便为网络提供一个稳定的流量。
请求限制
请求限制的功能来自于 ngx_http_limit_req_module
模块。使用它需要首先在 http 配置段中定义限制的参照标准和状态缓存区大小。
看看limit_req_zone
,举个例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
upstream up_pg_agent_test_backup_api {
ip_hash;
server 127.0.0.1:5111 weight=1 fail_timeout=30;
server 127.0.0.1:5112 weight=1 fail_timeout=30;
}
# 定义了一个 limit_req 缓冲区(容器)规则,请求频率限制为每秒 1 个请求(nr/s)
limit_req_zone $binary_remote_addr zone=limit_cd:10m rate=1r/s;
server {
listen 8020;
access_log /home/xxx/_logs_/nginx_agent_backup.log nginx_agent_backup;
location / {
# nodelay 不延迟处理
# burst 是配置超额处理,可简单理解为队列机制
# 上面配置同一个 IP 每秒只能发送一次请求(1r/s),这里配置了缓存3个请求,
# 就意味着同一秒内只能允许 4 个任务响应成功,其它任务请求则失败(503错误)
limit_req zone=limit_req burst=3 nodelay;
proxy_connect_timeout 20;
proxy_read_timeout 20;
proxy_send_timeout 20;
proxy_pass http://up_pg_agent_test_backup_api/;
include _nc_proxy_env.conf;
}
}
|
我把5112设计成阻塞,不执行render,你猜会如何。在客户端执行5此请求,你会发现5个请求都原地打转,直到超时,所有请求到另外一路正常返回结果。但也只是前2个请求返回结果,后三个全部显示503 Service Temporarily Unavailable
。
下面是Nginx错误日志:
并发限制
Nginx 并发限制的功能来自于 ngx_http_limit_conn_module
模块,跟请求配置一样,使用它之前,需要先定义参照标准和状态缓存区。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
# 定义了一个 limit_conn 缓冲区(容器)
limit_conn_zone $binary_remote_addr zone=limitconn:10m;
server {
listen 8021;
location / {
# 每个 IP 只允许一个连接
limit_conn limitconn 1;
# 限制传输速度(如果有N个并发连接,则是 N * limit_rate)
limit_rate 1024k;
proxy_connect_timeout 20;
proxy_read_timeout 20;
proxy_send_timeout 20;
proxy_pass http://up_pg_agent_test_backup_api/;
}
}
|
还有很多参数可以查阅Nginx官方文档:
http://nginx.org/en/docs/http/ngx_http_limit_conn_module.html
http://nginx.org/en/docs/http/ngx_http_limit_req_module.html
(完)