Nginx调优

Nginx在部署服务时经常被用到, 大多时候是作为代理使用. 如果用户量比较大就涉及到一些调优, 本文做一些分类记录.

关于Nginx的基础信息见另一篇: Nginx基础

以下部分主要基于两个主要配置文件:nginx.conf和conf.d/default.conf展开.

Worker Processes

# 默认为1, 应更新为一个CPU核心一个worker
# 查看CPU核数 grep ^processor /proc/cpuinfo | wc -l 
worker_processes auto;

# 文件句柄数,默认跟随系统设置
worker_rlimit_nofile 100000;

# 事件驱动部分
events {
# 每个worker允许的连接数, 默认512
  worker_connections 65536;
  use epoll;
  multi_accept on;
}

文件访问优化

日志

  • 访问日志使用缓冲或关闭
  • 如果日志文件路径包含变量,需要打开open_log_file_cache以提高性能
access_log  buffer=size  flush=time

sendfile

三个选项都开启,意味着先填满包,再尽快发送.

  • sendfile: 提供静态资源效率,直接在内核空间完成文件发送。
  • tcp_nopush: 对应Linux的TCP_CORK,数据包会在累计到一定大小后再发送,提高网络效率。与sendfile on结合使用。
  • tcp_nodelay: 另一个socket选项,禁用Nagle算法,尽快发送数据,某些情况节约200ms。Nginx只针对处于keepalive的TCP才启用。
http{
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
}

大文件下载

nginx处理文件传输,默认会在文件发送前先复制到buffer。sendfile允许文件句柄间的直接复制。

  • sendfile_max_chunk: 默认为0,可能造成一直占用worker.
  • aio : 使用异步文件传输线程池
location /mp3 {
  sendfile on;
  tcp_nopush on;
  sendfile_max_chunk 512k;
  aio threads;
}
# aio threads; 是一种简写,等价于:

# in the 'main' context
thread_pool default threads=32 max_queue=65536;
# in the 'http', 'server', or 'location' context
aio threads=default;

使用cache

# 缓存
http{
  
  proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=my_cache:10m max_size=10g inactive=7d use_temp_path=off;

  server{
    
    location ~* \.(apk|png|jpe?g)$ {
      proxy_cache my_cache;
    }
  }
}

其他(待测试)

# 待验证
open_file_cache max=1024 inactive=20s;
open_file_cache_valid 60s;
open_file_cache_min_uses 2;
open_file_cache_errors on;
sendfile off;    # 1. 效果不明显

# 2: CPU占用较高
sendfile on;
directio 10m;

# 3. nginx会把大文件写到磁盘临时文件,禁用cache
location / {
  proxy_max_temp_file_size 0;
}

gzip压缩

多使用缓存和压缩, 但是图片不应该开启压缩.

gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;

连接数优化

Keepalive Connections

  • client保活
  • upstream保活 (后端服务需要支持keepalive)
http {
    proxy_read_timeout 120;    # 可选,默认和上游间60秒超时,适用于http, server, location

    # 以下为upstream保活配置
    upstream minio {
      server 127.0.0.1:9000;
      keepalive 32;    # 每个worker缓存的最大keepalive空闲连接数(到upstream)
      keepalive_requests 102400;    # 可选,默认1000, 一个keep-alive服务的最大请求数,超出后关闭连接
      keepalive_timeout  65;        # 可选,默认60s
    }

    location / {
          # client保活:以下必须设置, 默认响应后会关闭连接
          proxy_http_version 1.1;  # 默认 1.0
          proxy_set_header Connection "";
          proxy_pass http://minio;
    }

}

解决 99: Cannot assign requested address 错误

访问返回502 bad gateway,从error.log可以看到类似错误:

failed (99: Cannot assign requested address) while connecting to upstream

解决方式1: 修改Linux内核参数,开启端口复用

# 开启TCP连接中TIME-WAIT sockets的快速回收
# 及时开启,永久保存需要保存到sysctl.conf
sysctl -w net.ipv4.tcp_tw_recycle=1

解决方式2: 开启nginx和上游的keepalive,参考上一节

限制资源访问

参考官方文档: Limiting Access to Proxied HTTP Resources

限制连接数 - limit_conn_zone

两种方式:

  • 基于ip
  • 基于server_name
limit_conn_zone $binary_remote_addr zone=addr:10m;

location /download/ {
     limit_conn addr 1;
}


http {
    limit_conn_zone $server_name zone=servers:10m;

    server {
        limit_conn servers 1000;
    }
}

限制请求率(并发请求) - limit_req_zone

  • limit_req_zone: 限制单位时间内的请求数,即速率限制,采用的漏桶算法 “leaky bucket”
  • limit_req_conn: 限制同一时间连接数,即并发限制
http {

    limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;

    server {
   
        location /search/ {
            limit_req zone=one;
            
            # 下面语句仅用于本地调试,超过的会记录日志
            limit_req_dry_run on;
            # 用于共享内存满时,增加突发队列,而不是直接返回503
            limit_req zone=one burst=5;
        }
    }
}

限制带宽 - limit_rate

location /download/ {
    limit_conn addr 1;
    limit_rate 50k;
}

扩展阅读

官方文档

调优参考