幫助Web應(yīng)用性能提升10倍的10個(gè)建議
提升 Web 應(yīng)用的性能變得越來越重要。線上經(jīng)濟(jì)活動(dòng)的份額持續(xù)增長(zhǎng),當(dāng)前發(fā)達(dá)世界中 5 % 的經(jīng)濟(jì)發(fā)生在互聯(lián)網(wǎng)上(查看下面資源的統(tǒng)計(jì)信息)。 我們現(xiàn)在所處的時(shí)代要求一直在線和互聯(lián)互通,這意味著用戶對(duì)性能有更高的期望。如果網(wǎng)站響應(yīng)不及時(shí),或者應(yīng)用有明顯的延遲,用戶很快就會(huì)跑到競(jìng)爭(zhēng)者那邊去。
例如,Amazon 十年前做的一項(xiàng)研究表明,網(wǎng)頁加載時(shí)間減少 100 毫秒,收入就會(huì)增加 1%。最近另一項(xiàng)研究凸顯了一個(gè)事實(shí),就是有一半以上的受調(diào)查網(wǎng)站經(jīng)營者說他們會(huì)因?yàn)閼?yīng)用的性能不好,而損失收入或客戶。
一個(gè)網(wǎng)站需要多快?網(wǎng)頁加載時(shí)間每增加 1 秒鐘,就會(huì)有 4 % 的用戶選擇離開。頂尖的電子商務(wù)網(wǎng)站把第一次交互時(shí)間控制在 1-3 秒內(nèi),這樣帶來了很高的轉(zhuǎn)換率。很明顯 Web 應(yīng)用性能的風(fēng)險(xiǎn)很高而且還在持續(xù)增長(zhǎng)。
提升性能說起來容易,實(shí)現(xiàn)起來卻很難。為了幫助大家,這篇文章提出了十個(gè)建議,可以讓網(wǎng)站的性能提升 10 倍。本篇作為系列文章的第一篇,詳細(xì)描述了如何借助一些驗(yàn)證過的優(yōu)化技術(shù)和一點(diǎn)來自 NGINX 的幫助,就能提升應(yīng)用的性能。該系列還概述了在安全性方面可能獲得的改善。
建議一、利用反向代理服務(wù)器加速和保護(hù)應(yīng)用
如果 Web 應(yīng)用運(yùn)行在一臺(tái)獨(dú)立的電腦上,性能問題的解決方案是顯而易見的:換一臺(tái)更快的電腦,里面加上更多的處理器、內(nèi)存、快速磁盤陣列等等。然后在這臺(tái)新電腦上運(yùn)行 WordPress 服務(wù)、Node.js 應(yīng)用、Java 應(yīng)用等等,會(huì)比以前快很多。(如果應(yīng)用需要訪問服務(wù)器,方案還是很簡(jiǎn)單:換兩臺(tái)更快的電腦,用更快速的連接把它們連接起來。)
但電腦速度可能不是問題所在。通常 Web 應(yīng)用運(yùn)行緩慢,是由于電腦一直在不同的任務(wù)間切換:同成千上萬的客戶交互、訪問磁盤上的文件、執(zhí)行應(yīng)用代碼和其它的任務(wù)。應(yīng)用服務(wù)器可能會(huì)因?yàn)橄旅孢@些問題而崩潰 —— 內(nèi)存耗盡、把很多的數(shù)據(jù)從內(nèi)存交換到磁盤上、以及很多請(qǐng)求都在等待一個(gè)類似磁盤 I/O 的單個(gè)任務(wù)。
你應(yīng)該采用一種完全不同的方式,而不是升級(jí)硬件:增加一個(gè)反向代理服務(wù)器來分擔(dān)這些任務(wù)。這臺(tái)反向代理服務(wù)器設(shè)置在運(yùn)行應(yīng)用的電腦之前,用來處理網(wǎng)絡(luò)流量。只有這臺(tái)反向代理服務(wù)器直接連到網(wǎng)絡(luò)上,它和應(yīng)用服務(wù)器通過一個(gè)快速的內(nèi)部網(wǎng)絡(luò)進(jìn)行通信。
利用這臺(tái)反向代理服務(wù)器,應(yīng)用服務(wù)器就不用等著和 Web 應(yīng)用的用戶進(jìn)行交互,它可以專注在建立網(wǎng)頁,并通過反向代理服務(wù)器把它們發(fā)送到網(wǎng)絡(luò)上。因?yàn)閼?yīng)用服務(wù)器不必再等待客戶的響應(yīng),所以能以最優(yōu)的速度運(yùn)行。
增加一臺(tái)反向代理服務(wù)器也增加了 Web 服務(wù)器的彈性。如果一臺(tái)服務(wù)器過載了,很容易增加另一臺(tái)同類型的服務(wù)器。如果一臺(tái)服務(wù)器宕機(jī),也很容易把它換掉。
因?yàn)榉聪虼矸?wù)器帶來的靈活性,它也成為了很多其它性能提升方法的先決條件,比如:
- 負(fù)載均衡(查看 建議二)—— 反向代理服務(wù)器上運(yùn)行一個(gè)負(fù)載均衡器,把流量平均分配給一堆應(yīng)用服務(wù)器。由于負(fù)載均衡器的引入,在增加應(yīng)用服務(wù)器時(shí)可以完全不用修改應(yīng)用程序。
- 緩存靜態(tài)文件(查看 建議三)—— 直接請(qǐng)求的文件,比如圖片或者代碼文件,可以存在反向代理服務(wù)器上,并直接發(fā)送給客戶端,這樣可以更快地提供服務(wù),分擔(dān)了應(yīng)用服務(wù)器的負(fù)載,可以讓應(yīng)用執(zhí)行得更快。
- 保護(hù)網(wǎng)站 —— 反向代理服務(wù)器可以設(shè)置較高的安全級(jí)別,通過監(jiān)控進(jìn)快速識(shí)別和響應(yīng)攻擊,這樣就可以把應(yīng)用服務(wù)器保護(hù)起來。
NGINX 軟件是專門設(shè)計(jì)用做反向代理服務(wù)器的,具有上述這些附加功能。NGINX 利用事件驅(qū)動(dòng)處理的方法,比其它傳統(tǒng)的服務(wù)器更加高效。NGINX Plus 增加了更多反向代理的高級(jí)功能和支持,包含應(yīng)用程序健康檢查、特定請(qǐng)求路由和高級(jí)緩存等
建議二、增加一個(gè)負(fù)載均衡器
增加一個(gè)負(fù)載均衡器是一個(gè)相對(duì)簡(jiǎn)單的改動(dòng),而且會(huì)大幅度地改善網(wǎng)站的性能和安全性。你可以利用負(fù)載均衡器把業(yè)務(wù)分配給一些服務(wù)器,而不是建造一臺(tái)更大更強(qiáng)的 Web 核心服務(wù)器。就算應(yīng)用程序編寫得很爛或者擴(kuò)展性很差,負(fù)載均衡器都能提升用戶體驗(yàn)而不需要任何其它的改動(dòng)。
負(fù)載均衡器首先是一個(gè)反向代理服務(wù)器(查看建議一)—— 它接收網(wǎng)絡(luò)流量,并把請(qǐng)求轉(zhuǎn)交給另一個(gè)服務(wù)器。一個(gè)竅門就是讓負(fù)載均衡器支持兩臺(tái)以上的應(yīng)用服務(wù)器,利用一個(gè)選擇算法在服務(wù)器間分配請(qǐng)求。最簡(jiǎn)單的方法就是輪詢,每個(gè)新請(qǐng)求發(fā)送給列表中的下一臺(tái)服務(wù)器。其它方法包括把請(qǐng)求發(fā)送給活動(dòng)連接數(shù)量最少的服務(wù)器。NGINX Plus 可以在同一臺(tái)服務(wù)器上維持一個(gè)給定的用戶會(huì)話,這個(gè)功能被稱為會(huì)話持久性。
負(fù)載均衡器可以極大地改善性能,因?yàn)樗鼈儽苊庾屢慌_(tái)服務(wù)器過載,而其它服務(wù)器卻處于空閑的狀態(tài)。它們也很容易擴(kuò)展 Web 服務(wù)器的能力,增加相對(duì)便宜的服務(wù)器并確保它們物盡其用。
負(fù)載均衡可以運(yùn)用在很多協(xié)議上,包含HTTP、HTTPS、SPDY、HTTP/2、WebSocket、FastCGI、SCGI、uwsgi、memcache,還有一些應(yīng)用程序,包含基于 TCP 的應(yīng)用和 L4 協(xié)議。分析 Web 應(yīng)用使用了什么技術(shù)和性能落后在什么地方。
同一臺(tái)服務(wù)器或者用于負(fù)載均衡的服務(wù)器,還能處理其他任務(wù),包含 SSL 終端、支持客戶端使用的 HTTP/1/x 和 HTTP/2、以及緩存靜態(tài)文件。
NGINX 通常被用于負(fù)載均衡:想了解更多,請(qǐng)參考這些資料,一篇介紹性的文章、一篇關(guān)于配置的文章、一本電子書和相關(guān)的網(wǎng)絡(luò)課程和相關(guān)文檔。我們的商業(yè)版本(NGINX Plus),支持更多負(fù)載均衡的特殊功能,比如基于服務(wù)器響應(yīng)時(shí)間的路由規(guī)劃,和基于微軟 NTLM 協(xié)議的負(fù)載均衡。(譯者注:NTLM 是NT LAN Manager的縮寫,NTLM 是 Windows NT 早期版本的標(biāo)準(zhǔn)安全協(xié)議。)
建議三、緩存靜態(tài)和動(dòng)態(tài)內(nèi)容
緩存通過更快地向客戶端提供內(nèi)容來改善 Web 應(yīng)用的性能。緩存包含一些策略:對(duì)內(nèi)容預(yù)處理以便更快地發(fā)布、在更快的設(shè)備上保存內(nèi)容、在更靠近客戶端的地方保存內(nèi)容,或者上述方法的組合。
有兩種不同類型的緩存需要考慮:
- 靜態(tài)內(nèi)容的緩存。不經(jīng)常變化的文件,比如圖像文件(JPEG,PNG)和代碼文件(CSS,JavaScript),可以存在一個(gè)邊緣服務(wù)器上,以便在內(nèi)存或磁盤上進(jìn)行快速檢索。
- 動(dòng)態(tài)內(nèi)容的緩存。很多 Web 應(yīng)用為每個(gè)頁面請(qǐng)求生成新的 HTML。通過簡(jiǎn)單地將已經(jīng)生成 HTML的副本保存一小段時(shí)間,就可以大幅度減少需要生成頁面的總數(shù),發(fā)布這些已經(jīng)生成的 HTML 副本已經(jīng)足夠滿足需求了。
比如一個(gè)網(wǎng)頁每秒有十次訪問,把它緩存 1 秒鐘,這個(gè)網(wǎng)頁 90% 的請(qǐng)求都可以用緩存滿足。如果你單獨(dú)緩存靜態(tài)內(nèi)容,甚至最新生成的網(wǎng)頁也會(huì)大量包含這些緩存的內(nèi)容。
Web 應(yīng)用生成緩存內(nèi)容主要有三種技術(shù):
- 讓內(nèi)容更靠近用戶。內(nèi)容副本靠近用戶,可以減少傳輸時(shí)間。
- 把內(nèi)容存在更快的電腦上。內(nèi)容可以保存在更快的電腦上以便加快檢索。
- 把內(nèi)容移出過載的電腦。有時(shí)候電腦運(yùn)行一個(gè)特定任務(wù)比基準(zhǔn)性能要慢,這是因?yàn)樗瑫r(shí)還在忙其他任務(wù)。把緩存設(shè)置在另一臺(tái)電腦上,都能提升有緩存資源和沒有緩存資源的性能,因?yàn)檫@臺(tái)主機(jī)不再過載了。
設(shè)置 Web 應(yīng)用的緩存從 Web 應(yīng)用服務(wù)器開始,是從內(nèi)到外來實(shí)現(xiàn)的。首先,緩存動(dòng)態(tài)內(nèi)容,減輕了應(yīng)用服務(wù)器的負(fù)擔(dān)。接下來,緩存靜態(tài)內(nèi)容(包括原本是動(dòng)態(tài)內(nèi)容的臨時(shí)副本),進(jìn)一步分擔(dān)應(yīng)用服務(wù)器的負(fù)擔(dān)。然后把緩存從應(yīng)用服務(wù)器移到更快的、距離用戶更近的電腦上,這樣卸下了應(yīng)用服務(wù)器的負(fù)擔(dān),減少了檢索和傳輸?shù)臅r(shí)間。
提高緩存可以大大加快應(yīng)用程序。大多數(shù)網(wǎng)頁中,一半以上的內(nèi)容都是靜態(tài)數(shù)據(jù)(比如大的圖像文件)。在沒有緩存的情況下,檢索和傳輸數(shù)據(jù)可能要花費(fèi)好幾秒鐘,但如果數(shù)據(jù)緩存在本地,只需要幾分之一秒就可以。
舉一個(gè)例子說明實(shí)際上如何使用緩存,NGINX 和 NGINX Plus 用兩條指令來創(chuàng)建緩存:proxy_cache_path 和 proxy_cache。你指定了緩存的位置和大小、文件保存在緩存的最長(zhǎng)時(shí)間和其它參數(shù)。使用的第三條指令(也相當(dāng)常用),proxy_cache_use_stale,甚至可以在服務(wù)器忙碌或掛掉而不能提供最新內(nèi)容的情況下,由緩存直接提供過期的內(nèi)容,給客戶端提供一些東西總比什么都沒有強(qiáng)。從用戶的角度來看,這會(huì)大大改善網(wǎng)站和應(yīng)用的正常運(yùn)行時(shí)間。
NGINX Plus 有一些高級(jí)的緩存功能,包括支持緩存清除,和將緩存狀態(tài)可視化并顯示在 dashboard 上,用于監(jiān)控實(shí)時(shí)活動(dòng)。
關(guān)于 NGINX 緩存的更多信息,可以參考相關(guān)文檔和 《NGINX Plus 管理指南》的「NGINX 內(nèi)容緩存」章節(jié)。
注意:緩存跨越了組織間的界限,讓從事應(yīng)用開發(fā)的人、進(jìn)行資本投資決策的人和維護(hù)網(wǎng)站的人都參與其中。成熟的緩存策略就像這里提到的,很好得體現(xiàn)了DevOps 方式的價(jià)值,也就是應(yīng)用程序員、架構(gòu)師和運(yùn)維人員等各方力量都團(tuán)結(jié)起來,努力達(dá)成對(duì)網(wǎng)站的功能、響應(yīng)時(shí)間、安全性和業(yè)務(wù)結(jié)果(比如完成的交易量或銷售額)的要求。
(譯者注:DevOps 不僅僅是一種軟件的部署方法。 它通過一種全新的方式,來思考如何讓軟件的作者(開發(fā)部門)和運(yùn)營者(運(yùn)營部門)進(jìn)行合作與協(xié)同。)
建議四、壓縮數(shù)據(jù)
壓縮是一個(gè)有巨大潛能的性能加速器。已經(jīng)有很多精心設(shè)計(jì)和高效的壓縮標(biāo)準(zhǔn),有針對(duì)圖像的(JPEG 和 PNG)、視頻的(MPEG-4)、音樂的(MP3)等等。這些標(biāo)準(zhǔn)都可以大幅減少文件的大小。
文本數(shù)據(jù) —— 包含 HTML(包含了純文本和 HTML 標(biāo)簽)、CSS 和類似 JavaScript 的代碼,這些數(shù)據(jù)通常不經(jīng)過壓縮就進(jìn)行傳輸了。壓縮這些數(shù)據(jù)會(huì)大大改善對(duì) Web 應(yīng)用性能的體驗(yàn),特別是那些連接緩慢或受限的移動(dòng)客戶端。
這是因?yàn)橛脩粼诤途W(wǎng)頁交互時(shí),文本數(shù)據(jù)通常已經(jīng)足夠了,而多媒體數(shù)據(jù)就需要更多的支持。智能內(nèi)容壓縮可以減少 HTML、Javascript、CSS 和其它文本內(nèi)容對(duì)帶寬的要求,通常是 30% 或者更多,從而減少加載時(shí)間。
如果使用 SSL,壓縮可以減少 SSL 加密的數(shù)據(jù)量,從而減少一些 CPU 時(shí)間。(譯者注:SSL,Security Socket Layer,加密套接字層,一種加密的通訊協(xié)議,用在客戶端與服務(wù)器之間。參考建議五。)
壓縮文本數(shù)據(jù)的方法有所不同。比如,本文的 HTTP/2 章節(jié)提到的一種新穎的文本壓縮方案,專門用來壓縮頭部數(shù)據(jù)。另一個(gè)例子是可以在 NGINX 中打開 GZIP。對(duì)文本數(shù)據(jù)進(jìn)行預(yù)先壓縮后,可以通過 gzip_static 指令直接提供 .gz 的壓縮文件(給客戶端)。
建議五、優(yōu)化 SSL/TLS
加密套接字層(SSL)協(xié)議及其后繼者 —— 傳輸層安全(TLS)協(xié)議,被越來越多得的網(wǎng)站所采用。SSL/TLS 加密了服務(wù)器發(fā)送給用戶的數(shù)據(jù),提升了網(wǎng)站的安全性。影響這一趨勢(shì)的部分原因是,Google 現(xiàn)在提升了啟用 HTTPS 網(wǎng)站的搜索排名。
盡管 SSL/TLS 越來越普遍,它們卻是影響許多網(wǎng)站性能的癥結(jié)所在。SSL/TLS 降低網(wǎng)站性能有兩個(gè)原因:
- 每當(dāng)打開一個(gè)新的連接,最初的握手都需要建立加密密鑰。瀏覽器使用 HTTP/1.x 和服務(wù)器建立多條連接,隨著服務(wù)器的增多,連接會(huì)成倍增加。
- 服務(wù)器上加密數(shù)據(jù),客戶端解密數(shù)據(jù),這些都是持續(xù)的開銷。
為了鼓勵(lì)使用 SSL/TLS,HTTP/2 和 SPDY (在下一章節(jié)詳細(xì)介紹)的作者在設(shè)計(jì)協(xié)議時(shí),讓每個(gè)瀏覽器會(huì)話只使用一個(gè)連接。這樣大大減少了 SSL 開銷的一個(gè)重要來源。但是,在提升基于 SSL/TLS 的應(yīng)用性能方面,還是有很多可以做的事情。
優(yōu)化 SSL/TLS 的機(jī)制因 Web 服務(wù)器而有所差別。比如,NGINX 使用 OpenSSL,運(yùn)行在標(biāo)準(zhǔn)硬件上,提供類似專用硬件解決方案的性能。NGINX SSL 性能解決方案有詳細(xì)的文檔、減少了 SSL/TLS 加解密對(duì) CPU 和 時(shí)間的消耗。
此外,這篇文章中還詳細(xì)介紹了提升 SSL/TLS 性能的各種方式。簡(jiǎn)單總結(jié)一下,這些技術(shù)包括:
- 會(huì)話緩存。使用 ssl_session_cache 指令,緩存 SSL/TLS 加密每個(gè)新連接所使用的參數(shù)。
- 會(huì)話標(biāo)簽或 ID。這些特定 SSL/TLS 會(huì)話信息都存在一個(gè)標(biāo)簽或 ID 中,所以可以順暢地重用一個(gè)連接,而不需要再次握手。
- OCSP 封裝。緩存 SSL/TLS 證書信息,來縮短握手時(shí)間。(譯者注:OCSP,Online Certificate Status Protocol,在線證書狀態(tài)檢查協(xié)議(RFC6960),用來向 CA 站點(diǎn)查詢證書狀態(tài),比如是否撤銷。通常情況下,瀏覽器使用 OCSP 協(xié)議發(fā)起查詢請(qǐng)求,CA 返回證書狀態(tài)內(nèi)容,然后瀏覽器接受證書是否可信的狀態(tài)。這個(gè)過程非常消耗時(shí)間,因?yàn)?CA 站點(diǎn)有可能在國外,網(wǎng)絡(luò)不穩(wěn)定,RTT 也比較大。那有沒有辦法不直接向 CA 站點(diǎn)請(qǐng)求 OCSP 內(nèi)容呢?OCSP 封裝(stapling) 就能實(shí)現(xiàn)這個(gè)功能。簡(jiǎn)單原理就是瀏覽器發(fā)起 client hello 時(shí)會(huì)攜帶一個(gè) certificate status request 的擴(kuò)展,服務(wù)器看到這個(gè)擴(kuò)展后將 OCSP 內(nèi)容直接返回給瀏覽器,完成證書狀態(tài)檢查。由于瀏覽器不需要直接向 CA 站點(diǎn)查詢證書狀態(tài),這個(gè)功能對(duì)訪問速度的提升非常明顯。 )
NGINX 和 NGINX Plus 可以用在 SSL 或 TLS 終端上 —— 當(dāng)和其它服務(wù)器進(jìn)行明文通信時(shí),對(duì)客戶端流量進(jìn)行加解密。按照這些步驟設(shè)置 NGINX 或 NGINX Plus,就能用在 SSL 或 TLS 終端上。當(dāng)用在接受 TCP 連接的服務(wù)器上,NGINX Plus 還有特別的設(shè)定步驟。
建議六、實(shí)現(xiàn) HTTP/2 或 SPDY
對(duì)于已經(jīng)使用 SSL/ TLS 的網(wǎng)站而言,因?yàn)?HTTP/2 和 SPDY 中的一個(gè)連接只需要一次握手,所以它們很有可能提升性能。對(duì)于沒有使用 SSL/TLS 的網(wǎng)站,改到 SSL/TLS 會(huì)讓性能變慢, 而 HTTP/2 和 SPDY 對(duì) SSL/TLS 的性能改進(jìn),就和性能下降的效果抵消了。
(譯者注:SPDY,一種開放的網(wǎng)絡(luò)傳輸協(xié)定,由Google開發(fā),用來傳送網(wǎng)頁內(nèi)容?;趥鬏斂刂茀f(xié)議(TCP)的應(yīng)用層協(xié)議 。Google最早是在Chromium中提出該協(xié)議。目前已經(jīng)被用于Google Chrome瀏覽器中來訪問Google的SSL加密服務(wù)。SPDY并不是首字母縮略字,而僅僅是”speedy”的縮寫。)
Google 在 2012年 引入 SPDY ,以實(shí)現(xiàn)比 HTTP/1. x 更快的性能。HTTP/2 基于 SPDY,最近剛被采納為 IETF 標(biāo)準(zhǔn)。SPDY 已被廣泛支持,不過很快就要被HTTP/2 所取代。
SPDY 和 HTTP/2 的關(guān)鍵特性是僅用一條單一連接而不是多條連接。這條連接是被復(fù)用的,同時(shí)可以有多個(gè)請(qǐng)求和應(yīng)答在上面?zhèn)鬏敗?/p>
這些協(xié)議充分發(fā)揮了單條連接的最大功效,避免了 HTTP/1.x 需要建立和管理多條連接的開銷。使用單條連接對(duì)于 SSL 特別有幫助,因?yàn)檫@樣最大程度地減少了 SSL/TLS 建立一個(gè)安全連接所需的握手次數(shù),因?yàn)槲帐滞ǔJ潜容^耗時(shí)的。
SPDY 協(xié)議需要使用到 SSL/TLS,HTTP/2 的官方說法是不需要用到它們,但是目前支持 HTTP/2 的瀏覽器只有在 SSL/TLS 被打開的情況下,才會(huì)用到 SSL/TLS。也就是說,只有當(dāng)一個(gè)網(wǎng)站使用 SSL 并且它的服務(wù)器接受 HTTP/2 流量時(shí),一個(gè)支持 HTTP/2 的瀏覽器才可以使用 SSL/TLS。否則,這個(gè)瀏覽器還是基于 HTTP/1.x 進(jìn)行通信。
一旦實(shí)現(xiàn)了 SPDY 或者 HTTP/2,你就不再需要傳統(tǒng)的 HTTP 性能優(yōu)化方法,比如區(qū)域切分、資源整合和雪碧圖。(譯者注:image spriting,工作原理是一堆的圖像(稱為“sprites”,精靈)合并成一張大的圖像(國內(nèi)稱為雪碧圖),以達(dá)到減少 HTTP 的請(qǐng)求數(shù)量)這些改動(dòng)讓代碼和部署變得更加簡(jiǎn)單,也更容易管理。要了解 HTTP/2 上相關(guān)改動(dòng)的更多信息,可以參考這篇白皮書。
NGINX 作為支持這些協(xié)議的一個(gè)例子,從一開始就支持 SPDY,目前很多使用 SPDY 的網(wǎng)站都在運(yùn)行 NGINX。 NGINX很早就支持 HTTP/2 了,2015 年 9 月 NGINX 的開源版本 和 NGINX Plus 就已經(jīng)支持了。
我們 NGINX 希望有朝一日大部分網(wǎng)站都可以使用 SSL,并遷移到 HTTP/2。這會(huì)提升安全性,同時(shí)由于找到和實(shí)現(xiàn)了新的優(yōu)化方法,代碼會(huì)更加簡(jiǎn)潔而且性能更好。
建議七、更新軟件版本
一個(gè)提升應(yīng)用性能的簡(jiǎn)單方法,就是為軟件技術(shù)棧選擇穩(wěn)定的、性能好的組件。此外,高質(zhì)量組件的程序員愿意加班追求性能的提升和盡快修正 bug,所以最好使用軟件最新的穩(wěn)定版本。新的發(fā)布會(huì)得到程序員和用戶社區(qū)的更多關(guān)注。新版本還會(huì)利用最新的編譯器優(yōu)化技術(shù),包含對(duì)新硬件的優(yōu)化。
穩(wěn)定的新版本通常都兼容老版本,而且有更好的性能。如果你持續(xù)更新軟件,很容易享受到性能優(yōu)化、bug 修正和安全報(bào)警等諸多好處。
一直使用軟件的老版本,還會(huì)讓你不能使用到新功能。比如,上面提到的 HTTP/2 現(xiàn)在需要使用 OpenSSL 1.0.1。從 2016 年中開始,HTTP/2 就需要使用 OpenSSL 1.0.2,OpenSSL的這個(gè)版本是在 2015 年 1 月發(fā)布的。
NGINX 用戶可以使用最新版本的 NGINX 開源軟件或者 NGINX Plus,新功能都包含其中,比如套接字切分和線程池(查看下面),而且性能還在持續(xù)優(yōu)化中。接下來仔細(xì)查看技術(shù)棧的軟件,并盡可能快地使用最新的版本。
建議八、優(yōu)化 Linux 性能
現(xiàn)在大多數(shù) Web 服務(wù)器的底層操作系統(tǒng)都是基于 Linux 的,所以 Linux 作為基礎(chǔ)設(shè)施的基礎(chǔ),在性能提升方面有很大的空間。默認(rèn)情況下,很多 Linux 系統(tǒng)被優(yōu)化成盡可能少地占用資源,以便適應(yīng)通常的桌面工作。這意味著 Web 應(yīng)用程序用例至少需要進(jìn)行最大性能的優(yōu)化。
Linux 針對(duì) Web 服務(wù)器所做的優(yōu)化。以 NGINX 為例,在加速 Linux 時(shí),需要考慮這些重要的改動(dòng):
- 緩沖隊(duì)列。如果有的連接看上去沒有響應(yīng)了,試著增大 net.core.somaxconn 看看,這個(gè)參數(shù)代表可以排隊(duì)等待的最大連接數(shù)。如果已存在的連接限制太小,你會(huì)看到錯(cuò)誤消息,可以逐漸增大參數(shù)直至錯(cuò)誤消息消失。
- 文件描述符。NGINX 在每個(gè)連接上使用兩個(gè)文件描述符。如果系統(tǒng)要服務(wù)很多連接,需要增大 sys.fs.file_max 和 nofile 這兩個(gè)參數(shù)以應(yīng)對(duì)增加的負(fù)載,前者是系統(tǒng)范圍內(nèi)文件描述符的限制,后者是用戶文件描述符的限制。
- 臨時(shí)端口。當(dāng)作為代理時(shí),NGINX 為每個(gè)上行服務(wù)器創(chuàng)建了臨時(shí)端口。你可以通過設(shè)定 net.ipv4.ip_local_port_range,來增加端口值的可用范圍。你還可以設(shè)定 net.ipv4.tcp_fin_timeout,減少超時(shí)來重新使用一個(gè)不活躍的端口,以便更快地周轉(zhuǎn)。
你可以查看《NGINX 性能優(yōu)化指南》(伯樂在線正在翻譯中),了解如何優(yōu)化 Linux 系統(tǒng),以便能毫不費(fèi)力地處理大量的網(wǎng)絡(luò)流量。
建議九、優(yōu)化 Web 服務(wù)器的性能
無論你使用哪一種 Web 服務(wù)器,都需要為 Web 應(yīng)用性能對(duì)它進(jìn)行優(yōu)化。下面的建議普遍適用于任何一個(gè) Web 服務(wù)器,但有一些是針對(duì) NGINX 的特別設(shè)定。這些優(yōu)化的關(guān)鍵點(diǎn)包括:
- 訪問日志??梢园颜?qǐng)求記錄先緩存在內(nèi)存中,然后一起寫入磁盤,而不是把每筆請(qǐng)求立刻寫到磁盤上。NGINX 使用 access_log 指令和 buffer=size 參數(shù),在內(nèi)存緩沖填滿時(shí),把日志記錄寫入磁盤。可以使用 flush=time 參數(shù),在特定時(shí)間后將緩沖內(nèi)容寫入磁盤。
- 緩沖區(qū)。緩沖區(qū)可以將一部分應(yīng)答保存在內(nèi)存中,直至緩沖被填滿了,這樣會(huì)讓與客戶端之前的通信更加高效。不能存入內(nèi)存中的應(yīng)答被寫入磁盤,這樣會(huì)導(dǎo)致性能的下降。當(dāng) NGINX 緩沖打開的時(shí)候,你可以通過 proxy_buffer_size 和 proxy_buffer 這兩個(gè)指令來進(jìn)行管理。
- 客戶端?;顣r(shí)間。保持連接可以減少開銷,特別是使用 SSL/TLS 的時(shí)候。在 NGINX 上,你可以通過增加 keepalive_request 的最大數(shù)量,來設(shè)定客戶端在指定連接上的請(qǐng)求數(shù)量,這個(gè)參數(shù)的默認(rèn)值是 100 ,你還可以增加 keepalive_timeout 讓連接在打開狀態(tài)上持續(xù)得更久一些,從而更快地響應(yīng)后續(xù)的請(qǐng)求。
- 上行?;顣r(shí)間。上行連接也就是指連到應(yīng)用服務(wù)器、數(shù)據(jù)庫服務(wù)器等這些連接,它們也可以從保持連接中受益。對(duì)于上行連接,你可以增大 keepalive,這個(gè)參數(shù)表示每個(gè)工作進(jìn)程中有多少空閑的?;钸B接是處于打開狀態(tài)的。這樣會(huì)增加重用連接的數(shù)量,減少打開全新連接的需求。保活的更多信息,參考這篇文章。
- 限制。限制客戶端所使用的資源也能提升性能和安全性。NGINX 可以通過 limit_conn 和 limit_conn_zone 指令限制一個(gè)給定源的連接數(shù)量,limit_rate 指令則用來限定帶寬。這些設(shè)定可以阻止一個(gè)合法用戶“占用”資源,也可以防止攻擊。limit_req 和 limit_req_zone 指令限制客戶端的請(qǐng)求。對(duì)于上行服務(wù)器的連接而言,可以在上行配置段中,使用 server 指令和 max_conns 參數(shù)。這樣限制了連接到上行服務(wù)器的數(shù)量,可以防止過載。相關(guān)的 queue 指令創(chuàng)建了一個(gè)隊(duì)列,當(dāng) max_conns 限制超過時(shí),可以在一定時(shí)間內(nèi)保存一定數(shù)量的請(qǐng)求。
- 工作進(jìn)程。工作進(jìn)程負(fù)責(zé)處理請(qǐng)求。NGINX 采用了基于事件的模型,以及和操作系統(tǒng)相關(guān)的機(jī)制,高效地把請(qǐng)求分配給工作進(jìn)程。work_processes 的推薦值是在每個(gè) CPU 上設(shè)定為 1。絕大多數(shù)系統(tǒng)出于需要,會(huì)在保證安全的前提下提高 work_connections (默認(rèn)值 512)的最大值,你可以通過實(shí)驗(yàn)來找到適合系統(tǒng)的值。
- 套接字切分。通常用一個(gè)單獨(dú)的監(jiān)聽套接字將新連接分配給各個(gè)工作進(jìn)程。套接字切分會(huì)為每個(gè)工作進(jìn)程創(chuàng)建一個(gè)監(jiān)聽套接字,當(dāng)監(jiān)聽套接字可用時(shí),內(nèi)核會(huì)把連接分配給它們。這樣在多核系統(tǒng)中可以減少對(duì)鎖的競(jìng)爭(zhēng)和提升性能。執(zhí)行 listen 指令時(shí)配合 reuseport 參數(shù),就可以打開套接字切分的功能。
- 線程池。任何一個(gè)計(jì)算機(jī)進(jìn)程都可能被一個(gè)慢速操作所拖累。對(duì) Web 服務(wù)器軟件來說,訪問磁盤會(huì)拖累很多快速的操作,比如在內(nèi)存上進(jìn)行計(jì)算或者復(fù)制信息。當(dāng)一個(gè)線程池被引入,可以把這個(gè)慢速操作分配給一個(gè)獨(dú)立的任務(wù),主進(jìn)程仍然處理快速操作。磁盤操作完成后,結(jié)果再返回給主進(jìn)程。 在 NGINX 中會(huì)把 read() 和 sendfile() 這兩個(gè)系統(tǒng)調(diào)用分散到線程池上。
小提示:當(dāng)改動(dòng)任何系統(tǒng)或服務(wù)上的設(shè)定時(shí),一次只修改一個(gè)設(shè)定,然后再測(cè)試性能。如果這個(gè)改動(dòng)造成問題,或者沒有讓網(wǎng)站變快,把它改回來就好了。
關(guān)于優(yōu)化 NGINX 的更多信息,請(qǐng)參考這篇文章。
建議十、監(jiān)控實(shí)時(shí)活動(dòng)來解決問題和瓶頸
開發(fā)和發(fā)布高性能應(yīng)用的關(guān)鍵,在于密切和實(shí)時(shí)地關(guān)注應(yīng)用程序在現(xiàn)實(shí)情況下的性能。你必須能夠監(jiān)控特定設(shè)備的活動(dòng)和網(wǎng)站的基礎(chǔ)設(shè)施。
大多數(shù)監(jiān)控網(wǎng)站的活動(dòng)都很被動(dòng) —— 它只告訴你將會(huì)發(fā)生什么,讓你自己去發(fā)現(xiàn)問題和解決問題。
監(jiān)控可以抓到不同類型的問題。它們包含:
- 服務(wù)器宕機(jī)。
- 服務(wù)器不穩(wěn)定,容易掉線。
- 服務(wù)器大概率出現(xiàn)緩沖失效。
- 服務(wù)器發(fā)送的內(nèi)容不正確。
你可以使用 New Relic 或 Dynatrace 這種全球性的應(yīng)用性能監(jiān)控工具,來監(jiān)控遙遠(yuǎn)地方加載頁面的時(shí)間,也可以利用 NGINX 監(jiān)控應(yīng)用程序的發(fā)布。當(dāng)你考慮是否需要給基礎(chǔ)設(shè)施擴(kuò)容來維持流量時(shí),應(yīng)用性能數(shù)據(jù)可以告訴你這些優(yōu)化是否真能給用戶帶來很大的改善。
NGINX Plus 增加了檢查應(yīng)用程序健康的功能 —— 綜合一些定期重復(fù)性的操作,以及在問題發(fā)生時(shí)報(bào)警,這樣可以快速地定位和解決問題。NGINX Plus 還有會(huì)話耗盡功能 —— 當(dāng)任務(wù)完成后終止新的連接,以及慢啟動(dòng)的能力 —— 允許負(fù)載均衡集群中的一臺(tái)服務(wù)器,從剛修復(fù)的狀態(tài)慢慢趕上來。如果使用得當(dāng),健康檢查可以在發(fā)生影響用戶體驗(yàn)的重大問題前,就定位出問題。會(huì)話耗盡和慢啟動(dòng),允許更換服務(wù)器,并保證在過程中不會(huì)對(duì)性能和正常的運(yùn)行時(shí)間造成不好的影響。下圖是一個(gè)在 NGINX Plus 中集成了實(shí)時(shí)活動(dòng)監(jiān)控的 dashboard,上面顯示了Web 基礎(chǔ)設(shè)施和服務(wù)器、TCP 連接以及緩存等相關(guān)信息。
總結(jié):如何看到性能提升 10 倍
能用在每個(gè) Web 應(yīng)用上的性能提升方法千差萬別,并且最后的效果也取決于預(yù)算、付出的時(shí)間和已有的實(shí)現(xiàn)等等。那么如何讓你自己的應(yīng)用達(dá)到性能提升 10 倍的目標(biāo)呢?
雖然你們遇到的情況肯定會(huì)不一樣,為了幫助理解每種優(yōu)化方法的影響,這里列出一些上面詳細(xì)討論的要點(diǎn):
- 反向代理服務(wù)器和負(fù)載均衡。如果沒有做負(fù)載均衡,或者負(fù)載均衡做得很爛,都會(huì)造成性能很差。增加一個(gè)反向代理服務(wù)器,比如 NGINX,就可以防止 Web 應(yīng)用在內(nèi)存和磁盤間往復(fù)切換。負(fù)載均衡可以將處理從過載的服務(wù)器移到其他可用的服務(wù)器上,并且很容易進(jìn)行擴(kuò)展。這些改動(dòng)可以大幅度地提升性能,和現(xiàn)在實(shí)現(xiàn)的最差情況相比,很容易實(shí)現(xiàn) 10 倍的性能提升,但實(shí)質(zhì)上整體性能的提升可能沒有這么大。
- 緩存動(dòng)態(tài)和靜態(tài)內(nèi)容。如果有一個(gè)服務(wù)器已經(jīng)過載了,它既是 Web 服務(wù)器又是應(yīng)用服務(wù)器,通過緩存動(dòng)態(tài)內(nèi)容就可以在峰值時(shí)刻提升 10 倍的性能。緩存靜態(tài)文件也能實(shí)現(xiàn)個(gè)位數(shù)字的性能提升。
- 壓縮數(shù)據(jù)。利用多媒體文件的壓縮格式,比如圖片采用 JPEG 格式、圖像采用 PNG 格式、電影采用 MPEG-4 格式、音樂采用 MP3 格式,這樣就能在很大程度上提升性能。一旦這些格式都用上,壓縮文本數(shù)據(jù)(代碼和 HTML)的頁面加載速度可以提升 2 倍。
- 優(yōu)化 SSL/TLS。安全握手對(duì)性能有很大影響,所以優(yōu)化它們可以帶來 2 倍的改善,特別是文本很多的網(wǎng)站。在 SSL/TLS 條件下,優(yōu)化多媒體文件改善很小。
- 實(shí)現(xiàn) HTTP/2 和 SPDY。當(dāng)和 SSL/TLS 一起使用時(shí),這些協(xié)議會(huì)讓整個(gè)網(wǎng)站的性能大幅度地提升。
- 優(yōu)化 Linux 和 Web 服務(wù)器軟件(例如 NGINX)。優(yōu)化緩沖區(qū)、保持連接、將耗時(shí)的任務(wù)分散到一個(gè)獨(dú)立的線程池上都能大幅提升性能。比如線程池運(yùn)用在對(duì)磁盤操作頻繁的任務(wù)上會(huì)帶來指數(shù)級(jí)的提速。