ARTICLE

提升Node.js在大規模上的效能的必要技巧

LATEST ARTICLE

提升Node.js在大規模上的效能的必要技巧

提升Node.js在大規模上的效能的必要技巧

監控並衡量您的應用程序性能

在您開始改善應用程式的效能之前,第一步應該是監控和測量其目前的效能狀態。這個測量過程將有助於檢測缺陷、低效率以及真正問題所在的領域。當完成測量後,您將需要根據找到的問題類型制定正確的策略,以獲得期望的結果。

要確定目前應用程式效能水準,您需要運行不同類型的測試,例如:
優勢 劣勢
機會
  • 隨著雲端計算和微服務架構的興起,node.js的非同步執行特性越來越受到企業青睞
  • 全球開源社群活躍且持續成長中,眾多開發者共享自己解決問題的策略和方法
  • 隨著iot、ai等新技術的出現, node.js也可以透過npm等套件庫快速地整合這些新的技術
  • node.js具備非阻塞i/o處理能力,能有效提升大規模資料處理的效率
  • node.js運行於v8引擎,性能極佳而且可以與前端javascript程式碼共享部分邏輯
  • node.js擁有豐富的套件庫npm,方便開發者尋找並使用所需模組
威脅
  • node.js在cpu密集型任務上表現不佳,若沒有正確優化可能會降低效能
  • 當node.js出現錯誤時,整個系統都會停止運作,需要投入額外資源進行異常管理及修復
  • 由於是單線程運行,在多核心cpu下無法充分利用硬體性能
  • 其它後端語言如python, go等在特定情況下可能表現得更優秀
  • 企業可能需要投入大量資源於訓練開發人員掌握node.js並優化其效能
  • 由於node.js是開源專案,如果社群未能持續維護或更新,可能會影響到長期使用的穩定性和可靠性
表: 強弱危機分析(最後更新: 2022-12-16)

壓力測試

這項測試是為了檢驗機器、網路、設備或程式代碼的能力而設計和開發的。它可以在正常工作條件之外測試系統的表現。主要目的是研究系統的潛力,即在何種程度上能夠容忍失敗,以及在失敗後如何恢復。

重點改寫版本: 這項測試旨在評估機器、網路、設備或程式代碼的能力,並非常重要。它可以模擬出異於正常工作狀況下系統的運作情況,以便深入探究其性能表現。此測試主要關注於分析系統可能具有的潛在問題,在什麼情況下會發生錯誤以及如何處理錯誤後重新恢復正常運作。


負載測試

這是一個評估應用程式負載的過程,模擬真實工作負載並測量應用程式的回應和使用情況。此外,在導致失敗之前,您還可以測試應用程式能夠承受多大負荷。 改編版本: 這個過程是為了評估應用程式的負載情況,模擬真實工作情境並測量其回應和使用情形。

同時,也能夠測試出在造成失敗之前,該應用程式所能承受的最大負荷。

突發測試

這有助於評估您的應用程式在遭遇大規模但意外上升或下降負載時的行為。

可擴展性測試

這是用來測試負載,以衡量應用程式在突然的高峰或低谷時對大量使用者請求負荷的能力。

容量測試

進行測試以瞭解應用程式在大量數據下的表現或行為。當您完成任何一項或全部上述測試時,您將獲得幾個重要的指標,例如平均延遲、回應時間、錯誤率、每秒請求數、輸送量、CPU和記憶體使用率、同時使用者等。下一步是重新執行測試,儘管您已實施特定的優化措施。

這次重新測試將幫助您驗證您的更改是否如預期地對系統或應用程式的性能產生了所需的結果。另外,保持追蹤您的應用程式或系統的性能也很重要。為此,您應該使用(APM)應用程式性能監控並保持追蹤以觀察性能情況。

有不同的監控工具和解決方案可供APM使用,我們建議使用NewRelic和AppSignal。兩者都易於使用且可以輕鬆集成到應用程式中。安裝後,只需運行以下命令即可:npx @appsignal/cli install。

這將自動提供多個性能指標的追蹤,如回應時間、輸送量、錯誤日誌、系統可用性、主機指標等。

快取有助於降低延遲時間

為了提升網頁應用程式的效能,其中一個最重要的策略就是進行資料快取。資料快取的主要目的是通過減少計算操作和I/O操作來提高數據檢索速度,也就是從網絡或數據庫中獲取數據。快取,也被稱為「臨時電腦記憶體」,是一個高速數據存儲層,它存儲了部分數據。

它阻止了頻繁地從主要數據存儲位置中檢索數據的請求,並從已存儲的數據中回答該請求。這節省了時間,對查詢作出更快速的回覆,並提供更好的用戶體驗。大多數請求都是常見且頻繁發生的,在不常變動。

如果您的應用程式收到一個關於未變動資料的請求,我們可以將其存儲起來,在未來同類型查詢時使用它進行回覆。快取是回覆相同類型請求的理想選項。它肯定會提升這些請求的效能並增強其性能。

此外,它還可以幫助我們防止伺服器資源因所有這些冗餘計算數據呼叫而被卡住或不必要地下降。這是有關由內部伺服器回覆的請求的全部內容。那麼,對於協力廠商API查詢呢?這些也是使用快取的經典情況。

快取將幫助我們從外部系統中獲取數據,存儲它並安全地重用於未來的請求中。在這種情況下,我們可以將API請求存儲在「快取層」中,以避免額外的網絡請求和與此類API呼叫相關的成本開銷。在應用程式中有幾種方式可以進行快取,包括: 內部快取解決方案、分佈式快取解決方案等等。


進程內快取

將我們經常使用的數據存儲在內存中,可以更快地檢索出來。例如:node-cache 安裝:npm install node-cache --save 在進程內緩存解決方案的缺點是它與應用程式進程相關聯,對於分佈式工作流程並不完全適用,特別是在緩存可變對象(一個在創建後其狀態可以改善的對象)時。

分散式快取解決方案

你可以使用分散式快取解決方案,例如Redis或Memcached。這兩種解決方案都可以獨立運行在應用程式上。此外,當將應用程式擴展到多個伺服器時,這些解決方案更加實用。


建議事項

如果你的項目是一個簡單的小應用程式或者一個小規模項目,那麼請選擇在進程中使用快取解決方案。當你有計劃在未來調整你的應用程式時,你始終可以選擇Redis作為分佈式快取解決方案。

帶有超時的I/O操作

Timeouts 是在構建 Node.js 應用程式時最容易應用的方式,以防止發生不必要的延遲。假設你擁有一個可能與其他外部服務互動且可能依賴並調用其他服務的伺服器。看起來你沒有對伺服器有完全控制權。

在這種情況下,如果任何一個服務變慢或無響應,將會造成緩慢或糟糕的使用者體驗。由於你無法對伺服器有完全控制權,不能保證你的相依性能像平常那樣迅速回應,儘管你沒遭遇到這些問題。這就是超時(timeout)的重要性所在。

讓我們更深入地理解這一點。超時是開發人員在後端設定給使用者固定等待時間限制的一種方式,它被設置在請求上。背後的原因是告知和準備客戶端他們需要等待多久才能收到回應。

當客戶端提出請求後,在預定時間內如果沒有回應,連線將自動中斷。這可以防止應用程式陷入無限的卡住狀態。參考範例,Node.js 中的 HTTP 請求。

注意:預設情況下,Axios 呼叫不會設置任何超時,所以你需要添加一個請求超時來防止這種情況發生:在這裡,對所有通過 axios 進行的 HTTP 請求設置了 2000 毫秒(2 秒)的默認超時。注意:Axios 的超時值是讀取超時,與連線超時不同。讀取超時更快,而連線超時比它低得多。


停止使用Node.js提供靜態資源和資產

為了讓您的Node.js伺服器達到最佳效能,請確保不要將它們用於從伺服器本身提供靜態資源,例如JavaScript、CSS或應用程式的圖片檔案等。Node.js並非設計成以此方式運作。因此,當主應用程式提供資產時,會消耗寶貴的資源並影響重要的業務計算。

將提供靜態檔案的任務轉移到像Nginx這樣的網頁伺服器上。通常它會執行一些在Node.js中沒有意義的優化工作。這項測試顯示Nginx在傳送靜態資產方面比Node.js快兩倍(使用Express static middleware)。

另一種停止提供靜態資源的方法是通過設置像Amazon CloudFront這樣的CDN代理來顯示靜態文件,以便將您的靜態內容快取並盡可能接近最終用戶端提供服務。這項活動將阻止Node.js提供靜態資源,只處理動態請求。

自動化負載平衡器:跨多台機器進行擴展

分擔負荷可以增強承受巨大重量的輪承的壽命、長久性和容量。基本原理很清楚,觀眾越多,管理他們所需的空間就越多。在這裡,為了擴展Node.js應用程式的性能,您只需要將流量分散到多台機器上。

當您將流量分配到多台機器上時,可以確保用戶享受不中斷的服務。另一個聰明的做法是將多個負載等化器製作並指向同一組伺服器和請求,以提供快速響應並避免任何故障。NodeJS express是負載平衡的一個例子:如果負載平衡工作正常,則控制台輸出可能如下所示:

通過集群改善吞吐量

分群是將具有相似特徵的群組分開,並將它們分配到不同的簇中。在您的Node.js應用程式中,叢集用於通過為並行運行的工作程式創建單獨的單一埠,以在單台機器上水準劃分服務器。這是一種簡單且常見的技術,通過將連接分散到所有不同的叢集中,讓CPU核心充分利用,從而降低停機時間、故障、無響應和減速等問題。

對於將叢集化到您的Node.js應用程式中,主要原因是它只運行在單個線程上,無法很好地利用多核系統。是的,您可以使用標準庫中的叢集模塊來叢集化您的Node.js服務器。以下是來自Standard Cluster模塊的代碼示例: 當您運行此程式時,發送到埠3000 的連接將在工作進程之間共用。

透過使用PM2進程管理器, 您可以得到最佳可靠性管理Node.js叢集處理方案. PM2 允許您處理工作進程的生成、在工作進程之間分配傳入負載,以及停止或重啟工作進程。此外, 它還可幫助我們監控和調整工作進程的性能。
相關數據:
  • 根據stack overflow 2020年開發者調查,約49.9%的專業開發者使用node.js。 來源: stack overflow
  • 根據indeed.com的數據,美國node.js開發人員的平均年薪為114,402美元。 來源: indeed.com
  • 在github上,node.js有超過71k的star數量和17.7k個forks(截至2021年6月)。 來源: github
  • 在全球top 10,000的網站中,3.8%使用node.js作為其後端程式語言。 來源: builtwith
  • 根據w3techs的統計數據,在所有使用javascript作為服務器端程式語言的網站中,約2.1%選用了 node.js。 來源: w3techs

提升你的Node.js app性能的額外建議

現在你已經知道了一些重要的技巧,可以用來改善性能。但是,這些技巧還不止於此。下面我們列出了一些關鍵的微優化步驟,可以讓你更好地提升Node.js應用程式的性能。

最好的總是保證最好的結果。當你正在改進應用程式的性能時,請始終使用最新版本的Node.js。依賴通常會束縛你的創造力、力量和時間。

請密切關注你所依賴的庫,並盡可能選擇性能最佳的庫來避免它們對你的應用程式性能產生負面影響。建立基本理解和編碼技巧,以便在遇到困難且時間緊迫時,可以自己編寫代碼並即時修復問題。避免使用依賴庫有助於提高Node.js應用程式的性能。

例如:最大程度地利用內建方法和庫,如lodash、Node-cache 確保獨立I/O操作使用異步原語,如回調、Promise、Async/Await。使用這些原語可以改善下游延遲並確保操作流程無縫。 例如:在開始任何實現之前,列出所有獨立的查詢調用,並使用Promise.all將這些個別的獨立查詢進行並行調用。

這一步驟可以減少每個單獨連接和查詢調用的時間,直到找到通常需要最長時間響應的那個。 例如:將單獨的查詢調用推送到數組中。使用Node.js流以實現最佳內存效率和降低延遲,特別是處理大量數據時。

確保批處理分析、報告或下載/導出表格。 數據庫連接:確保具有主從複製的數據庫連接。如果你想要顯示目錄目的搜索結果, 數據庫連接器必須使用Secondary Preferred Read Replica OR Master-Slave Replication。

為了防止你的數據庫查詢變成死鎖,你應該定期進行優化並適當地擴展它們。避免執行聚合查詢或多表聯接。最佳實踐是處理聚合、平均值、最大值等情況時,只需使用選擇查詢並找到替代方法解決問題。

例如:可以通過簡單的選擇查詢來收集這些結果,而不是使用平均值和最大值查詢。始終使用預定義的投影進行查詢調用 - 對於任何SQL或NoSQL數據庫,如MongoDB和MySql等。這意味著你只需要對所需的列執行查詢。

然後,數據庫查詢將僅為所需的列運行,不會提取不需要的列。應避免子查詢。如果必要,在特定情況下可以執行智慧條件邏輯和函數。

你可以選擇使用合適的索引以加快搜索速度。在循環中省略查詢調用。不要在任何循環中添加查詢調用。

你可以通過一次調用和連接使用智慧的條件方法。 例如,你可以準備一個數組並使用IN語句在一次調用和連接中收集所有數據。 這些是關於Node.js應用程式性能優化和改進的一些額外提示,你可以在開發階段注意到並加以處理。

不是所有的階段都薄弱。因此,請對那些需要優化的地方進行優化。一旦你確定了應用程式的熱點,你應該從特定區域開始優化工作。

注意:熱點可能會隨時間而變化,所以你需要不斷測試應用程式。你可以使用NewRelic、AppSignal等工具來跟蹤任何新的變化。

留言

文章隨選