Nginx配置優化

操控 Nginx 的命令其實並不多,撐控 Nginx 的核心是他的配置文件,為 Nginx 進行合理的配置能更大化發揮 Nginx 的能力,使應用表現更佳。

下面是從官網整理一些常用的或有助于提升性能的配置,部分內容撰自《Nginx配置优化指南》 一文。

MAIN环境

1
2
3
4
user  nginx;
worker_processes auto;
worker_rlimit_nofile 100000;
pid logs/nginx.pid;

worker_processes

  • 語法:worker_processes number | auto
  • 默認:worker_processes 1

定義進程數量,最優值由許多因素決定,包括(但不限於)CUP 核數、用於存儲數據的硬盤數量以及負載模式,不能確定的時候,將其設置為可用的 CUP 內核數將是一個好的開始,『auto』參數將嘗試自動檢測,『auto』參數從 1.3.8 和 1.2.5 才開始支持

worker_rlimit_nofile

  • 語法:worker_rlimit_nofile number
  • 默認:–

改變 work 進程最大打開文件數量上限,在不重啟主程序的情況下可用於提高上限值。如果沒有設置此值的話,系統會有一個默認限制值,用 ulimit -a 命令可以查看:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
core file size          (blocks, -c) 0
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 0
file size (blocks, -f) unlimited
pending signals (-i) 7812
max locked memory (kbytes, -l) 64
max memory size (kbytes, -m) unlimited
open files (-n) 65535
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200
real-time priority (-r) 0
stack size (kbytes, -s) 8192
cpu time (seconds, -t) unlimited
max user processes (-u) 7812
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited

可以看到此處的 open files 限制數量為 65535,設置更高的值後 nginx 就不會有too many open files問題了

user

  • 語法:user user [group](如果 [group] 參數缺省,用戶組的名字等於 user 參數所在的用戶組)
  • 默認:user nobody nobody

定義具備使用該進程資格的用戶和用戶組

pid

  • 語法:pid file
  • 默認:pid nginx.pid

定義存儲主進程 ID 的文件

EVEVTS环境

1
2
3
4
5
events {
worker_connections 2048;
multi_accept on;
use epoll;
}

worker_connections

  • 語法:worker_connections number
  • 默認:worker_connections 512;

設置可以被一個工作進程同時打開的最大連接數,這些連接數包含所有連接數,不僅僅是客戶端的,還有代理服務器的以及其他的。

值得注意的是,實際的並發連接數並不能超過 open_files 的最大限制數量,因此更變 worker_rlimit_nofile 的值我們就可以將 worker_connections 設得很高

multi_accept

  • 語法:multi_accept on | off
  • 默認:multi_accept off;

如果 multi\_accept 沒有開啟,一個工作進程在同一時間將會接受一個新的連接,否則一個工作進程在同一時間將會接受所有新的連接

use

  • 語法:use method
  • 默認:–

定義使用連接處理的方式,Nginx 支持多樣的連接處理方式,適合的連接處理方式由使用的平台決定,epoll 是使用在系統 Linux 2.6+ 的高效方式,通常沒有必要明確指定,Nginx 會默認使用最高效的方式,如果要特定指定某種方式,則可以使用該命令。

想了解更多連接處理方式,可以參考 connection processing

HTTP/SERVER/LOCATION環境

1
server_tokens off;

server_tokens

  • 語法:server_tokens on | off | string;
  • 默認:server_tokens on;

在錯誤信息(404頁面)或響應頭『Server』字段中是否展示 Nginx 版本號,考慮安全性,建議隱藏掉

另外,在 Nginx 商業版本中,從 1.9.13 版本開始,通過 string 參數可以定制簽名,非商業版設置的話,會提示配置出錯

1
2
3
sendfile        on;
tcp_nopush on;
#tcp_nodelay on;

sendfile

  • 語法:sendfile on | off
  • 默認:sendfile off;

是否啟動 sendfile(),簡單的理解就是在內核完成文件之間的數據傳送,沒有上下文切換開支,比read()write()更快

tcp_nopush

  • 語法:tcp_nopush on | off;
  • 默認:tcp_nopush off;

是否在 FreeBSD 系統使用 TCP_NOPUSH 套接字或在 Linux 系統使用 TCP_CORK 套接字選項,開啟該選項可以讓請求頭等信息放在一個數據包,等到達數據包最大量的時候才發送,這樣可以有助解決網絡阻塞的問題,只有在 sendfile 開啟的時候才起作用

tcp_nodelay

  • 語法:tcp_nodelay on | off;
  • 默認:tcp_nodelay on;

不緩衝發送數據,只有當連接轉換到 keep-alive 狀態的時候這個選項才起效,現已默認開啟,不用明確寫在配置文件也行了

1
2
access_log off;
error_log logs/error.log crit;

access_log

  • 語法:
    • access_log path [format [buffer=size] [gzip[=level]] [flush=time] [if=condition]];
    • access_log off;
  • 默認:access_log logs/access.log combined;

access_log會設置緩衝日誌的寫入,啟動後會產生很多日誌的寫入與刪除等操作,明顯佔用了系統的資源,關閉後會在所處層級取消所有緩衝日誌。更多信息可以參考 access_log

error_log

  • 語法:error_log file [level];
    • file:定義存放日誌的文件
    • level:日誌的記錄級別,可以是以下的其中一個:debug, info, notice, warn, error, crit, alert, 或 emerg,這些記錄級別按照嚴重性依次增加,若指定某一級別,則該級別以及比其更嚴重的級別日誌將會記錄,如指定 error,將會記錄 error, crit, alertemerg 所有相關日誌
  • 默認:error_log logs/error.log error;

error 信息通常比較容易產生,也比較多,因此我們指定 crit 級別,只記錄嚴重的錯誤日誌。

1
2
3
4
5
keepalive_timeout 30;
client_header_timeout 10;
client_body_timeout 10;
reset_timedout_connection on;
send_timeout 10;

keepalive_timeout

  • 語法:keepalive_timeout timeout [header_timeout];
  • 默認:keepalive_timeout 75s;

設置 keepalive 的超時時間,當設置為 0 的時候,關閉 keepalive 連接。一般的應用,30s的連接時間足以滿足 keepalive 連接傳輸的請求數據了,沒有必要用默認的 75s。

client_body_timeout

  • 語法:client_body_timeout time;
  • 默認:client_body_timeout 60s;

定義讀取客戶端請求主體的超時時間。這個時間只在兩個成功的讀操作期間被設置,而不在傳輸過程的全部請求主體,如果客戶端在這段時間內沒有傳送任何東西,服務端會返回 408(請求超時)錯誤。

client_header_timeout

  • 語法:client_header_timeout time;
  • 默認:client_header_timeout 60s;

定義讀取客戶端請求頭的超時時間。這個時間只在兩個成功的讀操作期間被設置,如果客戶端在這段時間內沒有傳送完請求頭的全部信息,服務端會返回 408(請求超時)錯誤。

reset_timedout_connection

  • 語法:reset_timedout_connection on | off;
  • 默認:reset_timedout_connection off;

是否重置超時連接,啟用該重置將表現如下:在某個套接字關閉前,SO_LINGER選項會被設置一個為0的超時時間值,當這個套接字關閉後,TCP RST會被發送到客戶端,所有被該套接字佔用的內存將會被釋放,這有助避免已經關閉的並處於 FIN_WAIT1 狀態和佔用內存資源的套接字保留過長時間。

簡單理解就是允許關閉沒有響應的卻佔有內存資源的客戶端連接,有助釋放內存。

send_timeout

  • 語法:send_timeout time;
  • 默認:send_timeout 60s;

設置服務端響應客戶端的超時時間。這個時間只在兩個成功的寫操作期間被設置,而不在傳輸過程的全部請求,如果客戶端在這段時間內沒有接受到任何東西,連接將會被關閉。

1
2
limit_conn_zone $binary_remote_addr zone=addr:5m;
limit_req_zone $binary_remote_addr zone=req_limit_per_ip:10m rate=5r/s;

limit_conn_zone

  • 語法:limit_conn_zone key zone=name:size;;
  • 默認:–

限制每個 IP 的連接數量。詳情請看 limit_conn_zone

limit_req_zone

  • 語法:limit_req_zone key zone=name:size rate=rate;;
  • 默認:–

限制一個會話的請求數量。詳情請看 limit_req_zone

1
2
3
4
5
6
gzip  on;
gzip_disable "msie6";
gzip_proxied expired no-cache no-store private auth;
gzip_min_length 10240;
gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/json application/xml;
gzip_comp_level 4;

大量減小傳輸數據的體積。詳情請看 Module ngx_http_gzip_module

gzip

  • 語法:gzip on | off;
  • 默認:gzip off;

告诉nginx采用gzip压缩的形式发送数据

gzip_disable

  • 語法:gzip_disable regex …;
  • 默認:–

为指定的客户端禁用gzip功能。我们设置成IE6或者更低版本以使我们的方案能够广泛兼容。

gzip_proxied

  • 語法:gzip_proxied off | expired | no-cache | no-store | private | no_last_modified | no_etag | auth | any …;
  • 默認:gzip_proxied off

允许或者禁止压缩基于请求和响应的响应流。我们设置为any,意味着将会压缩所有的请求

gzip_min_length

  • 語法:gzip_min_length length;
  • 默認:gzip_min_length 20;

设置对数据启用压缩的最少字节数。如果一个请求小于1000字节,我们最好不要压缩它,因为压缩这些小的数据会降低处理此请求的所有进程的速度。

gzip_types

  • 語法:gzip_types mime-type …;
  • 默認:gzip_types text/html;

设置需要压缩的数据格式。

gzip_comp_level

  • 語法:gzip_comp_level level;
  • 默認:gzip_comp_level 1;

设置数据的压缩等级。这个等级可以是1-9之间的任意数值,9是最慢但是压缩比最大的。我们设置为4,这是一个比较折中的设置。

1
2
3
4
open_file_cache max=200000 inactive=20s;
open_file_cache_valid 30s;
open_file_cache_min_uses 2;
open_file_cache_errors on;

open_file_cache

  • 語法:
    • open_file_cache off;
    • open_file_cache max=N [inactive=time];
  • 默認:open_file_cache off;

打开缓存的同时也指定了缓存最大数目,以及缓存的时间。我们可以设置一个相对高的最大时间,这样我们可以在它们不活动超过20秒后清除掉

open_file_cache_valid

  • 語法:open_file_cache_valid time;
  • 默認:open_file_cache_valid 60s;

open_file_cache 中指定检测正确信息的间隔时间。

open_file_cache_min_uses

  • 語法:open_file_cache_min_uses number;
  • 默認:open_file_cache_min_uses 1;

定义了 open_file_cache 中指令参数不活动时间期间里最小的文件数。

open_file_cache_errors

  • 語法:open_file_cache_errors on | off;
  • 默認:open_file_cache_errors off;

指定了当搜索一个文件时是否缓存错误信息,也包括再次给配置中添加文件。我们也包括了服务器模块,这些是在不同文件中定义的。如果你的服务器模块不在这些位置,你就得修改这一行来指定正确的位置。

最後完整的配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
worker_processes  auto;
worker_rlimit_nofile 100000;
user nginx;
pid logs/nginx.pid;
error_log logs/error.log crit;

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

http {
#...

include mime.types;
default_type application/octet-stream;

server_tokens off;

sendfile on;
tcp_nopush on;
tcp_nodelay on;

access_log off;

keepalive_timeout 30;
client_header_timeout 10;
client_body_timeout 10;
reset_timedout_connection on;
send_timeout 10;

limit_conn_zone $binary_remote_addr zone=addr:10m;

gzip on;
gzip_disable "msie6";
gzip_proxied expired no-cache no-store private auth;
gzip_min_length 10240;
gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/json application/xml;
gzip_comp_level 4;

open_file_cache max=200000 inactive=20s;
open_file_cache_valid 30s;
open_file_cache_min_uses 2;
open_file_cache_errors on;

#...
}