1. 程式人生 > >Nginx效能調優

Nginx效能調優

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.wangzb.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核心引數優化方法。

  • 1 net.ipv4.tcp_max_tw_buckets

    對於tcp連線,服務端和客戶端通訊完後狀態變為timewait,假如某臺伺服器非常忙,連線數特別多的話,那麼這個timewait數量就會越來越大。
    畢竟它也是會佔用一定的資源,所以應該有一個最大值,當超過這個值,系統就會刪除最早的連線,這樣始終保持在一個數量級。
    這個數值就是由net.ipv4.tcp_max_tw_buckets這個引數來決定的。
    CentOS7系統,你可以使用sysctl -a |grep tw_buckets來檢視它的值,預設為32768,
    你可以適當把它調低,比如調整到8000,畢竟這個狀態的連線太多也是會消耗資源的。
    但你不要把它調到幾十、幾百這樣,因為這種狀態的tcp連線也是有用的,
    如果同樣的客戶端再次和服務端通訊,就不用再次建立新的連線了,用這個舊的通道,省時省力。
    
    
  • 2 net.ipv4.tcp_tw_recycle = 1

    該引數的作用是快速回收timewait狀態的連線。上面雖然提到系統會自動刪除掉timewait狀態的連線,但如果把這樣的連線重新利用起來豈不是更好。
    所以該引數設定為1就可以讓timewait狀態的連線快速回收,它需要和下面的引數配合一起使用。
    
    
  • 3 net.ipv4.tcp_tw_reuse = 1

    該引數設定為1,將timewait狀態的連線重新用於新的TCP連線,要結合上面的引數一起使用。
    
    
  • 4 net.ipv4.tcp_syncookies = 1

    tcp三次握手中,客戶端向服務端發起syn請求,服務端收到後,也會向客戶端發起syn請求同時連帶ack確認,
    假如客戶端傳送請求後直接斷開和服務端的連線,不接收服務端發起的這個請求,服務端會重試多次,
    這個重試的過程會持續一段時間(通常高於30s),當這種狀態的連線數量非常大時,伺服器會消耗很大的資源,從而造成癱瘓,
    正常的連線進不來,這種惡意的半連線行為其實叫做syn flood攻擊。
    設定為1,是開啟SYN Cookies,開啟後可以避免發生上述的syn flood攻擊。
    開啟該引數後,服務端接收客戶端的ack後,再向客戶端傳送ack+syn之前會要求client在短時間內迴應一個序號,
    如果客戶端不能提供序號或者提供的序號不對則認為該客戶端不合法,於是不會發ack+syn給客戶端,更涉及不到重試。
    
    
  • 5 net.ipv4.tcp_max_syn_backlog

    該引數定義系統能接受的最大半連線狀態的tcp連線數。客戶端向服務端傳送了syn包,服務端收到後,會記錄一下,
    該引數決定最多能記錄幾個這樣的連線。在CentOS7,預設是256,當有syn flood攻擊時,這個數值太小則很容易導致伺服器癱瘓,
    實際上此時伺服器並沒有消耗太多資源(cpu、記憶體等),所以可以適當調大它,比如調整到30000。
    
    
  • 6 net.ipv4.tcp_syn_retries

    該引數適用於客戶端,它定義發起syn的最大重試次數,預設為6,建議改為2。
    
    
  • 7 net.ipv4.tcp_synack_retries

    該引數適用於服務端,它定義發起syn+ack的最大重試次數,預設為5,建議改為2,可以適當預防syn flood攻擊。
    
    
  • 8 net.ipv4.ip_local_port_range

    該引數定義埠範圍,系統預設保留埠為1024及以下,以上部分為自定義埠。這個引數適用於客戶端,
    當客戶端和服務端建立連線時,比如說訪問服務端的80埠,客戶端隨機開啟了一個埠和服務端發起連線,
    這個引數定義隨機埠的範圍。預設為32768    61000,建議調整為1025 61000。
    
    
  • 9 net.ipv4.tcp_fin_timeout

    tcp連線的狀態中,客戶端上有一個是FIN-WAIT-2狀態,它是狀態變遷為timewait前一個狀態。
    該引數定義不屬於任何程序的該連線狀態的超時時間,預設值為60,建議調整為6。
    
    
  • 10 net.ipv4.tcp_keepalive_time

    tcp連線狀態裡,有一個是established狀態,只有在這個狀態下,客戶端和服務端才能通訊。正常情況下,當通訊完畢,
    客戶端或服務端會告訴對方要關閉連線,此時狀態就會變為timewait,如果客戶端沒有告訴服務端,
    並且服務端也沒有告訴客戶端關閉的話(例如,客戶端那邊斷網了),此時需要該引數來判定。
    比如客戶端已經斷網了,但服務端上本次連線的狀態依然是established,服務端為了確認客戶端是否斷網,
    就需要每隔一段時間去發一個探測包去確認一下看看對方是否線上。這個時間就由該引數決定。它的預設值為7200秒,建議設定為30秒。
    
    
  • 11 net.ipv4.tcp_keepalive_intvl

    該引數和上面的引數是一起的,服務端在規定時間內發起了探測,檢視客戶端是否線上,如果客戶端並沒有確認,
    此時服務端還不能認定為對方不線上,而是要嘗試多次。該引數定義重新發送探測的時間,即第一次發現對方有問題後,過多久再次發起探測。
    預設值為75秒,可以改為3秒。
    
    
  • 12 net.ipv4.tcp_keepalive_probes

    第10和第11個引數規定了何時發起探測和探測失敗後再過多久再發起探測,但並沒有定義一共探測幾次才算結束。
    該引數定義發起探測的包的數量。預設為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