从零开始搭建后台服务 - Nginx(02)
上一章主要对Nginx进行了学习和搭建,并以一个开源面板软件为背景展开配置探讨从零开始搭建后台服务 - Nginx(01),本章主要整合配置,实践Nginx同步到生产环境。
Nginx操作命令
Nginx 的命令在控制台中输入 nginx -h
就可以看到完整的命令,这里列举几个常用的命令:
yum install ‐y nginx #安装
nginx -v ##版本,我这边当前版本是nginx/1.20.1
nginx -s reload # 向主进程发送信号,重新加载配置文件,热重启
nginx -s reopen # 重启
Nginx nginx -s stop # 快速关闭
nginx -s quit # 等待工作进程处理完成后关闭
nginx -T # 查看当前 Nginx 最终的配置
nginx -t -c <配置路径> # 检查配置是否有问题,如果已经在配置目录,则不需要-c
systemctl
是 Linux 系统应用管理工具 systemd
的主命令,用于管理系统,我们也可以用它来对 Nginx 进行管理,相关命令如下:
systemctl start nginx # 启动
systemctl stop nginx # 停止
systemctl restart nginx # 重启
systemctl reload nginx # 重新加载,用于修改配置后
systemctl enable nginx # 设置开机启动
systemctl disable nginx # 关闭开机启动
systemctl status nginx # 查看运行状态
Nginx目录结构
安装后主要就是关注配置目录/etc/nginx
,默认日志目录/var/log/nginx
和/usr/share/nginx/logs
。
查找目录执行一下命令cd / | find -name 'access.log'
。
这两个目录可以动态修改路径,方便起见我这准备配置目录结构不变,方便查找,日志目录单独存放。
Nginx入口配置
官方默认配置nginx.conf文件如下,
user nginx; # 运行用户,默认即是nginx,可以不进行设置
worker_processes auto; # Nginx 进程数,一般设置为和 CPU 核数一样
error_log /var/log/nginx/error.log; # Nginx 的错误日志存放目录
pid /run/nginx.pid; # Nginx 服务启动时的 pid 存放位置
# Load dynamic modules. See /usr/share/doc/nginx/README.dynamic.
include /usr/share/nginx/modules/*.conf;
events {
worker_connections 1024; # 每个进程允许最大并发数
}
http {
# 设置日志模式
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; # Nginx访问日志存放位置
sendfile on;# 开启高效传输模式
tcp_nopush on;# 减少网络报文段的数量
tcp_nodelay on;
keepalive_timeout 65;# 保持连接的时间,也叫超时时间,单位秒(非常重要)
types_hash_max_size 4096;
include /etc/nginx/mime.types; # 文件扩展名与类型映射表
default_type application/octet-stream; # 默认文件类型
# Load modular configuration files from the /etc/nginx/conf.d directory.
# See http://nginx.org/en/docs/ngx_core_module.html#include
# for more information.
include /etc/nginx/conf.d/*.conf; # 加载子配置项
server {##这个节点非常重要
listen 80; # 配置ipv4监听的端口
listen [::]:80; # 配置ipv6监听的端口
server_name _; # 配置的域名
root /usr/share/nginx/html;
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
error_page 404 /404.html; # 默认404对应的访问页面
location = /404.html {
}
error_page 500 502 503 504 /50x.html; # 默认50x对应的访问页面
location = /50x.html {
}
}
}
官方入口配置大致就这么多,上面大意我用中文注释了。但是这样的配置很显然离正常上线还有一定距离,接下来主要来介绍Nginx实际投产中肯定会用到的功能以及配置调优。
Nginx配置结构解析
main
http {
upstream { … }
split_clients {…}
map {…}
geo {…}
server {
if () {…}
location {
limit_except {…}
}
location {
location {
}
}
}
server {
}
}
以上是Nginx的常用配置,这个配置文件中包含了多个指令块,有些指令块还是重复的,那么遵循的规则是怎样的?接下来会一一剖析。
server {
listen 8080;
root /home/geek/nginx/html;
access_log logs/geek.access.log main;
location /test {
root /home/geek/nginx/test;
access_log logs/access.test.log main;
}
location /dlib {
alias dlib/;
}
location / {
}
例如上面的配置文件,这里面在 server 块和 location 块中都配置了 root 指令,Nginx 的继承规则如下:
- 子配置不存在时,直接使用父配置块的指令
- 子配置存在时,覆盖父配置块
server {
listen [::]:80 ;
listen 80 ;
server_name www.okpubg.com;
}
server {
listen [::]:80 ;
listen 80 ;
server_name *.okpubg.com;
}
server {
listen [::]:80 ;
listen 80 ;
server_name *.okpubg*;
}
server {
listen [::]:80 ;
listen 80 ;
server_name ~^(www\.)?(.+)$;
}
以上配置了多条Server配置,在做匹配时是有先后顺序关系:
- 精确匹配(与顺序无关)
- 在前的泛域名(与顺序无关)
- 在后的泛域名(与顺序无关)
- 按文件中的顺序匹配正则表达式域名
- default server
- 第 1 个
- listen 指定 default
map $args $foo {
default 0;
debug 1;
}
以上是map指令,主要作用是创建自定义变量,通过使用 nginx 的内置变量,去匹配某些特定规则,如果匹配成功则设置某个值给自定义变量,例如上述$args是nginx内置变量,就是获取的请求 url 的参数。如果参数匹配到debug,那么foo的参数被设置为1,否则就是自定义的0.
一个正则表达式如果以 "~" 开头,表示这个正则表达式对大小写敏感。以 “~*”开头,表示这个正则表达式对大小写不敏感
Nginx常用功能和配置调优
根据以往经验,正式投产时服务器一定会面临诸多问题,以下会用最终配置视角来配置Nginx,可以抄作业,但是在抄作业前还是需要了解我为什么要这么做,以及我做了何种测试,如何测试,在文章最后会附上我这边的配置。
问题一:如何支持Https协议
这基本上是最常见的需求。做法很简单,拿到申请到的https秘钥文件xxx.key和xxx.crt证书,上传到服务器目录,再配置下,以下是我这边配置方案:
Https协议证书是有过期时间的,因此在签名快要到期的时候申请SSL证书,如何申请,详细如下:
从零开始搭建后台服务(IAA业务)- 装机篇
问题二:如何支持反向代理
这个需求也很常规,几乎所有涉及到的服务,都会通过Nginx进行反向代理,如代理到本机上、代理到另外一台局域网服务器上,关键字是proxy_pass
,我的配置示例如下:
问题三:如何负载均衡
负载均衡主要是在http节点内,一个单独的配置项,可以配置多个ip+端口,但是负载均衡Nginx是有三种不同的负载算法,默认为轮询,就是轮流来,以下是几种分配方式:
- 轮询,默认方式,每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务挂了,能自动剔除;
- weight,权重分配,指定轮询几率,权重越高,在被访问的概率越大,用于后端服务器性能不均的情况;
- ip_hash,每个请求按访问 IP 的 hash 结果分配,这样每个访客固定访问一个后端服务器,可以解决动态网页 session 共享问题。负载均衡每次请求都会重新定位到服务器集群中的某一个,那么已经登录某一个服务器的用户再重新定位到另一个服务器,其登录信息将会丢失,这样显然是不妥的;
- fair(第三方),按后端服务器的响应时间分配,响应时间短的优先分配,依赖第三方插件 nginx-upstream-fair,需要先安装;
问题四:如何支持二级/多级域名
设置二级或多级域名之前,你需要在DNS服务器配置好二级域名,然后在域名解析中配置好我们的入口流量IP地址,然后我们在 Nginx 上配置一下虚拟主机的访问监听,就可以拿到从这个二级域名过来的请求了
如果想所有二级域名都到一个业务上,那么加上通配符
server_name *.okpubg.com
,多级域名也需要同样的步骤,即:申请域名->DNS服务器配置该域名解析IP->新建一个Server节点server_name
加上对应域名;
问题五:如何解决跨域问题
跨域问题本质上是浏览器同源策略的限制,比如a.cn的js不能访问b.cn的js因为他们不在同一个域下,同域解释就是域名相同,端口相同,协议相同,可以通过配置header偷的方式解决,如下所示:
location / {
# 允许跨域的请求,可以自定义变量$http_origin,*表示所有
add_header 'Access-Control-Allow-Origin' *;
# 允许携带cookie请求
add_header 'Access-Control-Allow-Credentials' 'true';
# 允许跨域请求的方法:GET,POST,OPTIONS,PUT
add_header 'Access-Control-Allow-Methods' 'GET,POST,OPTIONS,PUT';
# 允许请求时携带的头部信息,*表示所有
add_header 'Access-Control-Allow-Headers' *;
# 允许发送按段获取资源的请求
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
# 一定要有!!!否则Post请求无法进行跨域!
# 在发送Post跨域请求前,会以Options方式发送预检请求,服务器接受时才会正式请求
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain; charset=utf-8';
add_header 'Content-Length' 0;
# 对于Options方式的请求返回204,表示接受跨域请求
return 204;
}
}
问题六:如何保证频繁改动配置时不影响已有配置
配置文件改动是无法避免的事情,因为开发过程中随着业务的增大,势必对应的服务也会越来越多。我的解决方式是解耦配置项,一个业务大单元占用一个域名,一个域名作为一个单独的配置文件对待,而业务下细分的模块为location维度,随着开发的结束location也会在该文件中结束,直接形成生产环境,这样就避免频繁改动的问题。具体到细节如下图所示。
问题七:如何做到动静分离
首先要搞清楚动静分离是什么,比如当浏览器输入www.taobao.com
访问淘宝首页时,打开开发者调试工具可以很明显的看到,首页加载会出现100+
的请求数,而正常项目开发时,静态资源一般会放入到resources/static/
目录下,我们不希望请求资源的时候使用业务服务器,而是静态资源比如CDN,那么此时只需要在一个目录下新建/www/nginx/project/resources/static
,里面存放各资源,配置路径的时候一下配置:
location ~ .*\.(html|htm|gif|jpg|jpeg|bmp|png|ico|txt|js|css){
root /www/nginx/project/resources/static;
expires 7d;
}
也可以将静态资源上传到CDN服务器中,然后location
中配置一个新的upstream
指向
问题八:你性能调优都做了什么
主要在于配置字段的调优研究,此处参考了一些成熟的案例,结合自己的经验得出的结果,调优点如下:
root节点
worker_processes auto
这个字段为核心字段,默认值是1,他表明nginx工作进程数,此处最好的设定应该是>cpu的核心数,但是考虑到集群的通用性,不写死为固定数值,而是等于cpu的核心数,8核即8个工作线程。要注意的是: max connections = worker_processes * worker_connections。
worker_rlimit_nofile 25000
配置这个字段表明每个worker_processes最多打开多少个文件,最好是大于worker_connections。
events节点
use epoll
配置使用epoll模式,将大幅提高连接数,并且不活跃的连接数也不影响实际活跃的连接数,据称最少提升10000个连接数
worker_connections 24000
默认值是1024,这个值表明一个工作进程最多承载24000个连接,但是需要注意这里包括了client连接和代理服务器的连接数,且应该小于worker_rlimit_nofile
的值
accept_mutex on
配置这个节点主要避免发生惊群事件,即有一个连接过来时,工作进程陆续的接收连接,而不是所有进程被激活去抢连接
multi_accept on
启用多路复用,即收到一个连接通知时,接收尽可能多的连接
accept_mutex_delay 150ms
这个是配合multi_accept on使用的,本质是进程间的互斥锁使用时间,比如一个持有mutex锁的worker进程接受并处理请求,其他worker进程等待,过了等待时间下一个worker进程便取得mutex锁,处理请求
http节点
etag off
默认是开启,浏览器会发送页面的Etag值,让服务器进行比较,服务器如果发现eTag值没变,则返回304,浏览器则从缓存中获取页面,如果不相等,则重新获取页面,当集群环境下这个会出现不匹配的状况
server_tokens off;
默认开启,配置隐藏Nginx的版本信息,提高安全性
charset utf-8;
设置字符编码为UTF-8
absolute_redirect off;
默认是开启,302重定向后不会带端口,响应头Location变成了相对路径
ignore_invalid_headers off;
默认为true,配置off后,head头如果有非法字符,直接返回400(Bad Request)错误
keepalive_timeout 30s;
默认数值是75秒,这是很重要的一个数值,常用于keepalive进行多路复用时,能较大成都提升性能,数值高了影响服务端性能,低了无效果,折中取了中间值30s
keepalive_requests 500;
默认数值自1.19.10后改为100,keepalive被复用时一个请求能最多被执行500次,超出的部分重新再连,表现为再次进行三次握手的握手环节有时间
tcp_nopush on;
默认不开启,配置这个数值socket连接时不做发送操作,增大吞吐量
tcp_nodelay on;
默认不开启,配置这个数值,keepalive时启用该选项,增大吞吐量
sendfile on;
默认不开启,配置用于加速文件传输时使用cp命令取代传统意义的读写
open_file_cache max=300 inactive=15s;
open_file_cache_valid 30s;
open_file_cache_min_uses 1;
open_file_cache_errors on;
open_log_file_cache max=1000 inactive=20s valid=1m min_uses=2;
上述字段主要配合sendfile使用,表示缓存文件元数据(文件大小、修改时间等等)个数300个,如果15秒内没有被用户访问一次则抛弃掉该缓存,30秒检查一次,这个配置主要是作为缓存文件是提高性能
types_hash_max_size 1024;
server_names_hash_bucket_size 128;
以上是对服务器hash表设定初始容量,程序初始化时全局使用
gzip on;
传输过程中开启gzip来压缩response内容
gzip_static on;
如果目录下有同名的.gz文件,不需要额外压缩操作,增加性能
gzip_http_version 1.1;
压缩http协议的版本,1.1版本,如果是ab测试注意修改为1.0版本
gzip_comp_level 5;
数值是1-9,取5正好是CPU和大小的折中,一般可以压缩率能到75%
gzip_proxied any;
任何情况下都启用压缩
gzip_vary on;
往头信息中添加压缩标识
gzip_buffers 4 16k;
基础参数,缓存使用的大小
gzip_min_length 1k;
1k以内大小的不做gzip
gzip_disable msie6;
ie6不做gzip
gzip是比较重要的优化手段,压缩率取了个折中的数值,使压缩率和时间取了个折中,压缩率一般有60%以上
send_timeout 15;
默认值60,传输响应给客户端的超时时间,如果客户端在这段时间内没有收到任何消息,则连接关闭
client_header_timeout 15;
默认值60s,表示如果60s内没有收到完整的http request header,则为超时,如果客户端超时,Nginx 返回 HTTP 408
client_body_timeout 15;
默认值60s,表示如果连续的60s内没有收到客户端的1个字节,则表示超时
如果客户端超时,Nginx 返回 HTTP 408
client_body_buffer_size 32k;
分配给请求数据的32k大小,如果超出则数据先存储到临时文件中
client_body_temp_path client_body_temp 1 2;
超出大小时存放的临时目录,比如临时文件是:client_body_temp/7/000001234
client_max_body_size 256m;
默认值1m,上传文件时文件最大大小,超出大小则报413错误
client_header_buffer_size 4k;
默认值1k,如果(请求行+请求头)的大小如果没超过4k,放行请求,如果超过使用large_client_header_buffers字段
large_client_header_buffers 4 64k;
默认值4 8k,表示请求行(request line)的大小不能超过64k,否则返回414错误,请求头(request header)中的每一个头部字段的大小不能超过64k,否则返回400错误,(请求行+请求头)的大小不能超过256k(4 * 64k)
reset_timedout_connection on;
默认值false,表示当一个客户端连接超时,其相关的信息可能仍保留在内存中。启用该指令后,连接超时后将清除所有与内存的关联
以下是fastcgi的配置,cgi粗浅点理解就是一套协议,nginx无法执行外部程序,通过cgi协议就能访问外部程序
fastcgi_connect_timeout 300;
连接超时时间
fastcgi_send_timeout 300;
发送超时时间
fastcgi_read_timeout 300;
读取超时时间
fastcgi_buffer_size 64k;
buffer大小
fastcgi_buffers 4 64k;
buffer容器大小
fastcgi_busy_buffers_size 128k;
buffer繁忙时大小
fastcgi_temp_file_write_size 128k;
写入时最大大小
以下是https的配置,如果https作为主要是服务那么keepalive可以较高,目前这个数值统一为30秒
ssl_protocols TLSv1.3 TLSv1.2; # TLSv1 TLSv1.1
支持https协议
ssl_prefer_server_ciphers on;
这个配置开启意思为由服务端决定哪种加密算法
ssl_early_data on;
指令开启 0-RTT的支持
ssl_ecdh_curve X25519:secp384r1:P-256;
配置服务器使用的密码套件和椭圆曲线,具体什么用要熟悉ssl算法流程才能清楚
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
加密协议与套件
ssl_session_cache shared:SSL:10m;
1 MB能存4000个session,所以这种设定可以存储40000
ssl_session_timeout 10m;
开启SSL会话功能后,设置客户端能够反复使用存储在缓存中的会话参数时间
ssl_session_tickets on;
这一项存疑,有文章说开启这个会带来问题。功能是开启服务器会对它的所有会话数据(状态)并进行加密,再以票证的方式发回客户端。在接下来的连接中,客户端将票证提交回服务器,由服务器检查票证的完整性,解密其内容,再使用其中的信息恢复
线上环境调优后的配置
/etc/nginx/nginx.conf
#nginx 启动用户,设置一个没有多少特权的用户运行
user nginx;
#nginx 进程数
worker_processes auto;
#nginx 开启利用多核 CPU
worker_cpu_affinity auto;
#nginx 最多打开文件数
worker_rlimit_nofile 25000;
events {
#支持大量连接和非活动连接
use epoll;
#避免发生惊群现象
accept_mutex on;
#启用多路复用
multi_accept on;
#2个进程抢互斥锁的最少延迟时间
accept_mutex_delay 150ms;
#单个后台 worker process 进程的最大并发链接数
worker_connections 24000;
}
http {
include conf.d/http.conf;
}
/etc/nginx/conf.d/http.conf
# 基础配置
etag off;
charset utf-8;
charset_types
text/css
text/plain
text/vnd.wap.wml
text/javascript
text/markdown
text/calendar
text/x-component
text/vcard
text/cache-manifest
text/vtt
application/json
application/manifest+json;
include mime.types;
default_type application/octet-stream;
server_tokens off;
absolute_redirect off;
ignore_invalid_headers off;
# 服务器配置
types_hash_max_size 1024;
server_names_hash_bucket_size 128;
# 性能配置
sendfile on;
tcp_nopush on;
tcp_nodelay on;
# 打开文件配置
open_file_cache max=300 inactive=15s;
open_file_cache_valid 30s;
open_file_cache_min_uses 1;
open_file_cache_errors on;
open_log_file_cache max=1000 inactive=20s valid=1m min_uses=2;
# 存活配置
keepalive_timeout 30;
keepalive_requests 500;
# 客户端 IP 地址
# real_ip_header X-Forwarded-For;
# 日志配置
include conf.d/http.d/log_format.conf;
# 客户端配置
include conf.d/http.d/client.conf;
# 代理配置
include conf.d/http.d/proxy.conf;
# Gzip配置
include conf.d/http.d/gzip.conf;
# Brotli配置
#include conf.d/http.d/brotli.conf;
# SSL配置
include conf.d/http.d/ssl.conf;
# fastcgi配置
include conf.d/http.d/fastcgi.conf;
# 主机配置
include conf.d/vhost.d/*.conf;
/etc/nginx/conf.d/http.d/client.conf
# 客户端配置
send_timeout 15;
client_header_timeout 15;
client_body_timeout 15;
client_body_buffer_size 32k;
client_max_body_size 256m;
client_header_buffer_size 4k;
reset_timedout_connection on;
large_client_header_buffers 4 64k;
client_body_temp_path client_body_temp 1 2;
/etc/nginx/conf.d/http.d/gzip.conf
# FastCGI相关参数是为了改善网站的性能:减少资源占用,提高访问速度。
gzip on;
gzip_static on;
gzip_http_version 1.1;
gzip_comp_level 5;
gzip_proxied any;
gzip_vary on;
gzip_buffers 4 16k;
gzip_min_length 512;
gzip_disable msie6;
gzip_types
text/plain
text/css
text/x-script
text/x-component
text/x-java-source
application/javascript
application/x-javascript
text/javascript
text/js
image/x-icon
image/x-win-bitmap
image/vnd.microsoft.icon
application/x-perl
application/x-httpd-cgi
text/xml
application/xml
application/atom+xml
application/rss+xml
application/json
multipart/bag
multipart/mixed
application/xhtml+xml
font/eot
font/ttf
font/otf
font/x-woff
image/svg+xml
application/vnd.ms-fontobject
application/x-font-opentype
application/x-font-truetype
application/x-font-ttf
application/ttf
application/x-ttf
application/otf
application/x-otf
application/truetype
application/opentype
application/x-opentype
application/woff
application/eot
application/font
application/font-woff woff
application/font-sfnt
;
/etc/nginx/conf.d/http.d/fastcgi.conf
# FastCGI相关参数是为了改善网站的性能:减少资源占用,提高访问速度。
fastcgi_connect_timeout 300;
fastcgi_send_timeout 300;
fastcgi_read_timeout 300;
fastcgi_buffer_size 64k;
fastcgi_buffers 4 64k;
fastcgi_busy_buffers_size 128k;
fastcgi_temp_file_write_size 128k;
/etc/nginx/conf.d/http.d/headers.conf
proxy_set_header Host $host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $proxy_connection;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $proxy_x_forwarded_host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-Proto $proxy_x_forwarded_proto;
proxy_set_header X-Forwarded-Port $proxy_x_forwarded_port;
proxy_set_header X-Forwarded-Ssl $proxy_x_forwarded_ssl;
proxy_set_header Proxy "";
proxy_redirect off;
proxy_http_version 1.1;
/etc/nginx/conf.d/http.d/proxy.conf
# 代理配置
proxy_buffering on;
proxy_buffer_size 8k;
proxy_buffers 100 8k;
# X-Forwarded-Host
map $http_x_forwarded_host $proxy_x_forwarded_host {
default $http_x_forwarded_host;
'' $host;
}
# X-Forwarded-Proto
map $http_x_forwarded_proto $proxy_x_forwarded_proto {
default $http_x_forwarded_proto;
'' $scheme;
}
# X-Forwarded-Port
map $http_x_forwarded_port $proxy_x_forwarded_port {
default $http_x_forwarded_port;
'' $server_port;
}
# X-Forwarded-Ssl
map $proxy_x_forwarded_proto $proxy_x_forwarded_ssl {
default off;
https on;
}
# Connection
map $http_upgrade $proxy_connection {
default upgrade;
'' '';
}
/etc/nginx/conf.d/http.d/ssl.conf
ssl_protocols TLSv1.3 TLSv1.2; # TLSv1 TLSv1.1
ssl_prefer_server_ciphers on;
ssl_early_data on;
ssl_ecdh_curve X25519:secp384r1:P-256;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
ssl_session_tickets on;
# ssl_stapling on;
#ssl_stapling_verify on;
#resolver_timeout 5s;
# ssl_trusted_certificate ssl/trustchain.crt;
#resolver 119.29.29.29 233.5.5.5 valid=300s;
/etc/nginx/conf.d/http.d/log_format.conf
log_format compression '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" "$gzip_ratio"';
log_format upstream_time '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent"'
'rt=$request_time uct="$upstream_connect_time" uht="$upstream_header_time" urt="$upstream_response_time"';
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
# QUIC
#log_format quic '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$quic"';
# referrence from http://ltsv.org
log_format ltsv 'vhost:$host\t'
'host:$remote_addr\t'
'user:$remote_user\t'
'time:$time_local\t'
'method:$request_method\t'
'uri:$request_uri\t'
'protocol:$server_protocol\t'
'status:$status\t'
'size:$body_bytes_sent\t'
'referer:$http_referer\t'
'ua:$http_user_agent\t'
'reqtime:$request_time\t'
'apptime:$upstream_response_time\t'
'cookie:$http_cookie\t'
'set_cookie:$sent_http_set_cookie\t'
'upstream_addr:$upstream_addr\t'
'upstream_cache_status:$upstream_cache_status';
log_format json escape=json '{'
'"host": "$host",'
'"remote": "$remote_addr",'
'"user": "$remote_user",'
'"time": "$time_iso8601",'
'"method": "$request_method",'
'"uri": "$request_uri",'
'"protocol": "$server_protocol",'
'"status": $status,'
'"size": $body_bytes_sent,'
'"referrer": "$http_referer",'
'"ua": "$http_user_agent",'
'"reqtime": "$request_time",'
'"forwardedfor": "$http_x_forwarded_for",'
'"cache": "$upstream_cache_status",'
'"nginx_access": true'
'}';
# Refference from Graylog3 nginx + Docker content pack
log_format gelf_json escape=json '{'
'"time": "$time_iso8601",'
'"remote_addr": "$remote_addr", '
'"connection": "$connection", '
'"connection_requests": $connection_requests, '
'"pipe": "$pipe", '
'"body_bytes_sent": $body_bytes_sent, '
'"request_length": $request_length, '
'"request_time": $request_time, '
'"response_status": $status, '
'"request": "$request", '
'"request_method": "$request_method", '
'"host": "$host", '
'"upstream_cache_status": "$upstream_cache_status", '
'"upstream_addr": "$upstream_addr", '
'"http_x_forwarded_for": "$http_x_forwarded_for", '
'"http_referrer": "$http_referer", '
'"http_user_agent": "$http_user_agent", '
'"http_version": "$server_protocol", '
'"remote_user": "$remote_user", '
'"http_x_forwarded_proto": "$http_x_forwarded_proto", '
'"upstream_response_time": "$upstream_response_time", '
'"nginx_access": true'
'}';
# 日志位置配置
error_log logs/error.log;
access_log logs/access.log json;
以上是基本不太需要变动的配置项,接下来就是主要变动的配置模板
配置模板
/etc/nginx/conf.d/vhost.d/templates/default.conf
server {
listen [::]:80 default_server deferred;
listen 80 default_server deferred;
server_name _;
return 301 https://$host$request_uri;
}
server {
listen [::]:443 ssl http2 default_server;
listen 443 ssl http2 default_server;
server_name _;
return 444;
}
测试
测试环境主要围绕模拟生产环境搭建,即Nginx + Dokcer Go Web服务
KeepAlive Timeout测试
Nginx查询连接数输入命令:
netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'
#输出:
ESTABLISHED 8 #8个并发数
TIME_WAIT 1 #等价于keepalive的连接数
CLOSED //无连接是活动的或正在进行
LISTEN //服务器在等待进入呼叫
SYN_RECV //一个连接请求已经到达,等待确认
SYN_SENT //应用已经开始,打开一个连接
ESTABLISHED //正常数据传输状态/当前并发连接数
FIN_WAIT1 //应用说它已经完成
FIN_WAIT2 //另一边已同意释放
ITMED_WAIT //等待所有分组死掉
CLOSING //两边同时尝试关闭
TIME_WAIT //另一边已初始化一个释放
LAST_ACK //等待所有分组死掉
语法详解:
- netstat -n 不解析名称
- awk '/^tcp/' 代表搜索行首tcp
- {++S[NF]} NF 最后一列值,S[] 数组,S[LISTEN]默认为0,++S[LISTEN]用来统计出现LISTEN的个数
- {for(a in S) print a,S[a]} 表示打印S[]列表
开启1000个线程同时连接,测试:
开启500个线程同时连接:测试:
过了keepalivetime时间后,回收连接
说明keepalivetimeout如预期
压力测试:
全部换位Http协议后:
循环测试,500个线程在5秒内执行完,循环50次:
循环测试,2000个线程在5秒内执行完,循环10次:
最后
Nginx暂时到这里结束,实际上以上测试还有较大问题,其中最关键一点,1秒钟单台机器开1000个线程,这实际上和线上环境差别较大,因为耗时你不能确定是你本机开了较多线程的原因还是Nginx处理就如此,比如我开测试工具开,延迟300ms乍看下来已经负载到较差的情况了,实际上开浏览器时依然还是50ms以内,这说明本身测试工具就有一定的问题,只能是后面同样的机器下做对比测试会比较好