Web 應用性能提升 10 倍的 10 個建議

如果使用 SSL,壓縮可以減少 SSL 加密的數據量,從而減少一些 CPU 時間。(譯者注:SSL,Security Socket Layer,加密套接字層,一種加密的通訊協議,用在客戶端與服務器之間。參考建議五。)

壓縮文本數據的方法有所不同。比如,本文的 HTTP/2 章節提到的一種新穎的文本壓縮方案,專門用來壓縮頭部數據。另一個例子是可以在 NGINX 中打開 GZIP。對文本數據進行預先壓縮後,可以通過 gzip_static 指令直接提供 .gz 的壓縮文件(給客戶端)。

建議五、優化 SSL/TLS

加密套接字層(SSL)協議及其後繼者 —— 傳輸層安全(TLS)協議,被越來越多得的網站所採用。SSL/TLS 加密了服務器發送給用戶的數據,提升了網站的安全性。影響這一趨勢的部分原因是,Google 現在提升了啟用 HTTPS 網站的搜索排名。

儘管 SSL/TLS 越來越普遍,它們卻是影響許多網站性能的癥結所在。SSL/TLS 降低網站性能有兩個原因:

  1. 每當打開一個新的連接,最初的握手都需要建立加密密鑰。瀏覽器使用 HTTP/1.x 和服務器建立多條連接,隨著服務器的增多,連接會成倍增加。
  2. 服務器上加密數據,客戶端解密數據,這些都是持續的開銷。

為了鼓勵使用 SSL/TLS,HTTP/2 和 SPDY (在下一章節詳細介紹)的作者在設計協議時,讓每個瀏覽器會話只使用一個連接。這樣大大減少了 SSL 開銷的一個重要來源。但是,在提升基於 SSL/TLS 的應用性能方面,還是有很多可以做的事情。

優化 SSL/TLS 的機制因 Web 服務器而有所差別。比如,NGINX 使用 OpenSSL,運行在標準硬件上,提供類似專用硬件解決方案的性能。NGINX SSL 性能解決方案有詳細的文檔、減少了 SSL/TLS 加解密對 CPU 和 時間的消耗。

此外,這篇文章中還詳細介紹了提升 SSL/TLS 性能的各種方式。簡單總結一下,這些技術包括:

  • 會話緩存。使用 ssl_session_cache 指令,緩存 SSL/TLS 加密每個新連接所使用的參數。
  • 會話標籤或 ID。這些特定 SSL/TLS 會話信息都存在一個標籤或 ID 中,所以可以順暢地重用一個連接,而不需要再次握手。
  • OCSP 封裝。緩存 SSL/TLS 證書信息,來縮短握手時間。(譯者注:OCSP,Online Certificate Status Protocol,在線證書狀態檢查協議(RFC6960),用來向 CA 站點查詢證書狀態,比如是否撤銷。通常情況下,瀏覽器使用 OCSP 協議發起查詢請求,CA 返回證書狀態內容,然後瀏覽器接受證書是否可信的狀態。這個過程非常消耗時間,因為 CA 站點有可能在國外,網絡不穩定,RTT 也比較大。那有沒有辦法不直接向 CA 站點請求 OCSP 內容呢?OCSP 封裝(stapling) 就能實現這個功能。簡單原理就是瀏覽器發起 client hello 時會攜帶一個 certificate status request 的擴展,服務器看到這個擴展後將 OCSP 內容直接返回給瀏覽器,完成證書狀態檢查。由於瀏覽器不需要直接向 CA 站點查詢證書狀態,這個功能對訪問速度的提升非常明顯。 )

NGINX 和 NGINX Plus 可以用在 SSL 或 TLS 終端上 —— 當和其它服務器進行明文通信時,對客戶端流量進行加解密。按照這些步驟設置 NGINX 或 NGINX Plus,就能用在 SSL 或 TLS 終端上。當用在接受 TCP 連接的服務器上,NGINX Plus 還有特別的設定步驟。

建議六、實現 HTTP/2 或 SPDY

對於已經使用 SSL/ TLS 的網站而言,因為 HTTP/2 和 SPDY 中的一個連接只需要一次握手,所以它們很有可能提升性能。對於沒有使用 SSL/TLS 的網站,改到 SSL/TLS 會讓性能變慢, 而 HTTP/2 和 SPDY 對 SSL/TLS 的性能改進,就和性能下降的效果抵消了。

(譯者注:SPDY,一種開放的網絡傳輸協定,由Google開發,用來傳送網頁內容。基於傳輸控制協議(TCP)的應用層協議 。Google最早是在Chromium中提出該協議。目前已經被用於Google Chrome瀏覽器中來訪問Google的SSL加密服務。SPDY並不是首字母縮略字,而僅僅是”speedy”的縮寫。)

Google 在 2012年 引入 SPDY ,以實現比 HTTP/1. x 更快的性能。HTTP/2 基於 SPDY,最近剛被採納為 IETF 標準。SPDY 已被廣泛支持,不過很快就要被HTTP/2 所取代。

SPDY 和 HTTP/2 的關鍵特性是僅用一條單一連接而不是多條連接。這條連接是被複用的,同時可以有多個請求和應答在上面傳輸。

這些協議充分發揮了單條連接的最大功效,避免了 HTTP/1.x 需要建立和管理多條連接的開銷。使用單條連接對於 SSL 特別有幫助,因為這樣最大程度地減少了 SSL/TLS 建立一個安全連接所需的握手次數,因為握手通常是比較耗時的。

SPDY 協議需要使用到 SSL/TLS,HTTP/2 的官方說法是不需要用到它們,但是目前支持 HTTP/2 的瀏覽器只有在 SSL/TLS 被打開的情況下,才會用到 SSL/TLS。也就是說,只有當一個網站使用 SSL 並且它的服務器接受 HTTP/2 流量時,一個支持 HTTP/2 的瀏覽器才可以使用 SSL/TLS。否則,這個瀏覽器還是基於 HTTP/1.x 進行通信。

一旦實現了 SPDY 或者 HTTP/2,你就不再需要傳統的 HTTP 性能優化方法,比如區域切分、資源整合和雪碧圖。(譯者注:image spriting,工作原理是一堆的圖像(稱為“sprites”,精靈)合併成一張大的圖像(國內稱為雪碧圖),以達到減少 HTTP 的請求數量)這些改動讓代碼和部署變得更加簡單,也更容易管理。要了解 HTTP/2 上相關改動的更多信息,可以參考這篇白皮書。

NGINX 作為支持這些協議的一個例子,從一開始就支持 SPDY,目前很多使用 SPDY 的網站都在運行 NGINX。 NGINX很早就支持 HTTP/2 了,2015 年 9 月 NGINX 的開源版本 和 NGINX Plus 就已經支持了。

我們 NGINX 希望有朝一日大部分網站都可以使用 SSL,並遷移到 HTTP/2。這會提升安全性,同時由於找到和實現了新的優化方法,代碼會更加簡潔而且性能更好。

建議七、更新軟件版本

一個提升應用性能的簡單方法,就是為軟件技術棧選擇穩定的、性能好的組件。此外,高質量組件的程序員願意加班追求性能的提升和儘快修正 bug,所以最好使用軟件最新的穩定版本。新的發佈會得到程序員和用戶社區的更多關注。新版本還會利用最新的編譯器優化技術,包含對新硬件的優化。

穩定的新版本通常都兼容老版本,而且有更好的性能。如果你持續更新軟件,很容易享受到性能優化、bug 修正和安全報警等諸多好處。

一直使用軟件的老版本,還會讓你不能使用到新功能。比如,上面提到的 HTTP/2 現在需要使用 OpenSSL 1.0.1。從 2016 年中開始,HTTP/2 就需要使用 OpenSSL 1.0.2,OpenSSL的這個版本是在 2015 年 1 月發佈的。

NGINX 用戶可以使用最新版本的 NGINX 開源軟件或者 NGINX Plus,新功能都包含其中,比如套接字切分和線程池(查看下面),而且性能還在持續優化中。接下來仔細查看技術棧的軟件,並儘可能快地使用最新的版本。

建議八、優化 Linux 性能

現在大多數 Web 服務器的底層操作系統都是基於 Linux 的,所以 Linux 作為基礎設施的基礎,在性能提升方面有很大的空間。默認情況下,很多 Linux 系統被優化成儘可能少地佔用資源,以便適應通常的桌面工作。這意味著 Web 應用程序用例至少需要進行最大性能的優化。

Linux 針對 Web 服務器所做的優化。以 NGINX 為例,在加速 Linux 時,需要考慮這些重要的改動:

  • 緩衝隊列。如果有的連接看上去沒有響應了,試著增大 net.core.somaxconn 看看,這個參數代表可以排隊等待的最大連接數。如果已存在的連接限制太小,你會看到錯誤消息,可以逐漸增大參數直至錯誤消息消失。
  • 文件描述符。NGINX 在每個連接上使用兩個文件描述符。如果系統要服務很多連接,需要增大 sys.fs.file_max 和 nofile 這兩個參數以應對增加的負載,前者是系統範圍內文件描述符的限制,後者是用戶文件描述符的限制。
  • 臨時端口。當作為代理時,NGINX 為每個上行服務器創建了臨時端口。你可以通過設定 net.ipv4.ip_local_port_range,來增加端口值的可用範圍。你還可以設定 net.ipv4.tcp_fin_timeout,減少超時來重新使用一個不活躍的端口,以便更快地週轉。

你可以查看《NGINX 性能優化指南》(伯樂在線正在翻譯中),瞭解如何優化 Linux 系統,以便能毫不費力地處理大量的網絡流量。

建議九、優化 Web 服務器的性能

無論你使用哪一種 Web 服務器,都需要為 Web 應用性能對它進行優化。下面的建議普遍適用於任何一個 Web 服務器,但有一些是針對 NGINX 的特別設定。這些優化的關鍵點包括:

  • 訪問日誌。可以把請求記錄先緩存在內存中,然後一起寫入磁盤,而不是把每筆請求立刻寫到磁盤上。NGINX 使用 access_log 指令和 buffer=size 參數,在內存緩衝填滿時,把日誌記錄寫入磁盤。可以使用 flush=time 參數,在特定時間後將緩衝內容寫入磁盤。
  • 緩衝區。緩衝區可以將一部分應答保存在內存中,直至緩衝被填滿了,這樣會讓與客戶端之前的通信更加高效。不能存入內存中的應答被寫入磁盤,這樣會導致性能的下降。當 NGINX 緩衝打開的時候,你可以通過 proxy_buffer_size 和 proxy_buffer 這兩個指令來進行管理。
  • 客戶端保活時間。保持連接可以減少開銷,特別是使用 SSL/TLS 的時候。在 NGINX 上,你可以通過增加 keepalive_request 的最大數量,來設定客戶端在指定連接上的請求數量,這個參數的默認值是 100 ,你還可以增加 keepalive_timeout 讓連接在打開狀態上持續得更久一些,從而更快地響應後續的請求。
  • 上行保活時間。上行連接也就是指連到應用服務器、數據庫服務器等這些連接,它們也可以從保持連接中受益。對於上行連接,你可以增大 keepalive,這個參數表示每個工作進程中有多少空閒的保活連接是處於打開狀態的。這樣會增加重用連接的數量,減少打開全新連接的需求。保活的更多信息,參考這篇文章。
  • 限制。限制客戶端所使用的資源也能提升性能和安全性。NGINX 可以通過 limit_conn 和 limit_conn_zone 指令限制一個給定源的連接數量,limit_rate 指令則用來限定帶寬。這些設定可以阻止一個合法用戶“佔用”資源,也可以防止攻擊。limit_req 和 limit_req_zone 指令限制客戶端的請求。對於上行服務器的連接而言,可以在上行配置段中,使用 server 指令和 max_conns 參數。這樣限制了連接到上行服務器的數量,可以防止過載。相關的 queue 指令創建了一個隊列,當 max_conns 限制超過時,可以在一定時間內保存一定數量的請求。
  • 工作進程。工作進程負責處理請求。NGINX 採用了基於事件的模型,以及和操作系統相關的機制,高效地把請求分配給工作進程。work_processes 的推薦值是在每個 CPU 上設定為 1。絕大多數系統出於需要,會在保證安全的前提下提高 work_connections (默認值 512)的最大值,你可以通過實驗來找到適合系統的值。
  • 套接字切分。通常用一個單獨的監聽套接字將新連接分配給各個工作進程。套接字切分會為每個工作進程創建一個監聽套接字,當監聽套接字可用時,內核會把連接分配給它們。這樣在多核系統中可以減少對鎖的競爭和提升性能。執行 listen 指令時配合 reuseport 參數,就可以打開套接字切分的功能。
  • 線程池。任何一個計算機進程都可能被一個慢速操作所拖累。對 Web 服務器軟件來說,訪問磁盤會拖累很多快速的操作,比如在內存上進行計算或者複製信息。當一個線程池被引入,可以把這個慢速操作分配給一個獨立的任務,主進程仍然處理快速操作。磁盤操作完成後,結果再返回給主進程。 在 NGINX 中會把 read() 和 sendfile() 這兩個系統調用分散到線程池上。
Web 應用性能提升 10 倍的 10 個建議

小提示:當改動任何系統或服務上的設定時,一次只修改一個設定,然後再測試性能。如果這個改動造成問題,或者沒有讓網站變快,把它改回來就好了。

關於優化 NGINX 的更多信息,請參考這篇文章。

建議十、監控實時活動來解決問題和瓶頸

開發和發佈高性能應用的關鍵,在於密切和實時地關注應用程序在現實情況下的性能。你必須能夠監控特定設備的活動和網站的基礎設施。

大多數監控網站的活動都很被動 —— 它只告訴你將會發生什麼,讓你自己去發現問題和解決問題。

監控可以抓到不同類型的問題。它們包含:

  1. 服務器宕機。
  2. 服務器不穩定,容易掉線。
  3. 服務器大概率出現緩衝失效。
  4. 服務器發送的內容不正確。

你可以使用 New Relic 或 Dynatrace 這種全球性的應用性能監控工具,來監控遙遠地方加載頁面的時間,也可以利用 NGINX 監控應用程序的發佈。當你考慮是否需要給基礎設施擴容來維持流量時,應用性能數據可以告訴你這些優化是否真能給用戶帶來很大的改善。

NGINX Plus 增加了檢查應用程序健康的功能 —— 綜合一些定期重複性的操作,以及在問題發生時報警,這樣可以快速地定位和解決問題。NGINX Plus 還有會話耗盡功能 —— 當任務完成後終止新的連接,以及慢啟動的能力 —— 允許負載均衡集群中的一臺服務器,從剛修復的狀態慢慢趕上來。如果使用得當,健康檢查可以在發生影響用戶體驗的重大問題前,就定位出問題。會話耗盡和慢啟動,允許更換服務器,並保證在過程中不會對性能和正常的運行時間造成不好的影響。下圖是一個在 NGINX Plus 中集成了實時活動監控的 dashboard,上面顯示了Web 基礎設施和服務器、TCP 連接以及緩存等相關信息。

Web 應用性能提升 10 倍的 10 個建議

總結:如何看到性能提升 10 倍

能用在每個 Web 應用上的性能提升方法千差萬別,並且最後的效果也取決於預算、付出的時間和已有的實現等等。那麼如何讓你自己的應用達到性能提升 10 倍的目標呢?

雖然你們遇到的情況肯定會不一樣,為了幫助理解每種優化方法的影響,這裡列出一些上面詳細討論的要點:

  • 反向代理服務器和負載均衡。如果沒有做負載均衡,或者負載均衡做得很爛,都會造成性能很差。增加一個反向代理服務器,比如 NGINX,就可以防止 Web 應用在內存和磁盤間往復切換。負載均衡可以將處理從過載的服務器移到其他可用的服務器上,並且很容易進行擴展。這些改動可以大幅度地提升性能,和現在實現的最差情況相比,很容易實現 10 倍的性能提升,但實質上整體性能的提升可能沒有這麼大。
  • 緩存動態和靜態內容。如果有一個服務器已經過載了,它既是 Web 服務器又是應用服務器,通過緩存動態內容就可以在峰值時刻提升 10 倍的性能。緩存靜態文件也能實現個位數字的性能提升。
  • 壓縮數據。利用多媒體文件的壓縮格式,比如圖片採用 JPEG 格式、圖像採用 PNG 格式、電影採用 MPEG-4 格式、音樂採用 MP3 格式,這樣就能在很大程度上提升性能。一旦這些格式都用上,壓縮文本數據(代碼和 HTML)的頁面加載速度可以提升 2 倍。
  • 優化 SSL/TLS。安全握手對性能有很大影響,所以優化它們可以帶來 2 倍的改善,特別是文本很多的網站。在 SSL/TLS 條件下,優化多媒體文件改善很小。
  • 實現 HTTP/2 和 SPDY。當和 SSL/TLS 一起使用時,這些協議會讓整個網站的性能大幅度地提升。
  • 優化 Linux 和 Web 服務器軟件(例如 NGINX)。優化緩衝區、保持連接、將耗時的任務分散到一個獨立的線程池上都能大幅提升性能。比如線程池運用在對磁盤操作頻繁的任務上會帶來指數級的提速。

我們希望你自己嘗試下這些技術。

我們希望聽到你在某個應用程序上提升了性能。

你可以在下面的評論中分享你的結果!


分享到:


相關文章: