如何优化Nginx性能

2017-08-21

nginx以高性能负载平衡和缓存静态和动态Web内容的方式而闻名。本指南旨在帮助确定为nginx服务器做出最佳性能优化,以加速向最终用户提供内容。

nginx

如果您不熟悉nginx如何工作,我们建议您先阅读如何配置nginx。

worker 调优

最简单的方法,是在配置文件中配置正确的 worker 和 worker_connections。

Worker Processes

在/etc/nginx/nginx.conf,设置,worker_processes 1;如果您有一个较低的流量站点,其中nginx,数据库和Web应用程序都运行在同一台服务器上。

如果您有较高的流量站点或nginx的专用实例,请为每个CPU内核设置一个worker: worker_processes auto;

如果您想手动设置,可以使用grep ^processor /proc/cpuinfo | wc -l来查找服务器可以处理的进程数。

Worker Connections

该选项worker_connections设置每个工作进程一次可处理的最大连接数。默认情况下,worker连接限制为512,但是许多系统可以处理更多。

通过测试可以发现适当的大小调整,因为它是根据nginx正在处理的流量类型而变化的。系统的核心限制也可以通过使用ulimit:

$ ulimit -n

结果会输出一个数字:

65536

您还可以设置use epoll一个可扩展的I / O事件通知机制来触发事件,并确保I / O最大限度地利用它。

最后,您可以利用multi_accept一次工作来接受所有新的连接。

events配置时,该功能应该是这样的:

# /etc/nginx/nginx.conf
events {
    worker_connections  65536 ;
    use epoll;
    multi_accept on;
}

HTTP和TCP优化

Keep Alive

保持 keepalive 可以减少浏览器的重新连接。请记住将这些设置放在http {}指令中。

  • keepalive_timeoutkeepalive_requests控制保持活动设置。
  • sendfile 优化从文件系统提供的静态文件,如徽标。
  • tcp_nodelay 允许nginx使TCP作为单独的数据包发送多个缓冲区。
  • tcp_nopush通过激活TCP堆栈中的TCP_CORK选项,优化一次发送的数据量。TCP_CORK阻塞数据,直到数据包到达MSS,这等于MTU减去IP头的40或60字节。
keepalive_timeout 65;
keepalive_requests 100000;
sendfile on;
tcp_nopush on;
tcp_nodelay on;

Buffer Size

调整缓冲区大小可能是有利的。如果缓冲区大小太小,那么nginx会写入临时文件。这将导致磁盘I / O过多。请记住将这些设置放在http {}指令中。

  • client_body_buffer_size处理客户端缓冲区大小。大多数客户端缓冲区来自POST方法表单提交。128k通常是这个设置的好选择。
  • client_max_body_size设置最大身体缓冲区大小。如果请求中的大小超过配置值,则将413(请求实体太大)错误返回给客户端。作为参考,浏览器无法正确显示413错误。将大小设置为0将禁用检查客户端请求正文大小。
  • client_header_buffer_size处理客户端头大小。默认情况下,1k通常是一个理想的选择。
  • large_client_header_buffers显示大型客户端头的缓冲区的最大数量和大小。4个缓冲区的标头应该足够了。
  • output_buffers设置用于从磁盘读取响应的缓冲区的数量和大小。如果可能,客户端数据的传输将被推迟,直到nginx至少具有要发送的数据字节的设置大小。零值禁止延迟数据传输。
client_body_buffer_size      128k;
client_max_body_size         10m;
client_header_buffer_size    1k;
large_client_header_buffers  4 4k;
output_buffers               1 32k;
postpone_output              1460;

Connection Queue

/etc/sysctl.conf可以更改文件中的一些指令,以便为连接和存储桶设置Linux队列的大小。更新net.core.somaxconn并net.ipv4.tcp_max_tw_buckets更改等待nginx验收的连接的队列大小。如果内核日志中有错误消息,请增加值直到错误停止。

# /etc/sysctl.conf
net.core.somaxconn = 65536
net.ipv4.tcp_max_tw_buckets = 1440000

在通过使用net.core.netdev_max_backlog标签设置最大积压量之前,可以将数据包缓冲在网卡中,然后交给CPU 。有关更改此值的信息,请参阅网卡文档。

Timeouts

超时也可以大大提高性能。请记住将这些设置放在http {}指令中。

  • client_body_timeout在服务器等待身体发送的时间发送指令。
  • client_header_timeout在服务器等待发送头文件的时候发送指令。这些指令负责服务器等待客户端或客户端头发送请求后的时间。如果没有发送主体或头文件,服务器将发出408错误或请求超时。
  • send_timeout指定客户端的响应超时。此超时不适用于整个传输,而仅适用于两个后续的客户端读取操作。因此,如果客户端在这段时间内没有读取任何数据,那么nginx会关闭连接。
# /etc/nginx/nginx.conf
client_header_timeout   3 m ;
client_body_timeout     3 m ;
send_timeout            3 m ;

静态资源管理

如果您的网站提供静态资源(如CSS / JavaScript /图像),nginx可以在短时间内缓存这些文件。在配置块中添加此内容将告诉nginx缓存1000个文件30秒,不包括任何在20秒内未被访问的文件,只有在该时间段内至少访问过5次的文件。如果您没有频繁部署,您可以安全地将这些数字更高。请记住将这些设置放在http {}指令中。

# /etc/nginx/nginx.conf
open_file_cache max=1000 inactive=20s;
open_file_cache_valid 30s;
open_file_cache_min_uses 5;
open_file_cache_errors off;

您还可以通过特定位置进行缓存。缓存文件很长时间是有益的,特别是如果文件具有由构建过程或CMS提供的版本控制系统。这应该放在虚拟主机配置或主配置中(例如:/etc/nginx/ sites-available/default)

# /etc/nginx/nginx.conf
location ~* .(woff|eot|ttf|svg|mp4|webm|jpg|jpeg|png|gif|ico|css|js)$ {
    expires 365d;
}

Gzipping 内容

对于纯文本的内容,nginx可以使用gzip压缩来将这些资源压缩到客户端。现代网络浏览器将接受gzip压缩,并且会从明文资料的每个请求中刮除字节。以下列表是可压缩内容类型的“安全”列表; 但是,您只想在Web应用程序中启用您正在使用的内容类型。请记住将这些设置放在http {}指令中。

# /etc/nginx/nginx.conf
gzip on;
gzip_min_length 1000;
gzip_types text/html application/x-javascript text/css application/javascript text/javascript text/plain text/xml application/json application/vnd.ms-fontobject application/x-font-opentype application/x-font-truetype application/x-font-ttf application/xml font/eot font/opentype font/otf image/svg+xml image/vnd.microsoft.icon;
gzip_disable "MSIE [1-6]\.";

文件系统优化

将下面这些配置加入/etc/sysctl.conf, 可以提高操作系统的内存管理。

Ephemeral Ports

当nginx充当代理时,与上游服务器的每个连接都使用临时或临时端口。

IPv4本地端口范围定义端口范围值。一个常见的设置是net.ipv4.ip_local_port_range = 1024 65000。

TCP FIN超时限制端口必须处于非活动状态的时间,然后才能重新用于另一个连接。默认值通常为60秒,但通常可以安全地减少到30秒甚至15秒:

# /etc/sysctl.conf
net.ipv4.tcp_fin_timeout = 15

Scale TCP Window

TCP窗口缩放选项是将传输控制协议中允许的接收窗口大小增加到其先前最大值65,535字节以外的选项。该TCP选项以及其他几个在IETF RFC 1323中定义,它涉及长胖网络。它可以用net.ipv4.tcp_window_scaling = 1标签来定义。

Backlog Packets Before Drop

net.ipv4.tcp_max_syn_backlog确定数量的数据包,以保持在积压内核开始丢弃他们。一个合理的价值是net.ipv4.tcp_max_syn_backlog = 3240000

关闭缺少客户端响应的链接

**reset_timedout_connection on;**允许服务器在客户端停止响应后关闭连接。这释放了与socket关联的内存。请记住将此设置放在http {}指令内。

File Descriptors

文件描述符是用于处理诸如连接和打开文件之类的操作系统资源。nginx每个连接最多可以使用两个文件描述符。例如,如果是代理服务器,则通常有一个客户端连接的文件描述符,另一个用于连接到代理服务器的文件描述符,但如果使用HTTP保持活动,则该比率要低得多。对于服务大量连接的系统,可能需要对这些设置进行调整。 sys.fs.file_max定义文件描述符的系统范围限制。nofile定义文件中设置的用户文件描述符限制**/etc/security/limits.conf**。

# /etc/security/limits.conf
soft nofile 4096
hard nofile 4096

错误日志

error_log logs/error.log warn;定义写入错误日志的位置和不同的严重性级别。设置一个特定的日志级别会导致从该日志级别和更高级别的所有消息被记录。例如,default电平误差将导致errorcritalert,和emerg将被记录的消息。如果省略此参数,则error默认使用。

  • emerg:系统处于不可用状态的紧急情况。
  • alert:需要及时采取行动的严峻形势。
  • crit:需要解决的重要问题。
  • error:发生错误。有些事情没有成功。
  • warn: 普通的事情发生了,但不是令人担忧的原因。
  • notice:正常,但值得注意的事情发生了。
  • info: 可能很高兴知道的信息性消息。
  • debug:调试可用于确定发生问题的位置的信息。

使用log_format指令访问日志以配置记录消息的格式,以及access_log指定日志位置和格式的指令。

# /etc/nginx/nginx.conf
http {
    log_format compression '$remote_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent ' '"$http_referer" "$http_user_agent" "$gzip_ratio"';
    server {
        gzip on;
        access_log /spool/logs/nginx-access.log compression;
    }
}

条件记录日志

如果系统管理员只想记录某些请求,则可以根据条件记录日志。下面的示例排除了2XX和3XX HTTP状态代码的日志记录:

# /etc/nginx/nginx.conf
map $status $loggable {
    ~^[23]  0;
    default 1;
}

完全关闭日志

如果您有备用的记录方法,或者您不关心将任何请求记录到服务器,可以完全关闭日志记录。可以使用以下服务器指令执行关闭日志

# /etc/nginx/nginx.conf
server {
    listen       80;
    server_name  example.com;
    access_log  off;
    error_log off;
}

打开 nginx 监控

还可以设置activity monitoring 来实时查看JSON响应。通过以下配置,可以通过URL请求status.html位于的网页。

/usr/share/nginx/html
http://127.0.0.1/status.html

配置文件样例。

现在已经对三个文件进行了几个调整,以提高系统中的nginx性能。文件的完整片段包含在下面。

sysctl.conf

# /etc/sysctl.conf
net.core.somaxconn = 65536
net.ipv4.tcp_max_tw_buckets = 1440000
net.ipv4.ip_local_port_range = 1024 65000
net.ipv4.tcp_fin_timeout = 15
net.ipv4.tcp_window_scaling = 1
net.ipv4.tcp_max_syn_backlog = 3240000

limits.conf

# /etc/security/limits.conf
soft nofile 4096
hard nofile 4096

nginx.conf

# nginx.conf
pid /var/run/nginx.pid;
worker_processes  2;

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

http {
    keepalive_timeout 65;
    keepalive_requests 100000;
    sendfile         on;
    tcp_nopush       on;
    tcp_nodelay      on;

    client_body_buffer_size    128k;
    client_max_body_size       10m;
    client_header_buffer_size    1k;
    large_client_header_buffers  4 4k;
    output_buffers   1 32k;
    postpone_output  1460;

    client_header_timeout  3m;
    client_body_timeout    3m;
    send_timeout           3m;

    open_file_cache max=1000 inactive=20s;
    open_file_cache_valid 30s;
    open_file_cache_min_uses 5;
    open_file_cache_errors off;

    gzip on;
    gzip_min_length  1000;
    gzip_buffers     4 4k;
    gzip_types       text/html application/x-javascript text/css application/javascript text/javascript text/plain text/xml application/json application/vnd.ms-fontobject application/x-font-opentype application/x-font-truetype application/x-font-ttf application/xml font/eot font/opentype font/otf image/svg+xml image/vnd.microsoft.icon;
    gzip_disable "MSIE [1-6]\.";

    # [ debug | info | notice | warn | error | crit | alert | emerg ]
    error_log  /var/log/nginx.error_log  warn;

    log_format main      '$remote_addr - $remote_user [$time_local]  '
      '"$request" $status $bytes_sent '
      '"$http_referer" "$http_user_agent" '
  		'"$gzip_ratio"';

    log_format download  '$remote_addr - $remote_user [$time_local]  '
      '"$request" $status $bytes_sent '
      '"$http_referer" "$http_user_agent" '
  		'"$http_range" "$sent_http_content_range"';

    map $status $loggable {
        ~^[23]  0;
        default 1;
    }

    server {
        listen        127.0.0.1;
        server_name   127.0.0.1;
        root         /var/www/html;
        access_log   /var/log/nginx.access_log  main;

        location / {
            proxy_pass         http://127.0.0.1/;
            proxy_redirect     off;
            proxy_set_header   Host             $host;
            proxy_set_header   X-Real-IP        $remote_addr;
            proxy_set_header  X-Forwarded-For  $proxy_add_x_forwarded_for;
            proxy_connect_timeout      90;
            proxy_send_timeout         90;
            proxy_read_timeout         90;
            proxy_buffer_size          4k;
            proxy_buffers              4 32k;
            proxy_busy_buffers_size    64k;
            proxy_temp_file_write_size 64k;
            proxy_temp_path            /etc/nginx/proxy_temp;
        }

        location ~* .(woff|eot|ttf|svg|mp4|webm|jpg|jpeg|png|gif|ico|css|js)$ {
            expires 365d;
        }
    }
}
https://www.linode.com/docs/web-servers/nginx/configure-nginx-for-optimized-performance