如果Node.js已具備反向代理的功能,我為什麼要使用反向代理?

銀河1號發表於2019-04-01

這一年是2012年.PHP和Ruby on Rails作為渲染Web應用程式的最高伺服器端技術而備受矚目。但是,一個大膽的新競爭者掀起了一場風暴 - 一個能夠處理1M併發連線的人。這項技術不過是Node.js,從那以後一直穩步增長。

與當時大多數競爭技術不同,Node.js內建了一個Web伺服器。擁有這個伺服器意味著開發人員可以繞過無數的配置檔案,例如檔案php.ini的分層集合
.htaccess。擁有內建的Web伺服器還提供了其他便利,例如在上載檔案時處理檔案的能力以及實現WebSockets的簡易性。

每天Node.js驅動的Web應用程式都會愉快地處理數十億個請求。世界上大多數最大的公司都以Node.js的某種方式供電。說Node.js是生產就緒的當然是輕描淡寫。但是,自Node.js誕生以來,有一條建議是正確的:不應該直接將Node.js程式暴露給Web,而應該隱藏在反向代理之後。但是,在我們搞清楚為什麼要使用反向代理之前,讓我們首先看一下它是什麼。

什麼是反向代理?

反向代理基本上是一種特殊型別的Web伺服器,它接收請求,將它們轉發到其他地方的另一個HTTP伺服器,接收回復,並將回覆轉發給原始請求者。

但是,反向代理通常不會傳送確切的請求。通常,它會以某種方式修改請求。例如,如果反向代理服務於www.example.org:80,並且要將請求轉發給
ex.example.org:8080它,它可能會重寫原始Host標頭以匹配目標標頭。它還可以通過其他方式修改請求,例如清除格式錯誤的請求或在協議之間進行轉換。

一旦反向代理接收到響應,它就可以以某種方式轉換該響應。同樣,常見的方法是修改Host標頭以匹配原始請求。請求的主體也可以更改。常見的修改是對響應執行gzip壓縮。另一個常見的變化是在底層服務只支援HTTP時啟用HTTPS支援。

反向代理也可以將傳入的請求分派給多個後端例項。如果服務是在暴露api.example.org,反向代理可以將請求轉發給api1.internal.example.orgapi2

那裡有許多不同的反向代理。其中兩個比較受歡迎的是NginxHAProxy。這兩個工具都能夠執行gzip壓縮並新增HTTPS支援,並且它們也專注於其他領域。Nginx是兩種選擇中比較流行的,並且還具有一些其他有益的功能,例如從檔案系統提供靜態檔案的能力,因此我們將在本文中使用它作為示例。

既然我們知道反向代理是

什麼
,我們現在可以看看
為什麼
我們想要使用Node.js。

我為什麼要使用反向代理?

SSL終止

SSL終止是使用反向代理的最常見原因之一。從改變那些應用程式的協議http,以https不是追加的多一點的工作s。Node.js的本身

能夠執行進行必要的加密和解密https,並且可以配置為讀取所需的證照檔案。

但是,配置用於與我們的應用程式通訊的協議以及管理過期的SSL證照並不是我們的應用程式需要關注的問題。將證照檢入程式碼庫不僅繁瑣,而且還存在安全風險。在應用程式啟動時從中心位置獲取證照也存在風險。

因此,最好在應用程式之外執行SSL終止,通常在反向代理中執行。感謝像Let's Encrypt這樣certbot的技術,使用Nginx維護證照就像設定一個cron作業一樣簡單。這樣的作業可以自動安裝新證照並動態重新配置Nginx程式。這是一個破壞性較小的過程,然後重新啟動每個Node.js應用程式例項。

此外,通過允許反向代理執行SSL終止,這意味著

只有
反向代理作者編寫的程式碼
才能
訪問您的私有SSL證照。但是,如果您的Node.js應用程式正在處理SSL,那麼您的應用程式使用的每個第三方模組(甚至可能是惡意模組  )都可以訪問您的私有SSL證照。

gzip壓縮

gzip壓縮是另一個應該從應用程式解除安裝到反向代理的功能。gzip壓縮策略是在組織級別最好設定的,而不必為每個應用程式指定和配置。

在決定gzip的內容時最好使用一些邏輯。例如,非常小,可能小於1kb的檔案可能不值得壓縮,因為gzip壓縮版本有時可能更大,或者讓客戶端解壓縮檔案的CPU開銷可能不值得。此外,在處理二進位制資料時,根據格式,它可能無法從壓縮中受益。gzip也是無法簡單啟用或禁用的東西,它需要檢查傳入的Accept-Encoding頭以獲得相容的壓縮演算法。

cluster

JavaScript是一種單執行緒語言,因此,Node.js傳統上是一個單執行緒伺服器平臺(但是,Node.js v10中目前實驗性的工作執行緒支援旨在改變這一點)。這意味著從Node.js應用程式獲得儘可能多的吞吐量需要執行與CPU核心大致相同數量的例項。

Node.js帶有內建cluster模組,可以做到這一點。將向主程式傳送傳入的HTTP請求,然後將其分派給叢集工作程式。

但是,動態擴充套件叢集工作人員需要付出一些努力。在排程主程式中執行額外的Node.js程式時,通常還會增加開銷。此外,跨不同計算機的擴充套件過程是cluster無法做到的。

出於這些原因,有時最好使用反向代理來分派執行Node.js程式的請求。這些反向代理可以動態配置為在新應用程式到達時指向它們。實際上,應用程式應該只關注自己的工作,它不應該關心管理多個副本和分派請求。

企業路由

在處理大型Web應用程式(例如由多團隊企業構建的應用程式)時,使用反向代理來確定將請求轉發到何處非常有用。例如,example.org/search/*可以將發出的請求路由到內部搜尋應用程式,同時example.org/profile/*可以將其他請求分派到內部配置檔案應用程式。

這樣的工具允許其他強大的功能,如粘性會話,藍/綠部署,A / B測試等。我個人在程式碼庫中工作,在應用程式中執行此類邏輯,這種方法使應用程式很難維護。

效能優勢

Node.js具有很強的可塑性。它能夠從檔案系統提供靜態資源,使用HTTP響應執行gzip壓縮,內建支援HTTPS以及許多其他功能。它甚至能夠通過模組執行應用程式的多個例項並執行自己的請求排程cluster

然而,最終讓反向代理為我們處理這些操作符合我們的最佳利益,而不是讓我們的Node.js應用程式執行它。除了上面列出的每個原因之外,想要在Node.js之外進行這些操作的另一個原因是效率。

SSL加密和gzip壓縮是兩個高度CPU繫結的操作。專用的反向代理工具,如Nginx和HAProxy,通常比Node.js更快地執行這些操作。像Nginx這樣的Web伺服器從磁碟讀取靜態內容也會比Node.js更快。甚至群集有時也會更有效,因為像Nginx這樣的反向代理將使用比其他Node.js程式更少的記憶體和CPU。

但是,不要相信我們的話。我們來做一些基準吧!

使用以下進行以下負載測試siege。我們使用併發值10(同時發出10個請求的使用者)執行命令,命令將執行直到進行20,000次迭代(對於200,000個總體請求)。

為了檢查記憶體,我們pmap <pid> | grep total在基準測試的整個生命週期中執行命令幾次,然後平均結果。當使用單個工作執行緒執行Nginx時,最終會執行兩個例項,一個是主伺服器,另一個是工作伺服器。然後我們將這兩個值相加。當執行Node.js叢集為2時,將有3個程式,一個是主程式,另外兩個是工作程式。下表中的近似記憶體列是給定測試的每個Nginx和Node.js過程的總和。

以下是基準測試的結果:

如果Node.js已具備反向代理的功能,我為什麼要使用反向代理?
基準測試結果

node-cluster基準測試中,我們使用2個worker。這意味著有3個Node.js程式在執行:1個master和2個worker。在nginx-cluster-node基準測試中,我們執行了2個Node.js程式。每個Nginx測試都有一個Nginx主伺服器和一個Nginx工作程式。基準測試涉及從磁碟讀取檔案,Nginx和Node.js都沒有配置為將檔案快取在記憶體中。

使用Nginx為Node.js執行SSL終止會導致吞吐量增加約16%(749rps到865rps)。使用Nginx執行gzip壓縮會導致吞吐量增加約50%(5,047rps至7,590rps)。使用Nginx管理程式叢集導致效能損失約-1%(8,006rps到7,908rps),這可能是由於在環回網路裝置上傳遞額外請求的開銷。

基本上,單個Node.js程式的記憶體使用量約為600MB,而Nginx程式的記憶體使用量約為50MB。根據所使用的功能,這些可能會略微波動,例如,Node.js 在執行SSL終止時使用額外的~13MB,而當用作反向代理時,Nginx使用額外的~4MB來提供來自檔案系統的靜態內容。值得注意的一件事是Nginx在其整個生命週期中使用了一致的記憶體量。但是,由於JavaScript的垃圾收集性質,Node.js不斷波動。

以下是執行此基準測試時使用的軟體版本:

  • Nginx的: 1.14.2
  • Node.js的: 10.15.3
  • 圍城: 3.0.8

測試是在具有16GB記憶體,i7-7500U CPU 4x2.70GHzLinux和Linux核心的機器上進行的4.19.10。重新建立上述基準測試所需的所有必要檔案均可在此處獲得:
IntrinsicLabs / nodejs-reverse-proxy-benchmarkmarks

簡化的應用程式程式碼

基準測試很好,但在我看來,將工作從Node.js應用程式解除安裝到反向代理的最大好處是程式碼簡單。我們可以減少潛在錯誤的命令式應用程式程式碼的行數,並將其交換為宣告性配置。開發人員普遍認為,他們對由外部工程師團隊(如Nginx)編寫的程式碼比對自己編寫的程式碼更有信心。我們可以在一個位置配置它,而不是安裝和管理gzip壓縮中介軟體並使其在各種Node.js專案中保持最新。我們可以改為使用現有的證照管理工具,而不是運送或下載SSL證照,重新獲取或重新啟動應用程式流程。我們可以將其解除安裝到另一個工具,而不是將條件新增到我們的應用程式以檢查程式是主程式還是工作程式。反向代理允許我們的應用程式專注於業務邏輯並忘記協議和流程管理。

儘管Node.js完全能夠在生產中執行,但使用具有生產HTTP Node.js應用程式的反向代理提供了無數的好處。SSL和gzip等操作變得更快。SSL證照的管理可以變得更簡單。所需的應用程式程式碼量也減少了。我強烈建議您在下一個生產Node.js應用程式時使用反向代理。

檢視英文原文

檢視更多文章

公眾號:銀河系1號

聯絡郵箱:public@space-explore.com

(未經同意,請勿轉載)


相關文章