面試官:我想用Nginx提升系統(tǒng)10倍性能,你有哪些建議?

譯者:為之漫筆
來源:www.zcfy.cc/article/10-tips-for-10x-application-performance-nginx-22.html
原文:https://www.nginx.com/blog/10-tips-for-10x-application-performance/
提升Web應(yīng)用的性能從未像今天這樣刻不容緩。
在線經(jīng)濟(jì)活動的比例日益提高,就連發(fā)展中國家和地區(qū)的經(jīng)濟(jì)活動都已經(jīng)有5%以上在線進(jìn)行了(相關(guān)數(shù)據(jù)請參考本文后面的資源)。在這個超級鏈接、隨時在線的現(xiàn)代世界,用戶的期望也遠(yuǎn)非昔日可比。如果你的網(wǎng)站不能馬上響應(yīng),你的應(yīng)用不能立即運(yùn)行,用戶轉(zhuǎn)身就會投奔你的競爭對手。
亞馬遜大約10年前的一項(xiàng)研究表明,頁面加載時間減少1/10秒,能夠使其營收增長1%。另一項(xiàng)近期的調(diào)查也顯示,一多半受訪站點(diǎn)所有者提到因?yàn)樽约簯?yīng)用的性能不佳導(dǎo)致了收入減少或者用戶流失。
一個網(wǎng)站到底多快才行?頁面加載每花1秒鐘,就有大約4%的用戶走掉。排名最靠前的電商站點(diǎn)的首次交互時間為1至3秒,這個區(qū)間的轉(zhuǎn)換率最高。顯而易見,Web應(yīng)用性能的重要性與日俱增。

如果你的Web應(yīng)用只跑在一臺機(jī)器上,那要提升其性能非常簡單:換一臺更快的,多配幾個處理器,多加幾條內(nèi)存,磁盤陣列也要高速的。換了以后,這臺機(jī)器上跑的WordPress服務(wù)器、Node.js或Java應(yīng)用速度都會加快。(要是應(yīng)用還會訪問另一臺數(shù)據(jù)庫服務(wù)器,那也簡單:找兩臺更快的機(jī)器,用更快的網(wǎng)絡(luò)連起來就行了)
麻煩在于,機(jī)器速度并不是問題。很多時候Web應(yīng)用慢,是因?yàn)橐诟鞣N任務(wù)之間切換,一會兒要處理數(shù)千個連接上的用戶請求,一會兒要向磁盤讀寫文件,一會兒又要運(yùn)行應(yīng)用的代碼,一會兒又要去干別的。應(yīng)用服務(wù)器因此可能出現(xiàn)各種狀況,耗盡內(nèi)存、交換文件,或者讓很多請求等待一個硬盤I/O之類的任務(wù)。
除了升級硬件,其實(shí)你還可以選擇另外一種完全不同的方法:加一臺反向代理服務(wù)器,分擔(dān)上述一些任務(wù)。反向代理服務(wù)器位于運(yùn)行應(yīng)用的機(jī)器之前,負(fù)責(zé)處理來自外網(wǎng)的請求。反向代理服務(wù)器直接連到互聯(lián)網(wǎng),它與應(yīng)用服務(wù)器通信使用的是快速的內(nèi)部網(wǎng)絡(luò)。
負(fù)載均衡(參見“建議二”),反向代理服務(wù)器上運(yùn)行負(fù)載均衡服務(wù),把流量平均分配給幾臺應(yīng)用服務(wù)器。有了負(fù)載均衡,添加應(yīng)用服務(wù)器根本不需要修改應(yīng)用。 緩存靜態(tài)文件(參見“建議三”),圖片或代碼之類的可以直接請求的文件,都可以保存在反向代理服務(wù)器中,以便直接發(fā)給客戶端。這樣不僅可以更快地響應(yīng)請求,還能減輕應(yīng)用服務(wù)器的負(fù)擔(dān),加快其運(yùn)行速度。 保證站點(diǎn)安全,可以配置反向代理服務(wù)器提升其安全級別,通過它監(jiān)控來快速識別和響應(yīng)攻擊,從而保存應(yīng)用服務(wù)器安全。

傳統(tǒng)服務(wù)器與NGINX Worker的比較

增加負(fù)載均衡服務(wù)器相對簡單,但卻能顯著提升站點(diǎn)性能和安全性。通過它把流量分配給多個服務(wù)器,就可以不必升級Web服務(wù)器了。就算應(yīng)用本身寫得不太好,或者難以擴(kuò)展,負(fù)載均衡都可以在不做其他改變的情況下提升用戶體驗(yàn)。
負(fù)載均衡服務(wù)器可以避免一臺服務(wù)器過載而其他服務(wù)器過閑,從而極大提升性能。同時,有了它還可以讓W(xué)eb服務(wù)器擴(kuò)容更簡單,因?yàn)榭梢赃x用比較便宜的服務(wù)器,同時保證物盡其用。
可以通過負(fù)載均衡調(diào)度的協(xié)議包括HTTP、HTTPS、SPDY、HTTP/2、WebSocket、FastCGI、SCGI、uwsgi、memcached,以及其他一些應(yīng)用形式,包括基于TCP的應(yīng)用和其他第四層的協(xié)議。為此,首先要分析Web應(yīng)用,看性能短板在哪里,然后再確定使用哪一個。
同一臺服務(wù)器或用于負(fù)載均衡的服務(wù)器也可以承擔(dān)其他任務(wù),比如SSL終止、視客戶端不同支持HTTP/1/x或HTTP/2、緩存靜態(tài)文件。
建議三:緩存靜態(tài)及動態(tài)內(nèi)容
緩存能提升Web應(yīng)用性能,因?yàn)榭梢愿斓匕褍?nèi)容交付給客戶端。緩存的策略包括預(yù)處理內(nèi)容、在較快的設(shè)備上存儲內(nèi)容、把內(nèi)容保存在靠近客戶端的地方,以及同時運(yùn)用這些策略。
靜態(tài)內(nèi)容緩存,不常變化的文件,如圖片(JPEG、PNG)和代碼(CSS、JavaScript),可以保存在邊緣服務(wù)器中,以便快速從內(nèi)容或磁盤中獲取。 動態(tài)內(nèi)容緩存,很多Web應(yīng)用會為每個頁面請求生成全新的HTML,把生成的每個HTML都緩存一小段時間,可能顯著減少需要生成的頁面總數(shù),同時又可以保證交付的內(nèi)容足夠新鮮。
把內(nèi)容放到離用戶近的地方。離用戶近,傳輸時間少。 把內(nèi)容放到較快的機(jī)器上。機(jī)器快,檢索速度快。 把內(nèi)容從過度使用的機(jī)器中拿走。有時候機(jī)器會比在專注執(zhí)行特定任務(wù)時慢很多,那是因?yàn)樘嗳蝿?wù)讓它們分心。這時候把內(nèi)容拿到其他機(jī)器上,不僅對緩存的內(nèi)容有好處,對非緩存的內(nèi)容同樣有利,因?yàn)橥泄芩鼈兊闹鳈C(jī)的負(fù)擔(dān)減輕了。
Web應(yīng)用的緩存可以在Web應(yīng)用服務(wù)器內(nèi)部或外部實(shí)現(xiàn)。首先,考慮緩存動態(tài)內(nèi)容,以減輕應(yīng)用服務(wù)器的負(fù)載。其次,緩存用于靜態(tài)內(nèi)容(包括那些動態(tài)生成內(nèi)容的臨時副本),進(jìn)一步減輕應(yīng)用服務(wù)器的負(fù)擔(dān)。然后,考慮把緩存轉(zhuǎn)移到其他更快或更靠近用戶的機(jī)器,給應(yīng)用服務(wù)器減負(fù),縮短傳輸時間。
用好緩存能顯著加快應(yīng)用的響應(yīng)速度。對很多網(wǎng)頁來說,大圖片之類的靜態(tài)數(shù)據(jù),往往占據(jù)一半以上的內(nèi)容。不用緩存,查詢和傳輸這類數(shù)據(jù)可能會花好幾秒鐘,而用緩存,則可能只要花幾分之一秒。
可以舉一個例子來說明怎么使用緩存,NGINX和NGINX Plus通過兩個指令來設(shè)置緩存:proxy_cache_path和proxy_cache指定緩存的位置和大小、最長緩存時間以及其他參數(shù)。使用第三個(也是很受歡迎的)指令proxy_cache_use_stale,甚至可以告訴緩存在本來應(yīng)該提供新鮮內(nèi)容的服務(wù)器太忙或宕機(jī)時,提供原來的舊文件,對客戶端來說,拿到內(nèi)容總比拿不到強(qiáng)。從用戶角度看,這樣也可以樹立你的站點(diǎn)或應(yīng)用非常穩(wěn)定的形象。
NGINX Plus支持高級緩存功能,包括緩存凈化(caching purging)和通過控制板以可視化的形式展示緩存狀態(tài),實(shí)現(xiàn)實(shí)時監(jiān)控。
注意: 緩存涉及開發(fā)、決策和運(yùn)維,完善的緩存策略,比如本文提到的這些,能夠體現(xiàn)從DevOps角度考慮的價(jià)值。也說是說,開發(fā)人員、架構(gòu)師、運(yùn)維人員此時攜手,共同保障一個網(wǎng)站的功能、響應(yīng)時間、安全和業(yè)務(wù)目標(biāo)。
建議四:壓縮數(shù)據(jù)

壓縮同樣能極大提升性能。圖片、視頻、音樂等文件都有非常成熟和高效的壓縮標(biāo)準(zhǔn)(JPEG和PNG、MPEG-4、MP3),任何一個標(biāo)準(zhǔn)都可以把文件大小縮小一個數(shù)量級甚至更多。
文本文件,包括HTML(純文本和HTML標(biāo)簽)、CSS和JavaScript代碼,經(jīng)常在不壓縮的情況下傳輸。壓縮這些數(shù)據(jù)對提升Web應(yīng)用的感知性能有時候特別明顯,尤其是移動用戶的網(wǎng)絡(luò)很慢又不穩(wěn)定的情況下。

越來越多的網(wǎng)站在使用Secure Sockets Layer(SSL)及后來的Transport Layer Security(TLS)協(xié)議。SSL/TLS通過加密從源服務(wù)器發(fā)送給用戶的數(shù)據(jù)來提升網(wǎng)站安全性。Google會提升使用SSL/TLS的網(wǎng)站的搜索引擎排名,將有力地推動這一進(jìn)程。
1、每次打開新連接的初次握手都必須創(chuàng)建加密密鑰,而瀏覽器使用HTTP/1.x對每個2、服務(wù)器建立多個連接的方式進(jìn)一步加劇了這個問題。
為了鼓勵人們使用SSL/TLS,HTTP/2和SPDY(參見建議六)的作者將這兩個協(xié)議設(shè)計(jì)為只讓瀏覽器針對一次會話建立一個連接。這樣就把SSL導(dǎo)致性能降低的兩個主要原因之一消滅掉了。然而,說到優(yōu)化SSL/TLS性能,還是有很多事情可做。
優(yōu)化SSL/TLS的方法因Web服務(wù)器而異。以NGINX為例,NGINX使用OpenSSL,運(yùn)行于普通機(jī)器上,能夠提供接近定制機(jī)器的性能。NGINX SSL performance詳細(xì)介紹了如何將SSL/TLS加密和解密的開銷降至最低。
會話緩存。使用ssl_session_cache指令開啟緩存,緩存每次SSL/STL連接時用到的參數(shù)。 會話票或ID。把特定SSL/TLS會話的信息保存為一個會話票或ID,以便連接重用,而不必重新握手。 OCSP封套。通過緩存SSL/TLS證書信息減少握手時間。

提升應(yīng)用性能的一個簡單的方法,就是根據(jù)可靠性及性能選擇軟件。此外,高質(zhì)量組件的開發(fā)者更可能不斷提升性能和修復(fù)問題,因此使用最新的穩(wěn)定版本是劃算。新發(fā)布的版本會得到開發(fā)者和用戶更多的關(guān)注,同時也會利用新的編譯器優(yōu)化技術(shù),包括針對新硬件的調(diào)優(yōu)。
相對舊版本,新發(fā)布的穩(wěn)定版本明顯性能更高。堅(jiān)持升級,也可以保證在調(diào)優(yōu)、問題修復(fù)和安全警報(bào)方面與時俱進(jìn)。
Linux是今天大多數(shù)Web服務(wù)器的底層操作系統(tǒng),作為一切基礎(chǔ)設(shè)施的基礎(chǔ),Linux對提升性能至關(guān)重要。默認(rèn)情況下,很多Linux系統(tǒng)都比較保守,僅以桌面辦公為需求,以占用少量資源為調(diào)優(yōu)目標(biāo)。對于Web應(yīng)用而言,為達(dá)到性能最佳,肯定需要重新調(diào)優(yōu)。
文件描述符。NGINX對每個連接最多使用兩個文件描述符。如果系統(tǒng)服務(wù)于很多連接,可能需要增大sys.fs.file_max這個對描述符的系統(tǒng)級限制,以及nofile這個用戶文件描述符限制,以支持增大后的負(fù)載。 臨時端口。在作為代理使用時,NGINX會為每個上游服務(wù)器創(chuàng)建臨時端口??梢栽O(shè)置net.ipv4.ip_local_port_range,增大端口值的范圍,以增加可用的端口量。此外,還可以減小net.ipv4.tcp_fin_timeout的值,它控制非活動端口釋放重用的等待時間,加快周轉(zhuǎn)。 對NGINX而言,請參考NGINX性能調(diào)優(yōu)指南,了解如何不費(fèi)吹灰之力將你的Linux系統(tǒng)優(yōu)化為能夠支持更大的吞吐量。
無論使用什么Web服務(wù)器,都需要針對應(yīng)用對其調(diào)優(yōu)。以下建議適用于任何Web服務(wù)器,但會給出只有NGINX的設(shè)置說明。
訪問日志。不要每個請求的日志都馬上寫到磁盤,可以在內(nèi)存里做個緩存,然后批量定入。對NGINX而言,將buffer=_size_參數(shù)添加到access_log指令,等內(nèi)存緩沖區(qū)寫滿后再把日志寫到磁盤。如果你添加了**flush=_time_**參數(shù),那么緩沖區(qū)的內(nèi)容也會按照指定時間寫入磁盤。 緩沖。緩沖用于在內(nèi)存里保存部分響應(yīng),直到緩沖區(qū)被填滿,可以實(shí)現(xiàn)對客戶端更有效的響應(yīng)。無法寫入內(nèi)存的響應(yīng)會被寫到磁盤,從而降低性能。在NGINX的緩沖啟用時,可以使用proxy_buffer_size和proxy_buffers指令來管理它。 客戶端活動連接?;顒舆B接可以減少時間消耗,特別是在使用SSL/TLS的情下。對NGINX而言,可以針對客戶端提高keepalive_requests的數(shù)值,默認(rèn)值為100;也可以增大keepalive_timeout的值,讓活動連接持續(xù)時間更長,從而讓后續(xù)請求得到更快響應(yīng)。 上游活動連接。上游連接,即連接到應(yīng)用服務(wù)器、數(shù)據(jù)庫服務(wù)器的連接,同樣可以從活動連接的設(shè)置中獲得好處。對上游連接來說,可以增加活動連接,也就是每個工作進(jìn)程可用的空閑活動連接的數(shù)量。這樣可以增進(jìn)連接重用,減少重開連接。關(guān)于活動連接的更多信息,請參考這篇博客。 限制。限制客戶端使用的資源可以提升性能和安全性。對NGINX而言,limit_conn和limit_conn_zone指令限制指定源的連接數(shù),而limit_rate限制帶寬。這些設(shè)置可以防止合法用戶“侵吞”資源,同時也有助于防止攻擊。limit_req和limit_req_zone指令限制客戶端請求。對于到上游服務(wù)器的連接,可以在上游配置區(qū)的服務(wù)器指令中使用max_conns參數(shù),它限制對上游服務(wù)器的連接,防止過載。相關(guān)的隊(duì)列指令會創(chuàng)建一個隊(duì)列,在max_conns限制到達(dá)后將指定的請求數(shù)保存指定的時間。 工作進(jìn)程。工作進(jìn)程負(fù)責(zé)處理請求。NGINX采用基于事件的模型和OS相關(guān)的機(jī)制有效地在工作進(jìn)程間分配請求。建議將worker_processes的值設(shè)置為每個CPU一個工作進(jìn)程。如果需要,大多數(shù)系統(tǒng)都支持提高worker_connections的值(默認(rèn)為512)。可以通過試驗(yàn)找到最適合你系統(tǒng)的這個值。 套接字分片。通常,一個套接字監(jiān)聽器向所有工作進(jìn)程分發(fā)新連接。套按字分片則為每個工作進(jìn)程都創(chuàng)建一個套接字監(jiān)聽器,由內(nèi)核在套接字監(jiān)聽器可用時為其指定連接。這樣可以減少鎖爭用,提升多核系統(tǒng)上的性能。要啟用套接字分片,在listen指令中包含reuseport參數(shù)。 線程池。一個費(fèi)時的操作會阻塞任何計(jì)算機(jī)進(jìn)程。對Web服務(wù)器軟件來說,磁盤訪問可能阻礙很多較快的操作,比如內(nèi)存中的計(jì)算和復(fù)制。在使用線程池的情況下,慢操作會被指定給一組獨(dú)立的任務(wù),而主處理循環(huán)會繼續(xù)運(yùn)行較快的操作。磁盤操作完成后,結(jié)果會返回到主處理循環(huán)。在NGINX中,read()系統(tǒng)調(diào)用和sendfile()被轉(zhuǎn)載到了線程池。


性能提升因Web應(yīng)用不同會有巨大差異。實(shí)際的提升取決于預(yù)算、時間,以及現(xiàn)有實(shí)現(xiàn)的與理想性能的差距。那么怎么讓你的應(yīng)用獲得10倍的性能提升呢?
為了幫大家理解每項(xiàng)優(yōu)化建議的潛能,下面再針對之前的建議給出一些實(shí)施方針,希望大家各取所需。
反向代理服務(wù)器及負(fù)載均衡。沒有負(fù)載均衡或池負(fù)載均衡,可能導(dǎo)致極低的性能。添加一個反向代理服務(wù)器,比如NGINX,可以減少Web應(yīng)用在內(nèi)存和磁盤之間的往返。負(fù)載均衡可以把任務(wù)從過載的服務(wù)器轉(zhuǎn)移到空閑的服務(wù)器,也便于擴(kuò)展。這些改變能極大地提升性能,與原有的部署方式最差的時候相比,10倍性能提升是很輕松的事,即使不到10倍那也在總體上有了質(zhì)的飛躍。 緩存動態(tài)和靜態(tài)內(nèi)容。如果你的Web服務(wù)器同時又充當(dāng)了應(yīng)用服務(wù)器,那么通過緩存動態(tài)內(nèi)容就可以達(dá)到高峰期10倍的性能提升。緩存靜態(tài)內(nèi)容也可以有幾倍的性能提升。 壓縮數(shù)據(jù)。使用JPEG、PNG、MPEG-4以及MP3等壓縮格式能顯著提升性能。如果這些手段都用上了,那么壓縮的文本數(shù)據(jù)(代碼及HTML)可以將初始頁面加載時間提升兩倍。 優(yōu)化SSL/TLS。安全握手對性能有很大影響,因此對其進(jìn)行優(yōu)化可以讓初次響應(yīng)加快兩倍,對于文本內(nèi)容較多的網(wǎng)站尤其如此。優(yōu)化SSL/TLS下的媒體文件帶來的性能提升很小。 實(shí)施HTTP/2和SPDY。在使用SSL/TLS的情況下,這兩個協(xié)議有可能提升網(wǎng)站的整體性能。 調(diào)優(yōu)Linux和Web服務(wù)器。使用優(yōu)化的緩沖策略、使用活動連接,將耗時的任務(wù)轉(zhuǎn)載至獨(dú)立的線程池,可以顯著提升性能。比如線程池可以將磁盤操作密集性任務(wù)的性能提升至少一個數(shù)量級。
