单机Nginx性能优化

前言

消息爆炸的时代,对于速度的追逐已成了大家的标配。为了让自己的网站有更好的访问体验,网页加载控制在 3s 内,决定了网友愿不愿等你。静态文件的缓存优化了网页加载,超时机制会让 Client 与 Server 的响应不会长时间阻塞,GZIP 压缩提升 IO 效率、减少我们发送的数据量,限流来预防 DOS 攻击,TCP 参数调优提升传输效率。如何加速网页加载,提升网站访问的性能?

Nginx 的系统结构

Nginx 包含一个单一的 master 进程和多个 worker 进程。所有的这些进程都是单线程,并且设计为同时处理成千上万个连接。worker 进程是处理连接的地方,它用于处理客户端请求。master 进程负责读取配置文件、处理套接字、派生 worker 进程、打开日志文件等。总之, master 进程是一个可以通过处理信号响应来管理请求的进程。

CentOS7 下载安装 Nginx

准备好一台裸机,装好 CentOS7 系统

3.1 添加源

默认情况 Centos7 中无 Nginx 的源,最近发现 Nginx 官网提供了 Centos 的源地址。因此可以如下执行命令添加源:

sudo rpm -Uvh http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm

3.2 安装 Nginx

通过 yum search nginx 看是否已经添加源成功。
如果成功则执行下列命令安装 Nginx。

sudo yum install -y nginx

3.3 Nginx 开机自动运行

sudo systemctl start nginx.service
sudo systemctl enable nginx.service

常规参数讲解

进入 /etc/nginx 文件夹,编辑 nginx.conf ,可以看到下面的参数。简单介绍下:

# nginx进程数,建议按照cpu数目来指定,一般跟cpu核数相同或为它的倍数。
worker_processes 8;

#为每个进程分配cpu,上例中将8个进程分配到8个cpu,当然可以写多个,或者将一个进程分配到多个cpu。
worker_cpu_affinity 00000001 00000010 00000100 00001000 00010000 00100000 01000000 10000000;

# 作用于event的I/O多路复用模型
use epoll;

#收到新连接通知后接受尽可能多的连接,作用于event
multi_accept on;

epoll 接口作为 poll 接口的变体在 Linux 内核 2.5 中被引入。相比 select 实现的多路复用 I/O 模型,epoll 最大的好处在于它不会随着被监控描述符数目的增长而导致效率急速下降。

动静分离

将静态文件存储到 /usr/share/nginx/html 文件夹中,配置静态文件拦截规则。单个项目可以直接放在 /usr/share/nginx/html 根目录下,如果是多个项目,则要根据项目的根目录创建文件夹来保存静态文件。

enter image description here

配置拦截规则如下:

location ~ .*\.(eot|svg|ttf|woff|jpg|jpeg|gif|png|ico|cur|gz|svgz|mp4|ogg|ogv|webm) {
    #所有静态文件直接读取硬盘
    root /usr/share/nginx/html;
    expires 30d; #缓存30天
}

location ~ .*\.(js|css)?${
    #所有静态文件直接读取硬盘
    root /usr/share/nginx/html;
    expires      12h;
}

结果:https://www.ygoclub.com 这个网站的访问速度从 2s 下降到 300-400ms,大部分内容都将从静态文件目录或者硬盘中读取。

enter image description here

缓存配置

配置三步走:

  • 客户端、代理请求缓存;
  • 设置缓存空间,存储缓存文件;
  • 在 location 中使用缓存空间;
  • 打开文件的缓存配置。
#客户端请求主体的缓冲区大小
client_body_buffer_size 512k;
#客户端请求头部的缓冲区大小,这个可以根据系统分页大小来设置
client_header_buffer_size 4k;
client_max_body_size 512k;
large_client_header_buffers 2 8k;
proxy_buffer_size 16k;
proxy_buffers 4 64k;
proxy_busy_buffers_size 128k;
proxy_temp_file_write_size 128k;
#指定在何种情况下一个失败的请求应该被发送到下一台后端服务器
proxy_next_upstream http_502 http_504 http_404 error timeout invalid_header;

#设置缓存空间,存储缓存文件
proxy_cache_path /data/nginx-cache levels=1:2 keys_zone=nginx-cache:20m max_size=50g inactive=168h;

#在location中使用缓存空间,pathname是项目的目录,请自定义
location /pathname { 
    proxy_set_header X-Real-IP $remote_addr;
    proxy_cache nginx-cache;
    proxy_cache_valid 200 304 302 5d;
    proxy_cache_valid any 5d;
    proxy_cache_key '$host:$server_port$request_uri';
    add_header X-Cache '$upstream_cache_status from $host';
    proxy_set_header X-Real-IP $remote_addr;
    proxy_pass http://localhost/pathname;
}

#打开文件的缓存配置
#为打开文件指定缓存,默认是没有启用的,max 指定缓存数量,建议和打开文件数一致,inactive 是指经过多长时间文件没被请求后删除缓存。
open_file_cache max=65535 inactive=60s;

#文件描述符一直是在缓存中打开的,如果有一个文件在inactive时间内一次没被使用,它将被移除。
open_file_cache_min_uses 1;

#指定多长时间检查一次缓存的有效信息。
open_file_cache_valid 80s;

上述配置的结果,我们可以看到生成了很多缓存文件在 /data/nginx-cache 文件夹下面。

enter image description here

我们打开其中一个文件看看,会发现一些蹊跷,这里存储了请求头的信息。当我们处理一个 HTTP 请求的时候,它会先从这里读取。

enter image description here

连接超时

长时间占着连接资源不释放,最终会导致请求的堆积,Nginx 处理请求效率大大降低。所以我们对连接的控制都要注意设置超时时间,通过超时机制自动回收资源、避免资源浪费。

#客户端、服务端设置
server_names_hash_bucket_size 128;
server_names_hash_max_size 512;
# 长连接超时配置
keepalive_timeout  65;
client_header_timeout 15s;
client_body_timeout 15s;
send_timeout 60s;

#代理设置
#与后端服务器建立连接的超时时间。注意这个一般不能大于75秒
proxy_connect_timeout 30s;
proxy_send_timeout 120s;
#从后端服务器读取响应的超时
proxy_read_timeout 120s;

GZIP 压缩

在我们进行 gzip 打包压缩之前,最好将一些静态文件先进行压缩为 min 文件,请求的时候合并为同一文件。再通过 gzip 压缩后,你会发现网站加载又加速了。

#开启gzip,减少我们发送的数据量
gzip on;
#允许压缩的最小字节数
gzip_min_length 1k;
#4个单位为16k的内存作为压缩结果流缓存
gzip_buffers 4 16k;
#设置识别HTTP协议版本,默认是1.1
gzip_http_version 1.1;
#gzip压缩比,可在1~9中设置,1压缩比最小,速度最快,9压缩比最大,速度最慢,消耗CPU
gzip_comp_level 4;
#压缩的类型
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript; 
#给代理服务器用的,有的浏览器支持压缩,有的不支持,所以避免浪费不支持的也压缩,所以根据客户端的HTTP头来判断,是否需要压缩
gzip_vary on;
#禁用IE6以下的gzip压缩,IE6的某些版本对gzip的压缩支持很不好
gzip_disable "MSIE [1-6].";

访问限流

我们构建网站是为了让用户访问它们,我们希望用于合法访问。所以不得不采取一些措施限制滥用访问的用户。这种滥用指的是从同一IP每秒到服务器请求的连接数。因为这可能是在同一时间内,世界各地的多台机器上的爬虫机器人多次尝试爬取网站的内容。

#限制用户连接数来预防DOS攻击
limit_conn_zone $binary_remote_addr zone=perip:10m;
limit_conn_zone $server_name zone=perserver:10m;
#限制同一客户端ip最大并发连接数
limit_conn perip 2;
#限制同一server最大并发连接数
limit_conn perserver 20;
#限制下载速度,根据自身服务器带宽配置
limit_rate 300k; 

高效数据传输配置

#开启文件的高效传输模式。tcp_nopush和tcp_nodelay可防止网络及磁盘i/o阻塞,提升nginx工作效率;
sendfile on;
#数据包不会马上传送出去,等到数据包最大时,一次性的传输出去,这样有助于解决网络堵塞。
tcp_nopush on;
#只要有数据包产生,不管大小多少,就尽快传输
tcp_nodelay on;

内核参数的优化

编辑 /etc/sysctl.conf 文件,根据需要调整参数配置。

#如果想把timewait降下了就要把tcp_max_tw_buckets值减小,默认是180000
net.ipv4.tcp_max_tw_buckets = 5000

#开启重用功能,允许将TIME-WAIT状态的sockets重新用于新的TCP连接
net.ipv4.tcp_tw_reuse = 1

#系统中最多有多少个TCP套接字不被关联到任何一个用户文件句柄上。如果超过这个数字,孤儿连接将即刻被复位并打印出警告信息。这个限制仅仅是为了防止简单的DoS攻击
net.ipv4.tcp_max_orphans = 262144

#当keepalive起用的时候,TCP发送keepalive消息的频度。缺省是2小时。我们可以调短时间跨度
net.ipv4.tcp_keepalive_time = 30

日志配置

日志文件对于我们日常运维至关重要,如果没有日志排查问题,你将很难判断异常的所在,要解决问题无异于大海捞针。日志的保存时必要的,不可缺少的,我们来看下怎么配置有利于排查问题?

  • 关键字:其中关键字 access_log,error_log 不能改变
  • error_log 错误日志级别:[debug | info | notice | warn | error | crit | alert | emerg],级别越高记录的信息越少。不要配置 info 等级较低的级别,会带来大量的磁盘 I/O 消耗。

error_log 生产场景一般是 warn | error | crit 这三个级别之一

#定义日志模板
log_format 日志模板名称 日志格式;

#访问日志
access_log   path      format        gzip[=level]              [buffer=size]          [flush=time];
关键字     存放的路径   日志格式模板   gzip压缩,level指压缩级别   存放缓存日志的缓存大小   保存在缓存中的最长时间

#错误日志
error_log      ;
关键字     日志文件   错误日志级别

#示例
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  /Users/jackson/Desktop/www.ygoclub.com-access.log  main gzip flush=5m;
error_log  /Users/jackson/Desktop/www.ygoclub.com-error.log  error;

打开 /Users/jackson/Desktop/www.ygoclub.com-error.log 日志文件,我们可以看到很多找不到文件的异常。日志辅助我们找到了问题,只要将文件补充上去就解决了。

enter image description here

实战配置

13.1 整体配置

worker_processes  1;
pid  /var/run/nginx.pid;

events {
    worker_connections  2048;
    multi_accept on;
    use epoll;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;
                      
    log_format main '{"@timestamp":"$time_iso8601",'   
    '"host":"$server_addr",'
    '"clientip":"$remote_addr",'
    '"size":$body_bytes_sent,'
    '"responsetime":$request_time,'
    '"upstreamtime":"$upstream_response_time",'
    '"upstreamhost":"$upstream_addr",'
    '"http_host":"$host",'
    '"url":"$uri",'
    '"xff":"$http_x_forwarded_for",'
    '"referer":"$http_referer",'
    '"agent":"$http_user_agent",'
    '"status":"$status"}';
    
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    
    server_names_hash_bucket_size 128;
    server_names_hash_max_size 512;
    keepalive_timeout  65;
    client_header_timeout 15s;
    client_body_timeout 15s;
    send_timeout 60s;
    
    limit_conn_zone $binary_remote_addr zone=perip:10m;
    limit_conn_zone $server_name zone=perserver:10m;
    limit_conn perip 2;
    limit_conn perserver 20;
    limit_rate 300k; 

    proxy_cache_path /data/nginx-cache levels=1:2 keys_zone=nginx-cache:20m max_size=50g inactive=168h;
    
    client_body_buffer_size 512k;
    client_header_buffer_size 4k;
    client_max_body_size 512k;
    large_client_header_buffers 2 8k;
    proxy_connect_timeout 5s;
    proxy_send_timeout 120s;
    proxy_read_timeout 120s;
    proxy_buffer_size 16k;
    proxy_buffers 4 64k;
    proxy_busy_buffers_size 128k;
    proxy_temp_file_write_size 128k;
    proxy_next_upstream http_502 http_504 http_404 error timeout invalid_header;
    
    gzip on;
    gzip_min_length 1k;
    gzip_buffers 4 16k;
    gzip_http_version 1.1;
    gzip_comp_level 4;
    gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
    gzip_vary on;
    gzip_disable "MSIE [1-6].";

    include /etc/nginx/conf.d/*.conf;
}

13.2 负载均衡

upstream ygoapi{ 
  server 0.0.0.0:8082 fail_timeout=5 max_fails=3;
  server 0.0.0.0:8083 fail_timeout=5 max_fails=3;
  ip_hash;
}

13.3 HTTP 配置

#隐藏版本信息
server_tokens off;
server {
    listen       80;
    server_name  www.ygoclub.com;
    charset utf-8;
    
    #重定向HTTP请求到HTTPS
    return 301 https://$server_name$request_uri;
}

13.4 HTTPS 配置

  • 准备条件:需要先去下载 HTTPS 证书
server {
    listen 443;
    server_name www.ygoclub.com;
    ssl on;
    ssl_certificate cert/证书名称.pem;
    ssl_certificate_key cert/证书名称.key;
    ssl_session_timeout 5m;
    # SSL协议配置
    ssl_protocols SSLv2 SSLv3 TLSv1.2;
    ssl_ciphers ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP;
    ssl_prefer_server_ciphers on;
    
    valid_referers none blocked server_names
               *.ygoclub.com;
               
    #日志配置
    access_log  /Users/jackson/Desktop/www.ygoclub.com-access.log  main gzip=4 flush=5m;
    error_log  /Users/jackson/Desktop/www.ygoclub.com-error.log  error;
    
    location ~ .*\.(eot|svg|ttf|woff|jpg|jpeg|gif|png|ico|cur|gz|svgz|mp4|ogg|ogv|webm) {
        proxy_cache nginx-cache;
        proxy_cache_valid 200 304 302 5d;
        proxy_cache_key '$host:$server_port$request_uri';
        add_header X-Cache '$upstream_cache_status from $host';
        #所有静态文件直接读取硬盘
        root /usr/share/nginx/html;
        expires 30d; #缓存30天
    }

    location ~ .*\.(js|css)?$
    {
        proxy_cache nginx-cache;
        proxy_cache_valid 200 304 302 5d;
        proxy_cache_key '$host:$server_port$request_uri';
        add_header X-Cache '$upstream_cache_status from $host';
        #所有静态文件直接读取硬盘
        root /usr/share/nginx/html;
        expires      12h;
    }

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }
    
    location /druid {
        proxy_set_header X-Real-IP $remote_addr;
        proxy_cache nginx-cache;
        proxy_cache_valid 200 10m;
        proxy_pass http://ygoapi/druid;
    }
    
    location /api {
       proxy_set_header X-Real-IP $remote_addr;
       proxy_pass http://ygoapi/api;
    }
    
    # redirect server error pages to the static page /50x.html
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
}
有朋自远方来,不亦乐乎?
为提供更好的知识分享,欢迎提出建议、指正问题,博客:风流三月1,微信号是 pgy1607974129 ,公众号是“ Ygo 工作室”。
Ygo工作室

本文由风流三月1发布,微信号:pgy1607974129

你可能感兴趣的:(单机Nginx性能优化)