Nginx 参数调优

lance 2020-04-24 AM 186℃ 0条

Nginx 配置参数优化

Nginx 作为高性能 web 服务器,即使不特意调整配置参数也可以处理大量的并发请求。
以下的配置参数是借鉴网上的一些调优参数,仅作为参考,不见得适于你的线上业务。

worker 进程

  • worker_processes
该参数表示启动几个工作进程,建议和本机 CPU 核数保持一致,每一核 CPU 处理一个进程。
  • worker_rlimit_nofile
它表示 Nginx 最大可用的文件描述符个数,需要配合系统的最大描述符,建议设置为 102400。
还需要在系统里执行 ulimit -n 102400 才可以。
也可以直接修改配置文件 /etc/security/limits.conf 修改
增加:
* soft nofile 655350
* hard nofile 655350
  • worker_connections
该参数用来配置每个 Nginx worker 进程最大处理的连接数,这个参数也决定了该 Nginx 服务器最多能处理多少客户端请求
(worker_processes * worker_connections),建议把该参数设置为 10240,不建议太大。

http 和 tcp 连接

  • use epoll
使用 epoll 模式的事件驱动模型,该模型为 Linux 系统下最优方式。
  • multi_accept on
使每个 worker 进程可以同时处理多个客户端请求。
  • sendfile on
使用内核的 FD 文件传输功能,可以减少 user mode 和 kernel mode 的切换,从而提升服务器性能。
  • tcp_nopush on
当 tcp_nopush 设置为 on 时,会调用 tcp_cork 方法进行数据传输。
使用该方法会产生这样的效果:当应用程序产生数据时,内核不会立马封装包,而是当数据量积累到一定量时才会封装,然后传输。
  • tcp_nodelay on
不缓存 data-sends(关闭 Nagle 算法),这个能够提高高频发送小数据报文的实时性。
(关于 Nagle 算法)
【假如需要频繁的发送一些小包数据,比如说 1 个字节,以 IPv4 为例的话,则每个包都要附带 40 字节的头,
也就是说,总计 41 个字节的数据里,其中只有 1 个字节是我们需要的数据。
为了解决这个问题,出现了 Nagle 算法。
它规定:如果包的大小满足 MSS,那么可以立即发送,否则数据会被放到缓冲区,等到已经发送的包被确认了之后才能继续发送。
通过这样的规定,可以降低网络里小包的数量,从而提升网络性能。】
  • keepalive_timeout
定义长连接的超时时间,建议 30s,太短或者太长都不一定合适,当然,最好是根据业务自身的情况来动态地调整该参数。
  • keepalive_requests
定义当客户端和服务端处于长连接的情况下,每个客户端最多可以请求多少次,可以设置很大,比如 50000.
  • reset_timeout_connection on
设置为 on 的话,当客户端不再向服务端发送请求时,允许服务端关闭该连接。
  • client_body_timeout
客户端如果在该指定时间内没有加载完 body 数据,则断开连接,单位是秒,默认 60,可以设置为 10。
  • send_timeout
这个超时时间是发送响应的超时时间,即 Nginx 服务器向客户端发送了数据包,但客户端一直没有去接收这个数据包。
如果某个连接超过 send_timeout 定义的超时时间,那么 Nginx 将会关闭这个连接。单位是秒,可以设置为 3。

buffer 和 cache(以下配置都是针对单个请求)

  • client_body_buffer_size
当客户端以 POST 方法提交一些数据到服务端时,会先写入到 client_body_buffer 中,如果 buffer 写满会写到临时文件里,建议调整为 128k。
  • client_max_body_size
浏览器在发送含有较大 HTTP body 的请求时,其头部会有一个 Content-Length 字段,client_max_body_size 是用来限制 Content-Length 所示值的大小的。
这个限制 body 的配置不用等 Nginx 接收完所有的 HTTP 包体,就可以告诉用户请求过大不被接受。会返回 413 状态码。
例如,用户试图上传一个 1GB 的文件,Nginx 在收完包头后,发现 Content-Length 超过 client_max_body_size 定义的值,
就直接发送 413(Request Entity Too Large) 响应给客户端。
将该数值设置为 0,则禁用限制,建议设置为 10m。
  • client_header_buffer_size
设置客户端 header 的 buffer 大小,建议 4k。
  • large_client_header_buffers
对于比较大的 header(超过 client_header_buffer_size)将会使用该部分 buffer,两个数值,第一个是个数,第二个是每个 buffer 的大小。
建议设置为 4 8k
  • open_file_cache
该参数会对以下信息进行缓存:
打开文件描述符的文件大小和修改时间信息;
存在的目录信息;
搜索文件的错误信息(文件不存在无权限读取等信息)。
格式:open_file_cache max=size inactive=time;
max 设定缓存文件的数量,inactive 设定经过多长时间文件没被请求后删除缓存。
建议设置 open_file_cache max=102400 inactive=20s;
  • open_file_cache_valid
指多长时间检查一次缓存的有效信息。建议设置为 30s。
  • open_file_cache_min_uses
open_file_cache 指令中的 inactive 参数时间内文件的最少使用次数,
如,将该参数设置为 1,则表示,如果文件在 inactive 时间内一次都没被使用,它将被移除。
建议设置为 2。

压缩

对于纯文本的内容,Nginx 是可以使用 gzip 压缩的。使用压缩技术可以减少对带宽的消耗。
由 ngx_http_gzip_module 模块支持

配置如下:
gzip on; 
# 开启 gzip 功能
gzip_min_length 1024; 
# 设置请求资源超过该数值才进行压缩,单位字节
gzip_buffers 16 8k; 
# 设置压缩使用的 buffer 大小,第一个数字为数量,第二个为每个 buffer 的大小
gzip_comp_level 6; 
# 设置压缩级别,范围 1-9,9 压缩级别最高,也最耗费 CPU 资源
gzip_types text/plain application/x-javascript text/css application/xml image/jpeg image/gif image/png; 
# 指定哪些类型的文件需要压缩
gzip_disable "MSIE 6\."; 
# IE6 浏览器不启用压缩

测试:
curl -I -H "Accept-Encoding: gzip, deflate" http://www.alinux.com/1.css

日志

  • 错误日志级别调高,比如 crit 级别,尽量少记录无关紧要的日志。
  • 对于访问日志,如果不要求记录日志,可以关闭,
  • 静态资源的访问日志关闭

静态文件过期

对于静态文件,需要设置一个过期时间,这样可以让这些资源缓存到客户端浏览器,
在缓存未失效前,客户端不再向服务期请求相同的资源,从而节省带宽和资源消耗。

配置示例如下:
location ~* ^.+\.(gif|jpg|png|css|js)$                                      
{
    expires 1d; 
    # 1d 表示 1 天,也可以用 24h 表示一天。
}

作为代理服务器

Nginx 绝大多数情况下都是作为代理或者负载均衡的角色。
因为前面章节已经介绍过以下参数的含义,在这里只提供对应的配置参数:
http
{
    proxy_cache_path /data/nginx_cache/ levels=1:2 keys_zone=my_zone:10m inactive=300s max_size=5g;
    ...;
    server
    {
    proxy_buffering on;
    proxy_buffer_size 4k;
    proxy_buffers 2 4k;
    proxy_busy_buffers_size 4k;
    proxy_temp_path /tmp/nginx_proxy_tmp 1 2;
    proxy_max_temp_file_size 20M;
    proxy_temp_file_write_size 8k;

    location /
    {
        proxy_cache my_zone;
        ...;
    }
    }
}

SSL 优化

  • 适当减少 worker_processes 数量,因为 ssl 功能需要使用 CPU 的计算。
  • 使用长连接,因为每次建立 ssl 会话,都会耗费一定的资源(加密、解密)
  • 开启 ssl 缓存,简化服务端和客户端的“握手”过程。
ssl_session_cache   shared:SSL:10m;
# 缓存为 10M
ssl_session_timeout 10m;
# 会话超时时间为 10 分钟

调整 Linux 内核参数

作为高性能 WEB 服务器,只调整 Nginx 本身的参数是不行的,因为 Nginx 服务依赖于高性能的操作系统。
以下为常见的几个 Linux 内核参数优化方法。
  • net.ipv4.tcp_max_tw_buckets
对于 tcp 连接,服务端和客户端通信完后状态变为 timewait,假如某台服务器非常忙,连接数特别多的话,那么这个 timewait 数量就会越来越大。
毕竟它也是会占用一定的资源,所以应该有一个最大值,当超过这个值,系统就会删除最早的连接,这样始终保持在一个数量级。
这个数值就是由 net.ipv4.tcp_max_tw_buckets 这个参数来决定的。
CentOS7 系统,你可以使用 sysctl -a |grep tw_buckets 来查看它的值,默认为 32768,
你可以适当把它调低,比如调整到 8000,毕竟这个状态的连接太多也是会消耗资源的。
但你不要把它调到几十、几百这样,因为这种状态的 tcp 连接也是有用的,
如果同样的客户端再次和服务端通信,就不用再次建立新的连接了,用这个旧的通道,省时省力。

可以用 ss -an | wc -l 看当前连接数量
  • net.ipv4.tcp_tw_recycle = 1
该参数的作用是快速回收 timewait 状态的连接。上面虽然提到系统会自动删除掉 timewait 状态的连接,但如果把这样的连接重新利用起来岂不是更好。
所以该参数设置为 1 就可以让 timewait 状态的连接快速回收,它需要和下面的参数配合一起使用。
  • net.ipv4.tcp_tw_reuse = 1
该参数设置为 1,将 timewait 状态的连接重新用于新的 TCP 连接,要结合上面的参数一起使用。
  • net.ipv4.tcp_syncookies = 1
tcp 三次握手中,客户端向服务端发起 syn 请求,服务端收到后,也会向客户端发起 syn 请求同时连带 ack 确认,
假如客户端发送请求后直接断开和服务端的连接,不接收服务端发起的这个请求,服务端会重试多次,这个重试的过程会持续一段时间(通常高于 30s),当这种状态的连接数量非常大时,服务器会消耗很大的资源,从而造成瘫痪,
正常的连接进不来,这种恶意的半连接行为其实叫做 syn flood 攻击。
设置为 1,是开启 SYN Cookies,开启后可以避免发生上述的 syn flood 攻击。
开启该参数后,服务端接收客户端的 ack 后,再向客户端发送 ack+syn 之前会要求 client 在短时间内回应一个序号,如果客户端不能提供序号或者提供的序号不对则认为该客户端不合法,于是不会发 ack+syn 给客户端,更涉及不到重试。
  • net.ipv4.tcp_max_syn_backlog
该参数定义系统能接受的最大半连接状态的 tcp 连接数。客户端向服务端发送了 syn 包,服务端收到后,会记录一下,
该参数决定最多能记录几个这样的连接。在 CentOS7,默认是 256,当有 syn flood 攻击时,这个数值太小则很容易导致服务器瘫痪,
实际上此时服务器并没有消耗太多资源(cpu、内存等),所以可以适当调大它,比如调整到 30000。
  • net.ipv4.tcp_syn_retries
该参数适用于客户端,它定义发起 syn 的最大重试次数,默认为 6,建议改为 2。
  • net.ipv4.tcp_synack_retries
该参数适用于服务端,它定义发起 syn+ack 的最大重试次数,默认为 5,建议改为 2,可以适当预防 syn flood 攻击。
  • net.ipv4.ip_local_port_range
该参数定义端口范围,系统默认保留端口为 1024 及以下,以上部分为自定义端口。这个参数适用于客户端,
当客户端和服务端建立连接时,比如说访问服务端的 80 端口,客户端随机开启了一个端口和服务端发起连接,
这个参数定义随机端口的范围。默认为 32768 61000,建议调整为 1025 61000。
  • net.ipv4.tcp_fin_timeout
tcp 连接的状态中,客户端上有一个是 FIN-WAIT-2 状态,它是状态变迁为 timewait 前一个状态。
该参数定义不属于任何进程的该连接状态的超时时间,默认值为 60,建议调整为 6。
  • net.ipv4.tcp_keepalive_time
tcp 连接状态里,有一个是 established 状态,只有在这个状态下,客户端和服务端才能通信。正常情况下,当通信完毕,
客户端或服务端会告诉对方要关闭连接,此时状态就会变为 timewait,如果客户端没有告诉服务端,
并且服务端也没有告诉客户端关闭的话(例如,客户端那边断网了),此时需要该参数来判定。
比如客户端已经断网了,但服务端上本次连接的状态依然是 established,服务端为了确认客户端是否断网,
就需要每隔一段时间去发一个探测包去确认一下看看对方是否在线。这个时间就由该参数决定。它的默认值为 7200 秒,建议设置为 30 秒。
  • net.ipv4.tcp_keepalive_intvl
该参数和上面的参数是一起的,服务端在规定时间内发起了探测,查看客户端是否在线,如果客户端并没有确认,此时服务端还不能认定为对方不在线,而是要尝试多次。该参数定义重新发送探测的时间,即第一次发现对方有问题后,过多久再次发起探测。
默认值为 75 秒,可以改为 3 秒。
  • net.ipv4.tcp_keepalive_probes
net.ipv4.tcp_keepalive_time 和 net.ipv4.tcp_keepalive_intvl 参数规定了何时发起探测和探测失败后再过多久再发起探测,但并没有定义一共探测几次才算结束。
该参数定义发起探测的包的数量。默认为 9,建议设置 2。

设置和范例

在 Linux 下调整内核参数,可以直接编辑配置文件 /etc/sysctl.conf,然后执行 sysctl -p 命令生效

结合以上分析的各内核参数,范例如下

net.ipv4.tcp_fin_timeout = 6
net.ipv4.tcp_keepalive_time = 30
net.ipv4.tcp_max_tw_buckets = 8000
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 30000
net.ipv4.tcp_syn_retries = 2
net.ipv4.tcp_synack_retries = 2
net.ipv4.ip_local_port_range = 1025 61000
net.ipv4.tcp_keepalive_intvl = 3
net.ipv4.tcp_keepalive_probes = 2

标签: linux, nginx, optimize

非特殊说明,本博所有文章均为博主原创。

觉得文章不错,打赏一点吧,1分也是爱😀

WeChat Pay

微信打赏

Alipay

支付宝打赏

评论啦~