一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

Nginx 配置之性能篇

 BENpudding 2015-11-26



在介紹完我博客(imququ.com)的 Nginx 配置中與安全有關的一些配置后,這篇文章繼續(xù)介紹與性能有關的一些配置。WEB 性能優(yōu)化是一個系統(tǒng)工程,涵蓋很多方面,做好其中某個環(huán)節(jié)并不意味性能就能變好,但可以肯定地說,如果某個環(huán)節(jié)做得很糟糕,那么結果一定會變差。

首先說明下,本文提到的一些 Nginx 配置,需要較高版本 Linux 內核才支持。在實際生產(chǎn)環(huán)境中,升級服務器內核并不是一件容易的事,但為了獲得最好的性能,有些升級還是必須的。很多公司服務器運維和項目開發(fā)并不在一個團隊,一方追求穩(wěn)定不出事故,另一方希望提升性能,本來就是矛盾的。好在我們折騰自己 VPS 時,可以無視這些限制。


TCP 優(yōu)化


Nginx 關于 TCP 的優(yōu)化基本都是修改系統(tǒng)內核提供的配置項,所以跟具體的 Linux 版本和系統(tǒng)配置有關,我對這一塊還不是非常熟悉,這里只能簡單介紹下:


http {

sendfile on;

tcp_nopush on;

tcp_nodelay on;

keepalive_timeout 60;

... ...

}


第一行的 sendfile 配置可以提高 Nginx 靜態(tài)資源托管效率。sendfile 是一個系統(tǒng)調用,直接在內核空間完成文件發(fā)送,不需要先 read 再 write,沒有上下文切換開銷。


TCP_NOPUSH 是 FreeBSD 的一個 socket 選項,對應 Linux 的 TCP_CORK,Nginx 里統(tǒng)一用 tcp_nopush 來控制它,并且只有在啟用了 sendfile 之后才生效。啟用它之后,數(shù)據(jù)包會累計到一定大小之后才會發(fā)送,減小了額外開銷,提高網(wǎng)絡效率。


TCP_NODELAY 也是一個 socket 選項,啟用后會禁用 Nagle 算法,盡快發(fā)送數(shù)據(jù),可以節(jié)約 200ms。Nginx 只會針對處于 keep-alive 狀態(tài)的 TCP 連接才會啟用 tcp_nodelay。


可以看到 TCP_NOPUSH 是要等數(shù)據(jù)包累積到一定大小才發(fā)送,TCP_NODELAY 是要盡快發(fā)送,二者相互矛盾。實際上,它們確實可以一起用,最終的效果是先填滿包,再盡快發(fā)送。


關于這部分內容的更多介紹可以看這篇文章:NGINX OPTIMIZATION: UNDERSTANDING SENDFILE, TCP_NODELAY AND TCP_NOPUSH。


配置最后一行用來指定服務端為每個 TCP 連接最多可以保持多長時間。Nginx 的默認值是 75 秒,有些瀏覽器最多只保持 60 秒,所以我統(tǒng)一設置為 60。


另外,還有一個 TCP 優(yōu)化策略叫 TCP Fast Open(TFO),這里先介紹下,配置在后面貼出。TFO 的作用是用來優(yōu)化 TCP 握手過程??蛻舳说谝淮谓⑦B接還是要走三次握手,所不同的是客戶端在第一個 SYN 會設置一個 Fast Open 標識,服務端會生成 Fast Open Cookie 并放在 SYN-ACK 里,然后客戶端就可以把這個 Cookie 存起來供之后的 SYN 用。下面這個圖形象地描述了這個過程:



關于 TCP Fast Open 的更多信息,可以查看 RFC7413,或者這篇文章:Shaving your RTT with TCP Fast Open。需要注意的是,現(xiàn)階段只有 Linux、ChromeOS 和 Android 5.0 的 Chrome / Chromium 才支持 TFO,所以實際用途并不大。


5 月 26 日發(fā)布的 Nginx 1.9.1,增加了 reuseport 功能,意味著 Nginx 也開始支持 TCP 的 SO_REUSEPORT 選項了。這里也先簡單介紹下,具體配置方法后面統(tǒng)一介紹。啟用這個功能后,Nginx 會在指定的端口上監(jiān)聽多個 socket,每個 Worker 都能分到一個。請求過來時,系統(tǒng)內核會自動通過不同的 socket 分配給對應的 Worker,相比之前的單 socket 多 Worker 的模式,提高了分發(fā)效率。下面這個圖形象地描述了這個過程:



有關這部分內容的更多信息,可以查看 Nginx 的官方博客:Socket Sharding in NGINX Release 1.9.1。


開啟 Gzip


我們在上線前,代碼(JS、CSS 和 HTML)會做壓縮,圖片也會做壓縮(PNGOUT、Pngcrush、JpegOptim、Gifsicle 等)。對于文本文件,在服務端發(fā)送響應之前進行 GZip 壓縮也很重要,通常壓縮后的文本大小會減小到原來的 1/4 - 1/3。下面是我的配置:


http {

gzip on;

gzip_vary on;

gzip_comp_level 6;

gzip_buffers 16 8k;

gzip_min_length 1000;

gzip_proxied any;

gzip_disable 'msie6';

gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript;

... ...

}


這部分內容比較簡單,只有兩個地方需要解釋下:

gzip_vary 用來輸出 Vary 響應頭,用來解決某些緩存服務的一個問題,詳情請看我之前的博客:HTTP 協(xié)議中 Vary 的一些研究。


gzip_disable 指令接受一個正則表達式,當請求頭中的 UserAgent 字段滿足這個正則時,響應不會啟用 GZip,這是為了解決在某些瀏覽器啟用 GZip 帶來的問題。特別地,指令值 msie6 等價于 MSIE [4-6]\.,但性能更好一些。另外,Nginx 0.8.11 后,msie6 并不會匹配 UA 包含 SV1 的 IE6(例如 Windows XP SP2 上的 IE6),因為這個版本的 IE6 已經(jīng)修復了關于 GZip 的若干 Bug。


開啟緩存


優(yōu)化代碼邏輯的極限是移除所有邏輯;優(yōu)化請求的極限是不發(fā)送任何請求。這兩點通過緩存都可以實現(xiàn)。


服務端


我的博客更新并不頻繁,評論部分也早就換成了 Disqus,所以完全可以將頁面靜態(tài)化,這樣就省掉了所有代碼邏輯和數(shù)據(jù)庫開銷。實現(xiàn)靜態(tài)化有很多種方案,我直接用的是 Nginx 的 proxy_cache(注:本博客為了做更精細的靜態(tài)化,已經(jīng)將緩存邏輯挪到 Web 應用里實現(xiàn)了):


proxy_cache_path /home/jerry/cache/nginx/proxy_cache_path levels=1:2 keys_zone=pnc:300m inactive=7d max_size=10g;

proxy_temp_path /home/jerry/cache/nginx/proxy_temp_path;

proxy_cache_key $host$uri$is_args$args;

server {

location / {

resolver 127.0.0.1;

proxy_cache pnc;

proxy_cache_valid 200 304 2h;

proxy_cache_lock on;

proxy_cache_lock_timeout 5s;

proxy_cache_use_stale updating error timeout invalid_header http_500 http_502;

proxy_http_version 1.1;

proxy_ignore_headers Set-Cookie;

... ...

}

... ...

}


首先,在配置最外層定義一個緩存目錄,并指定名稱(keys_zone)和其他屬性,這樣在配置 proxy_pass 時,就可以使用這個緩存了。這里我對狀態(tài)值等于 200 和 304 的響應緩存了 2 小時。


默認情況下,如果響應頭里有 Set-Cookie 字段,Nginx 并不會緩存這次響應,因為它認為這次響應的內容是因人而異的。我的博客中,這個 Set-Cookie 對于用戶來說沒有用,也不會影響輸出內容,所以我通過配置 proxy_ignore_header 移除了它。


客戶端


服務端在輸出響應時,可以通過響應頭輸出一些與緩存有關的信息,從而達到少發(fā)或不發(fā)請求的目的。HTTP/1.1 的緩存機制稍微有點復雜,這里簡單介紹下:


首先,服務端可以通過響應頭里的 Last-Modified(最后修改時間) 或者 ETag(內容特征) 標記實體。瀏覽器會存下這些標記,并在下次請求時帶上 If-Modified-Since: 上次 Last-Modified 的內容If-None-Match: 上次 ETag 的內容,詢問服務端資源是否過期。如果服務端發(fā)現(xiàn)并沒有過期,直接返回一個狀態(tài)碼為 304、正文為空的響應,告知瀏覽器使用本地緩存;如果資源有更新,服務端返回狀態(tài)碼 200、新的 Last-Modified、Etag 和正文。這個過程被稱之為 HTTP 的協(xié)商緩存,通常也叫做弱緩存。


可以看到協(xié)商緩存并不會節(jié)省連接數(shù),但是在緩存生效時,會大幅減小傳輸內容(304 響應沒有正文,一般只有幾百字節(jié))。另外為什么有兩個響應頭都可以用來實現(xiàn)協(xié)商緩存呢?這是因為一開始用的 Last-Modified 有兩個問題:

1)只能精確到秒,1 秒內的多次變化反映不出來;

2)時間采用絕對值,如果服務端 / 客戶端時間不對都可能導致緩存失效 在輪詢的負載均衡算法中,如果各機器讀到的文件修改時間不一致,有緩存無故失效和緩存不更新的風險。HTTP/1.1 并沒有規(guī)定 ETag 的生成規(guī)則,而一般實現(xiàn)者都是對資源內容做摘要,能解決前面兩個問題。


另外一種緩存機制是服務端通過響應頭告訴瀏覽器,在什么時間之前(Expires)或在多長時間之內(Cache-Control: Max-age=xxx),不要再請求服務器了。這個機制我們通常稱之為 HTTP 的強緩存。


一旦資源命中強緩存規(guī)則后,再次訪問完全沒有 HTTP 請求(Chrome 開發(fā)者工具的 Network 面板依然會顯示請求,但是會注明 from cache;Firefox 的 firebug 也類似,會注明 BFCache),這會大幅提升性能。所以我們一般會對 CSS、JS、圖片等資源使用強緩存,而入口文件(HTML)一般使用協(xié)商緩存或不緩存,這樣可以通過修改入口文件中對強緩存資源的引入 URL 來達到即時更新的目的。


這里也解釋下為什么有了 Expire,還要有 Cache-Control。也有兩個原因:1)Cache-Control 功能更強大,對緩存的控制能力更強;2)Cache-Control 采用的 max-age 是相對時間,不受服務端 / 客戶端時間不對的影響。


另外關于瀏覽器的刷新(F5 / cmd + r)和強刷(Ctrl + F5 / shift + cmd +r):普通刷新會使用協(xié)商緩存,忽略強緩存;強刷會忽略瀏覽器所有緩存(并且請求頭會攜帶 Cache-Control:no-cache 和 Pragma:no-cache,用來通知所有中間節(jié)點忽略緩存)。只有從地址欄或收藏夾輸入網(wǎng)址、點擊鏈接等情況下,瀏覽器才會使用強緩存。


默認情況下,Nginx 對于靜態(tài)資源都會輸出 Last-Modified,而 ETag、ExpireCache-Control 則需要自己配置:


location ~ ^/static/ {

root /home/jerry/www/blog/www;

etag on;

expires max;

}


expires 指令可以指定具體的 max-age,例如 10y 代表 10 年,如果指定為 max,最終輸出的 Expires 會是 2037 年最后一天,Cache-Controlmax-age 會是 10 年(準確說是 3650 天,315360000 秒)。


使用 SPDY(HTTP/2)


我的博客之前多次講到過 HTTP/2(SPDY),現(xiàn)階段 Nginx 只支持 SPDY/3.1,這樣配置就可以啟用了(編譯 Nginx 時需要加上 --with-http_spdy_module 和 --with-http_ssl_module):


server {

listen 443 ssl spdy fastopen=3 reuseport;

spdy_headers_comp 6;

... ...

}


那個 fastopen=3 用來開啟前面介紹過的 TCP Fast Open 功能。3 代表最多只能有 3 個未經(jīng)三次握手的 TCP 鏈接在排隊。超過這個限制,服務端會退化到采用普通的 TCP 握手流程。這是為了減少資源耗盡攻擊:TFO 可以在第一次 SYN 的時候發(fā)送 HTTP 請求,而服務端會校驗 Fast Open Cookie(FOC),如果通過就開始處理請求。如果不加限制,惡意客戶端可以利用合法的 FOC 發(fā)送大量請求耗光服務端資源。


reuseport 就是用來啟用前面介紹過的 TCP SO_REUSEPORT 選項的配置。


HTTPS 優(yōu)化


建立 HTTPS 連接本身就慢(多了獲取證書、校驗證書、TLS 握手等等步驟),如果沒有優(yōu)化好只能是慢上加慢。


server {

ssl_session_cache shared:SSL:10m;

ssl_session_timeout 10m;

ssl_session_tickets on;

ssl_stapling on;

ssl_stapling_verify on;

resolver 8.8.4.4 8.8.8.8 valid=300s;

resolver_timeout 10s;

... ...

}


我的這部分配置就兩部分內容:TLS 會話恢復和 OCSP stapling。

TLS 會話恢復的目的是為了簡化 TLS 握手,有兩種方案:Session Cache 和 Session Ticket。他們都是將之前握手的 Session 存起來供后續(xù)連接使用,所不同是 Cache 存在服務端,占用服務端資源;Ticket 存在客戶端,不占用服務端資源。另外目前主流瀏覽器都支持 Session Cache,而 Session Ticket 的支持度一般。


ssl_stapling 開始的四行用來配置 OCSP stapling 策略。瀏覽器可能會在建立 TLS 連接時在線驗證證書有效性,從而阻塞 TLS 握手,拖慢整體速度。OCSP stapling 是一種優(yōu)化措施,服務端通過它可以在證書鏈中封裝證書頒發(fā)機構的 OCSP(Online Certificate Status Protocol)響應,從而讓瀏覽器跳過在線查詢。服務端獲取 OCSP 一方面更快(因為服務端一般有更好的網(wǎng)絡環(huán)境),另一方面可以更好地緩存。有關 OCSP stapling 的詳細介紹,可以看這里。


在給 Nginx 指定證書時,需要選擇合適的證書鏈。因為瀏覽器在驗證證書信任鏈時,會從站點證書開始,遞歸驗證父證書,直至信任的根證書。這里涉及到兩個問題:1)服務器證書是在握手期間發(fā)送的,由于 TCP 初始擁塞窗口的存在,如果證書太長很可能會產(chǎn)生額外的往返開銷;2)如果服務端證書沒包含中間證書,大部分瀏覽器可以正常工作,但會暫停驗證并根據(jù)子證書指定的父證書 URL 自己獲取中間證書。這個過程會產(chǎn)生額外的 DNS 解析、建立 TCP 連接等開銷。配置服務端證書鏈的最佳實踐是包含站點證書和中間證書兩部分。有的證書提供商簽出來的證書級別比較多,這會導致證書鏈變長,選擇的時候需要特別注意。


好了,我的博客關于安全和性能兩部分 Nginx 配置終于都寫完了。實際上很多策略沒辦法嚴格區(qū)分是為了安全還是性能,比如 HSTS 和 CHACHA20_POLY1305,兩方面都有考慮,所以寫的時候比較糾結,早知道就合成一篇來寫了。


    本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內容均由用戶發(fā)布,不代表本站觀點。請注意甄別內容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權內容,請點擊一鍵舉報。
    轉藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多

    91蜜臀精品一区二区三区| 亚洲欧美日产综合在线网| 精品国产成人av一区二区三区| 一区二区三区免费公开| 国产女同精品一区二区| 日本在线高清精品人妻| 日本在线视频播放91| 沐浴偷拍一区二区视频| 亚洲熟女国产熟女二区三区| 国产麻豆成人精品区在线观看| 日韩人妻中文字幕精品| 日韩在线中文字幕不卡| 欧美字幕一区二区三区| 亚洲最新中文字幕在线视频 | 国产免费人成视频尤物| 色偷偷偷拍视频在线观看| 观看日韩精品在线视频| 日韩精品视频高清在线观看| 国产免费成人激情视频| 九九热精品视频免费观看| 风间中文字幕亚洲一区| 在线免费不卡亚洲国产| 麻豆最新出品国产精品| 丁香六月啪啪激情综合区| 黄色av尤物白丝在线播放网址| 都市激情小说在线一区二区三区 | 亚洲最新av在线观看| 中文字幕日韩欧美理伦片| 亚洲精品深夜福利视频| 亚洲一区二区福利在线| 久久精品少妇内射毛片| 日本高清二区视频久二区| 亚洲精品欧美精品日韩精品| 白丝美女被插入视频在线观看| 99国产精品国产精品九九| 欧美午夜国产在线观看| 大香蕉伊人一区二区三区| 国产一区国产二区在线视频| 蜜桃臀欧美日韩国产精品| 老司机精品视频免费入口| 丰满人妻熟妇乱又伦精另类视频|