目录

一、worker进程配置

二、I/O配置

三、TCP模块配置

四、Buffer模块

五、静态文件缓存

六、压缩模块

七、其他

八、性能监控

        1、如何使用监控

        2、监控项说明

        2.1、Nginx服务器的基本信息

        2.2、 Nginx服务器处理请求信息统计

        2.3、 根据upstream进行信息统计


写在开头:本文为学习后的总结,可能有不到位的地方,错误的地方,欢迎各位指正。

        一般情况下,一个正常安装的Nginx足以满足我们的日常工作要求,不过为了尽可能的提高我们的性能,还是有一些参数可以由我们来调整的。需要注意一点,这是一个简单的预览——那些可以通过微调来提高性能设置的概述,不同的环境可能情况不太一样。在调整完毕后,一定要做好测试验证工作(nginx -s reload 重新加载/nginx -t检查配置)。本文中,我们将优化参数按模块划分为worker进程配置、I/O配置等。

一、worker进程配置

        1、worker_processes

nginx通过工作进程处理具体的请求,设置几个工作进程就代表允许几个并发。最优的设置是worker进程数量要与CPU的核数相等,Linux中我们可以用lscpu命令来找出CPU的核数。

worker_processes 8; 

        它是一个全局性配置,不属于events模块,也不属于http或location模块。

        2、worker_cpu_affinity

        为每个进程分配CPU的工作内核,参数有多个二进制值表示,每一组代表一个进程。每组中的每一位代表该进程使用CPU的情况,1代表使用,0代表不使用。

worker_cpu_affinity 00000001 00000010 00000100 00001000 00010000 00100000 01000000 10000000;

        默认情况下worker进程不绑定在任何一个CPU上。在 nginx 版本 1.9.10 之后,是可以自动将 worker 进程绑定到对应的 cpu 上面的。

        3、worker_connections

        指定一个worker进程在同一时间可以处理的最大请求数,默认512,配置在events模块中。
理论上每台nginx服务器的最大连接数为 worker_processes*worker_connections。

worker_connections 512;

        4、worker_rlimit_nofile

        由于每一个socket都会打开一个文件描述符,所以服务器可以同时处理连接数量受到系统文件描述符数量的限制。如果nginx打开的socket数量超过了文件描述符的数量,那么在error.log文件中会出现too many opened files错误。最大文件打开数可以通过ulimit -n查看。

worker_rlimit_nofile 65535;

        5、accept_mutex

accept_mutex on;

        假设如上文中一样,我们开启了8个工作进程接收请求。当一个新连接到达时,多个Worker将以串行方式来处理,其中有一个Worker会被唤醒,其他的Worker继续保持休眠状态;
        如果没有激活accept_mutex,那么所有的Worker都会被唤醒并争抢这一个请求,但最后只有一个Worker能获取新连接,其它的Worker会重新进入休眠状态,这就是惊群问题。它使服务器的性能下降,因为所有被唤醒的worker进程在重新进入waiting状态前会占用一段CPU时间。
        Nginx默认激活了accept_mutex,也就是说不会有惊群问题。当服务器连接数不多时,开启这个参数会让负载有一定程度的降低(因为不会唤醒多个worker进程)。但是当服务器的吞吐量很大时,为了效率,需要关闭这个参数(串行化的方式不然导致影响速度的降低)。

        6、accept_mutex_delay

        当accept_mutex功能启用后,只有一个持有mutex锁的worker进程会接受并处理请求,其他worker进程等待。accept_mutex_delay指定的时间就是这些worker进程的等待时间,过了等待时间下一个worker进程便取得mutex锁,处理请求。
        accept_mutex_delay在events模块中指定,默认的值为500ms。

accept_mutex_delay 500ms;

        7、multi_accept

        让nginx worker进程尽可能多地接受请求。它的作用是让worker进程一次性地接受监听队列里的所有请求,然后处理。

        如果multi_accept的值设为off,多个worker按并行方式来处理连接,也就是一个连接会唤醒所有的worker,直到连接分配完毕,没有取得连接的继续休眠。

        否则的话,多个worker按串行方式来处理连接,也就是一个连接只有一个worker被唤醒,其他的处于休眠状态,这个工作进程将同时接受所有的新连接。

        默认Nginx没有开启multi_accept(也有说法默认开启,可能存在版本差异)。如果web服务器面对的是一个持续的请求流,那么启用multi_accept可能会造成worker进程一次接受的请求大于worker_connections指定可以接受的请求数。这就是overflow,这个overflow会造成性能损失,overflow这部分的请求不会受到处理。

multi_accept on;

二、I/O配置

        1、epoll

        设置事件驱动模型使用 epoll。epoll 是 Nginx 支持的高性能事件驱动库之一。

use epoll;

        2、Sendfile

        正常情况下,服务端获取文件资源,需要应用程序发起read()指令,操作系统由用户态进入内核态,将文件资源cpoy到内核缓冲区后,再返回给应用程序。然后再由应用程序通过write()指令将文件资源copy到内核态中socket缓冲区,最后返回给客户端浏览器。
        硬盘 >> 内核buffer >> 用户buffer >> 内核socket buffer >> 协议栈

        在上面的情况中,我们发现,获取一次文件资源需要两次由用户态进入内核态,且需需要多次copy文件资源,将其从内核缓存区复制到应用程序缓冲区,再写回内核态中的socket缓冲区。这样的过程无疑是复杂的,Linux为我们提供了sendfile函数来优化整个过程,内核缓冲区直接将文件资源发送给socket缓冲区,避免了再与用户态的2次交互过程。在nginx中可以使用sendfile on来打开该功能。
        用 sendfile()来进行网络传输的过程:
        硬盘 >> 内核 buffer (快速拷贝到 内核socket buffer) >>协议栈

Sendfile on 

        3、directio、directio_alignment

        操作系统内核通常尝试优化和缓存任何读/写请求,但是对于一些较大的数据或者说缓存命中率较差的数据,我们却不期望缓存在高速缓存中,我们应该按需加载。直接I/O就提供这么一个功能,它让应用数据直接从磁盘中进行I/O请求。这样一来能够更好地利用CPU周期和提高缓存命中率。

directio 4m;#任何大于4m的文件将由直接I/O加载。
directio_alignment 512; #设置使用直接I/O数据传输时的块大小,单位为字节。 

三、TCP模块配置

        1、keepalive_timeout

        HTTP底层TCP连接超时时间,HTTP是基于TCP连接的,如果每次HTTP连接都重新建立一次TCP连接,将会造成资源的巨大消耗。我们使用keepalive_timeout设置TCP保持连接的时间,这样就能避免多次创建连接。

keepalive_timeout 60;

        2、tcp_nodelay

        TCP/IP网络有一个“小数据包”的问题,如果一条信息中只有一个字符,那么网络可能会堵塞。这样的数据包大小为41字节,其中TCP信头40字节,内容为1字节。像这种小数据包,它们的开销是4000%。大量的小数据包可以迅速让网络饱和。
        John Nagle发明了Nagle算法,它在一定的时间段,将小数据包暂存,将这些小数据包集合起来,整合为一个数据包发送,在下一个时间段又是如此。这改善了网络传输的效率。时间段通常为200ms。

        TCP_NODELAY可以用来关闭Nagle的缓冲算法,将数据尽快地发送(不需要等待200ms)。        

tcp_nodelay on;

        Nginx可以在http, server, location当中定义

        3、tcp_nopush

        tcp_nopush告诉TCP栈将数据包附加在另外一个数据包,当数据包饱和时或程序明确地指示发送时再发送。Nginx默认启用了tcp_nopush。

tcp_nopush on;

        tcp_nopush和tcp_nopush看起来是'互斥'的,tcp_nodelay可以降低网络延迟,而tcp_nopush可以优化发送的数据包。但实际上同时启用tcp_nopush和sendfile可以确保在传输文件时,内核总是生成最大量的完整TCP数据包以供传输,而最后一个TCP数据包可以是不完整的,这个不完整的数据包tcp_nodelay保证传输送达。

        4、send_timeout

        响应客户端超时时间,这个超时时间仅限于两个活动之间的时间,如果超过这个时间,客户端没有任何活动,nginx关闭连接。

send_timeout 15;

四、Buffer模块

        在接受请求时,nginx提供可以将请求数据写入请求缓存区的功能。这些缓存区的数据可以作为Nginx的变量使用。

        缓存区大小与请求的数据大小相比,若小于请求的数据,则将数据写入磁盘文件中。如果buffer太小,Nginx会不停的写一些临时文件,这样会导致磁盘不停的去读写。

        

        1、client_max_body_size

        默认 1M,表示客户端请求服务器最大允许大小,在“Content-Length”请求头中指定。如果请求的正文数据大于client_max_body_size,HTTP协议会报错 413 Request Entity Too Large。就是说如果请求的正文大于client_max_body_size,一定是失败的。如果需要上传大文件,一定要修改该值。

client_max_body_size 2m;

        2、client_body_buffer_size

        设置请求主体的缓冲区大小,如果请求的数据小于client_body_buffer_size直接将数据先在内存中存储

client_body_buffer_size 10K;

        如果请求的数据小于client_body_buffer_size直接将数据先在内存中存储。如果请求的值大于client_body_buffer_size小于client_max_body_size,就会将数据先存储到临时文件中,默认该路径值是/tmp/,可以由client_body_temp 手动设置,记得给Nginx的用户组设置读写权限。

        如果追求效率,就设置 client_max_body_size 、client_body_buffer_size相同,这样就不会存储临时文件,直接存储在内存了。

        3、client_header_buffer_size

        用于设置客户端请求的请求行+请求头缓冲区大小,大部分情况1KB大小足够,不过由于一般系统分页都要大于1k,所以这里设置为分页大小。分页大小可以用命令getconf PAGESIZE取得。

client_header_buffer_size 4k;

        4、large_client_header_buffers

        该指令规定了用于读取大型客户端请求头的缓冲区的最大数量和大小。如果(请求行+请求头)的大小超过client_header_buffer_size,则以large_client_header_buffers配置为准。

large_client_header_buffers 4 8k;

        请求行(request line)的大小不能超过8k,请求头(request header)中的每一个头部字段的大小不能超过8k,总的(请求行+请求头)的大小不能超过32k(4 * 8k)。当在默认的缓存区不足时按需分配,如果请求转入长连接则释放缓存区。

五、静态文件缓存

        NGINX虽然已经对静态内容做过优化。但在高流量网站的情况下,仍然可以使用open_file_cache进一步提高性能。 NGINX缓存将最近使用的文件描述符和相关元数据(如修改时间,大小等)存储在缓存中。缓存不会存储所请求文件的内容。

        1、open_file_cache

open_file_cache max=65535 inactive=20s;

        max指定缓存数量,建议和打开文件数一致,inactive 是指经过多长时间文件没被请求后删除缓存。

        2、open_file_cache_valid

        检验缓存中元素有效性的频率;默认为60s

open_file_cache_valid 30s;

        3、open_file_cache_min_uses

        NGINX将在非活动时间段之后从高速缓存中清除元素。在非活动时长访问的次数超过了指定次数,则不淘汰;否则淘汰。

open_file_cache_min_uses 4;

六、压缩模块

        开启 gzip 压缩后,nginx 会在返回内容前将内容压缩后返回,可以减少带宽和提高传输速度,给用户更好的体验。但是压缩文件也会消耗 cpu 资源,所以要合理使用。

        查看文件是否 gzip 压缩,直接在浏览器的返回 Response Headers 头中查看是否存在 content-encoding: gzip 参数。

        1、gzip

        开启压缩

gzip on;

        2、gzip_min_length

        设置允许压缩的页面最小字节数,页面字节数从header头的Content-Length中获取,默认值是0,不管页面多大都进行压缩,建议设置成大于1K,如果小与1K可能会越压越大。

gzip_min_length 1k;

        3、gzip_buffers

        压缩缓冲区大小,默认值是申请与原始数据大小相同的内存空间来存储gzip压缩结果。

gzip_buffers     4 32k; 

        表示申请4个单位为32K的内存作为压缩结果流缓存。

        4、gzip_http_version

        压缩版本,用于设置识别HTTP协议版本,默认是1.1,目前大部分浏览器已经支持GZIP解压,使用默认即可。

gzip_http_version 1.1; 

        5、gzip_comp_level

        压缩比例,用来指定GZIP压缩比,1压缩比最小,处理速度最快,9压缩比最大,传输速度快,但是处理慢,也比较消耗CPU资源。

gzip_comp_level 6; 

七、其他

        1、日志优化

        当系统处于负载状态时,启用日志缓冲区可以降低 nginx worker 进程阻塞。大量的磁盘I/O操作和 cpu 消耗对于服务器资源也是一种巨大的消耗,将日志数据缓冲到内存中也是一个优化手段。使用缓冲,nginx 会等缓冲区满了之后一并写入到日志文件中,而不是每次访问都执行一次单独的写操作。

        要启用访问日志缓冲,可以直接在 access_log 配置后面追加配置,涉及到 buffer 和 flush 两个参数。buffer 参数意义是缓冲区的大小,当缓冲区已经写满时,日志会被写入文件中; flush 参数意义是缓冲区内日志在缓冲区内存中保存的最长时间,当缓存中的日志超过最大缓存时间,
也会被写入到文件中, 不足的地方即写入到日志文件的日志有些许延迟,一般即时调试时应当关闭日志缓冲。

access_log /var/log/nginx/access.log main buffer=32k flush=1m;

        经过以上配置之后,当缓冲区中日志超过 32k 或者 超过 1m 时,缓冲区的日志会写入到 access.log 日志文件中。

        2、静态资源优化

        前文介绍了将静态资源在nginx服务器中缓存的配置,我们还可以将静态资源保存到客户端浏览器上进行缓存以减少连接请求,同时关闭静态资源的日志记录减少磁盘I/O。不过可能会导致不能获取到最新的资源。

server {
    # 图片、视频
    location ~ .*\.(gif|jpg|jpeg|png|bmp|swf|flv|mp4|ico)$ {
      expires 30d;   # 将资源缓存30天
      access_log off;  # 关闭日志记录
    }
    # 字体
    location ~ .*\.(eot|ttf|otf|woff|svg)$ {
      expires 30d;
      access_log off;
    }
    # js、css
    location ~ .*\.(js|css)?$ {
      expires 7d;
      access_log off;
    }
}

        3、负载均衡算法

        目前常见的负载均衡算法包含:轮询法、加权轮询法、源地址哈希法、请求地址哈希法、最小连接数法。

        选择适合的负载均衡方案能有效提高系统性能。以请求地址哈希(url_hash)为例,当我们在集群环境下(A、B两台服务器),收到下载请求分发给了服务器A,需要从文件服务器拉取文件到A上,为了省去不必要的网络带宽和下载耗时,在A上做了一层临时缓存(缓存一个月)。后续的下载请求如果被分发到了B服务器上,那么B服务器也会去进行文件下载,这就造成了资源的浪费,我们可以利用url_hash将下载请求固定打到A上,以此来提高缓存命中率。

upstream somestream {
    hash $request_uri;
    server 192.168.244.1:8080;
    server 192.168.244.2:8080;
    server 192.168.244.3:8080;
    server 192.168.244.4:8080;
 
}

八、性能监控

        1、如何使用监控

        我们一般使用第三方的可视化插件nginx-module-vts进行Nginx的流量统计来实现性能监控的效果。安装教程可以看下这里《CentOS 7下Nginx安装配置nginx-module-vts 监控模块》,本文只对该插件的使用做简单介绍。

http {
    vhost_traffic_status_zone;
    server {
        location /status {
                    vhost_traffic_status_display;
                    vhost_traffic_status_display_format html;
        }
    }
}

        在上面的配置中:

vhost_traffic_status_zone:自动开启流量统计模块

vhost_traffic_status_display_format html:以内置的HTML格式的实时仪表板进行响应

        通过以上配置,我们可以通过浏览器打开http://ip:port/status来在线查看Nginx的监控详情。

        2、监控项说明

        2.1、Nginx服务器的基本信息

根据上图可以查询到运行中Nginx的基本信息。 

Version:    Nginx的当前版本
WorkerProcess:    Nginx当前开启用以接受处理用户请求的工作线程数
OSMaxNoFile:    操作系统最大打开文件数
Uptime:    Nginx自上一起启动到现在运行的时间
active:    活跃的连接数量
reading:    读取客户端的连接数
writing:    响应数据到客户端的连接数量
Req/s:    当前每秒的请求数

        2.2、 Nginx服务器处理请求信息统计

Req/s:    当前服务器每秒的请求数
1xx 2xx 3xx 4xx 5xx:    分别针对返回状态是4xx、5xx、2xx等响应的统计信息
Sent Rcvd Sent/s Rcvd/s:    Sent与Rcvd统计Nginx自本次启动后发送与接受请求的流量值,该值的类型是一个累增值。Sent/s与Rcvd/s监控Nginx当前的发送与接受的流量速率。
Hit:    用户发起请求缓存的命中率,该值越大越好。 

        2.3、 根据upstream进行信息统计

 由上图可以知道当前监控的Nginx服务中包含两个upstream。

server:    当前upstream下包含的服务器数量
state:    当前服务器的状态
Req/s:    当前服务器每秒的请求数。
1xx 2xx 3xx 4xx 5xx:    分别针对返回状态是4xx、5xx、2xx等响应的统计信息。
Sent Rcvd Sent/s Rcvd/s:    与上文中一致。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐