本文介绍nignx相关内容
安装,以centos7为例
yum安装
- 添加yum源
cat > /etc/yum.repo.d/nginx.repo << EOF
[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/centos/7/$basearch/
gpgcheck=0
enabled=1
EOF
- 刷新yum缓存
yum makecache fast
- 安装nginx
yum install nginx -y
编译安装
- 安装依赖
yum install gcc gcc-c++ pcre pcre-devel openssl openssl-devel zlib zlib-devel make automake -y
- 创建用户
useradd -s /sbin/nologin nginx
- 下载安装包
wget http://nginx.org/download/nginx-1.16.0.tar.gz
tar -zxvf nginx-1.16.0.tar.gz
cd nginx-1.16.0
- 编译配置
./configure \
--prefix=/usr/local/nginx \
--user=nginx \
--group=nginx \
--with-http_stub_status_module \
--with-http_ssl_module \
--with-http_realip_module \
--with-http_gzip_static_module \
--with-http_v2_module \
--with-pcre \
--with-stream \
--with-stream_ssl_module \
--with-stream_realip_module
- 开始编译
make && make install
- 创建服务配置文件
cat > /usr/lib/systemd/system/nginx.service << EOF
[Unit]
Description=nginx - high performance web server
Documentation=http://nginx.org/en/docs/
After=network.target remote-fs.target nss-lookup.target
[Service]
Type=forking
PIDFile=/usr/local/nginx/logs/nginx.pid
ExecStartPre=/usr/local/nginx/sbin/nginx -t -c /usr/local/nginx/conf/nginx.conf
ExecStart=/usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf
ExecReload= /usr/local/nginx/sbin/nginx -s reload
ExecStop= /usr/local/nginx/sbin/nginx -s stop
PrivateTmp=true
[Install]
WantedBy=multi-user.target
EOF
- 添加执行权限
chmod +x /usr/lib/systemd/system/nginx.service
- 启动并设置开机启动
systemctl enable --now nginx.service
nginx调优
- 系统连接数的优化
cat >> /etc/security/limits.conf << EOF
* soft nofile 65535
* hard nofile 65535
* soft nproc 65535
* hard nproc 65535
EOF
- 内核优化
net.ipv4.ip_nonlocal_bind = 1
#作为负载均衡服务器一定要开启(LVS、haproxy、nginx),允许某个服务监听在本机所没有的IP地址的端口上,如LVS的vip;作为负载均衡服务器不开启此参数,则服务是无法起来的。
net.ipv4.ip_forward = 1
#开启ipv4转发功能,用于跨网段转发;负载均衡服务器一定要开启。
net.ipv4.tcp_timestamps = 0
#给报文添加时间戳,会对添加时间戳的报文做校验;作为web服务器可开启,作为负载均衡服务器一定要关闭。一个局域网内,都是用一个公网IP,如果访问一个网站的index.html资源,负载均衡服务器处理完一个请求后,又有第二个相同的IP访问相同网站的index.html,这时负载均衡服务器会把第二个报文校验完毕后,发现IP和请求的资源一致,会把报文抛弃掉,所以作为负载均衡服务器必须关闭此参数。
net.ipv4.tcp_tw_reuse = 0
#端口复用;依赖于net.ipv4.tcp_timestamps参数,如果net.ipv4.tcp_timestamps开启,则net.ipv4.tcp_tw_reuse生效,如果没开启,则此参数也不生效。
#参数设置为 1 ,表示允许将TIME_WAIT状态的socket重新用于新的TCP链接,这对于服务器来说意义重大,因为总有大量TIME_WAIT状态的链接存在;用于TCP连接。
net.ipv4.tcp_tw_recycle = 0
#快速回收TIME_WAIT状态,用于大量TIME_OUT场景;依赖于net.ipv4.tcp_timestamps参数。
#这个参数用于设置启用timewait快速回收;开启后,用户如果正在看网页,过会儿再点,会发现断开连接,会重新TCP三次握手建立连接。
fs.file-max = 1000000
#表示单个进程最多可以打开的文件描述符的数量。
net.ipv4.tcp_keepalive_time = 600
#当keepalive启动时,TCP发送keepalive消息的频度;默认是2小时,将其设置为10分钟,可更快的清理无效链接。
net.ipv4.tcp_fin_timeout = 30
#当服务器主动关闭链接时,socket保持在FIN_WAIT_2状态的较大时间。
net.ipv4.tcp_max_tw_buckets = 5000
#表示操作系统允许TIME_WAIT套接字数量的较大值,如超过此值,TIME_WAIT套接字将立刻被清除并打印警告信息,默认为8000,过多的TIME_WAIT套接字会使Web服务器变慢。
net.ipv4.ip_local_port_range = 1024 65000
#定义UDP和TCP链接的本地端口的取值范围。
net.ipv4.tcp_rmem = 10240 87380 12582912
#定义了TCP接受socket请求缓存的内存最小值、默认值、较大值。
net.ipv4.tcp_wmem = 10240 87380 12582912
#定义TCP发送缓存的最小值、默认值、较大值。
net.core.netdev_max_backlog = 8096
#当网卡接收数据包的速度大于内核处理速度时,会有一个列队保存这些数据包。这个参数表示该列队的较大值。
net.core.rmem_default = 6291456
#表示内核套接字接受缓存区默认大小。
net.core.wmem_default = 6291456
#表示内核套接字发送缓存区默认大小。
net.core.rmem_max = 12582912
#表示内核套接字接受缓存区较大大小。
net.core.wmem_max = 12582912
#表示内核套接字发送缓存区较大大小。
注意:以上的四个参数,需要根据业务逻辑和实际的硬件成本来综合考虑。
net.ipv4.tcp_syncookies = 1
#与性能无关。用于解决TCP的SYN攻击。
net.ipv4.tcp_max_syn_backlog = 8192
#这个参数表示TCP三次握手建立阶段接受SYN请求列队的较大长度,默认1024,将其设置的大一些可使出现。
Nginx繁忙来不及accept新连接时,Linux不至于丢失客户端发起的链接请求。
net.core.somaxconn = 262114
#选项默认值是128,这个参数用于调节系统同时发起的TCP连接数,在高并发的请求中,默认的值可能会导致链接超时或者重传,因此需要结合高并发请求数来调节此值。
net.ipv4.tcp_max_orphans=262114
#选项用于设定系统中最多有多少个TCP套接字不被关联到任何一个用户文件句柄上。如果超过这个数字,孤立链接将立即被复位并输出警告信息。这个限制指示为了防止简单的DOS攻击,不用过分依靠这个限制甚至认为的减小这个值,更多的情况是增加这个值。
nignx配置
- 重点配置解读
user nginx; # 系统用户为nginx
worker_processes 4; #如果服务器为4核,这里配4
worker_cpu_affinity 0001 0010 0100 1000; #如果服务器为4核,需要多核处理,则这么配
worker_rlimit_nofile 65535;
error_log /var/log/nginx/error.log warn;
events {
use epoll;
worker_connections 20480; #提高并发
}
http {
access_log /var/log/nginx/access.log main;
client_max_body_size 10M; #最大上传量
underscores_in_headers on; #header不区分大小写
tcp_nodelay on;
#tcp_nodelay off,会增加通信的延时,但是会提高带宽利用率。在高延时、数据量大的通信场景中应该会有不错的效果
#tcp_nodelay on,会增加小包的数量,但是可以提高响应速度。在及时性高的通信场景中应该会有不错的效果
include /etc/nginx/conf.d/*.conf;
}
- 日志配置(输出为json格式,方便elasticsearch解析)
log_format main escape=json
'{"@timestamp":"$time_iso8601",'
'"host":"$hostname",'
'"server_ip":"$server_addr",'
'"client_ip":"$remote_addr",'
'"xff":"$proxy_add_x_forwarded_for",'
'"domain":"$host",'
'"url":"$uri",'
'"referer":"$http_referer",'
'"args":"$args",'
'"upstream_time":"$upstream_response_time",'
'"response_time":"$request_time",'
'"request_method":"$request_method",'
'"status_code":"$status",'
'"size_num":"$body_bytes_sent",'
'"request_body":"$request_body",'
'"request_length":"$request_length",'
'"protocol":"$server_protocol",'
'"upstreamhost":"$upstream_addr",'
'"file_dir":"$request_filename",'
'"http_user_agent":"$http_user_agent"'
'}';
- 我用的配置(不要直接复制,会起不来)
user nginx;
worker_processes 4;
worker_cpu_affinity 0001 0010 0100 1000;
worker_rlimit_nofile 65535;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
use epoll;
worker_connections 20480;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main escape=json
'{"@timestamp":"$time_iso8601",'
'"host":"$hostname",'
'"server_ip":"$server_addr",'
'"client_ip":"$remote_addr",'
'"xff":"$proxy_add_x_forwarded_for",'
'"domain":"$host",'
'"url":"$uri",'
'"referer":"$http_referer",'
'"args":"$args",'
'"upstream_time":"$upstream_response_time",'
'"response_time":"$request_time",'
'"request_method":"$request_method",'
'"status_code":"$status",'
'"size_num":"$body_bytes_sent",'
'"request_body":"$request_body",'
'"request_length":"$request_length",'
'"protocol":"$server_protocol",'
'"upstreamhost":"$upstream_addr",'
'"file_dir":"$request_filename",'
'"http_user_agent":"$http_user_agent"'
'}';
access_log /var/log/nginx/access.log main;
server_names_hash_bucket_size 512;
sendfile on;
server_tokens off;
keepalive_timeout 30;
client_header_buffer_size 4k;
client_max_body_size 10M;
underscores_in_headers on;
tcp_nodelay on;
gzip on;
gzip_buffers 32 4K;
gzip_comp_level 6;
gzip_min_length 100;
gzip_types application/javascript text/css text/xml;
gzip_disable "MSIE [1-6]\.";
gzip_vary on;
more_clear_headers 'Server';
include /etc/nginx/conf.d/*.conf;
}
转发配置
是否带证书
- 带证书
server {
listen 443 ssl;
server_name {{域名}};
ssl_certificate /etc/nginx/certs/{{证书名}}.pem;
ssl_certificate_key /etc/nginx/certs/{{证书名}}.key;
ssl_session_timeout 5m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
ssl_prefer_server_ciphers on;
location / {
proxy_pass http://192.168.1.132:30057;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
- 不带证书
server {
listen 80;
location / {
proxy_pass http://192.168.1.132:30057;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
upstream方法
- 多个后端地址
upstream {{应用别名}}{
server 192.168.1.130:30070 max_fails=3 fail_timeout=30s weight=1;
server 192.168.1.131:30070 max_fails=3 fail_timeout=30s weight=1;
}
server {
listen 30070;
location / {
proxy_pass http://{{应用别名}}/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
转发规则
- 模糊匹配域名后面的第一级aaa转发到特定地址
server {
listen 80;
location / {
proxy_pass http://192.168.1.132:30064;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location ^~ /aaa/ {
proxy_pass http://192.168.1.132:30070/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
- 绝对匹配域名为/aaa/notify的路由转发到特定地址
server {
listen 80;
location / {
proxy_pass http://192.168.1.132:30064;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location /aaa/notify {
proxy_pass http://192.168.1.132:30070/aaa/notify;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
- 通过header中的参数值判断转发,将channel为online转发到特定地址
server {
listen 80;
location / {
#参数格式为 $http_{{参数名}}
if ($http_channel = "online") {
proxy_pass http://192.168.1.32:20007;
}
proxy_pass http://192.168.1.106:16000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
- 设置访问白名单
server {
listen 80;
allow 192.168.1.1; # 对方出口地址
deny all; # 拒绝所有其它地址
location / {
proxy_pass http://192.168.1.37:20009;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
高并发优化
nginx后端使用k8s集群应用提供服务,需与k8s的服务保持长连接,并增加缓冲区空间。
如果不设置长连接,每次建立连接花费的时间将会影响接口响应的速度,如果是高并发场景,连接会在释放与连接状态中不停切换,导致接口响应的效果变差。具体压测数据可以参考文章
upstream {{应用别名}}{
server 192.168.1.36:30057 max_fails=3 fail_timeout=30s weight=1;
server 192.168.1.30:30057 max_fails=3 fail_timeout=30s weight=1;
server 192.168.1.31:30057 max_fails=3 fail_timeout=30s weight=1;
}
server {
listen 30057;
location / {
proxy_pass http://{{应用别名}}/;
proxy_connect_timeout 75;
proxy_read_timeout 300;
proxy_send_timeout 300;
proxy_buffer_size 64k;
proxy_buffers 4 64k;
proxy_busy_buffers_size 128k;
proxy_temp_file_write_size 128k;
proxy_http_version 1.1;
proxy_set_header Connection "Keep-Alive";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}