[譯] Node.js 高性能和可擴展應用程序的最佳實踐 [第 2/3 部分]

第 2 章 —— 如何使您的 Node.js 應用程序安全擴展

上篇文章中,咱們學會了如何無需憂慮代碼,而水平擴展 Node.js 應用程序。本章中,咱們將討論擴展時必須注意的事項,以便在擴展流程時防止錯誤發生。前端

從 DB 中分離應用程序實例

本章首先要講的不是代碼,而是你的基礎架構node

若是你但願應用程序可以多主機擴展,則必須部署數據庫到一些獨立的主機,以即可以根據須要自由複製主機。android

在同一臺機器上部署應用程序和數據庫可能很便宜而且用於開發目的,但絕對不建議用於生產環境,其中應用程序和數據庫必須可以獨立擴展。這一樣適用於像 Redis 這樣的內存數據庫。ios

無狀態

若是您生成應用程序的多個實例,每一個進程都有本身的內存空間。這意味着即便您在一臺機器上運行,當您在全局變量中存儲某些值,或者更常見的是在內存中存儲會話時,若是負載均衡服務器在下一個請求期間將您重定向到另外一個進程,您將沒法在那裏找到它。git

這適用於會話數據和內部值,如任何類型的應用程序配置。github

對於可在運行時更改的設置或配置,一種解決方案是將它們存儲在外部數據庫(磁盤或內存中)上,以使全部進程均可以訪問它們。web

使用 JWT 進行無狀態身份驗證

身份驗證是開發無狀態應用程序時要考慮的首要問題之一。若是將會話存儲在內存中,它們將做用於該單個進程。redis

爲了使工做正常,您應該將網絡負載均衡服務器配置爲始終將同一用戶重定向到同一臺計算機,並將重定向到同一用戶的本地用戶始終重定向到同一進程(粘性會話)。數據庫

解決此問題的一個簡單方法是將會話的存儲策略設置爲持久性,例如將它們存儲在 DB 中而不是 RAM 中。可是,若是您的應用程序檢查每一個請求的會話數據,則每次 API 的調用都會有磁盤 I/O 操做,從性能的角度來看,這絕對不是好事。後端

更好,更快的解決方案(若是您的身份驗證框架支持它)是將會話存儲在像 Redis 這樣的內存數據庫中。Redis 實例一般位於應用程序實例外部,例如 DB 實例,但在內存中工做會更快。不管如何,在 RAM 中存儲會話會使您在併發會話數增長時須要更多內存。

若是您想採用更有效的無狀態身份驗證方法,能夠查看 JSON Web 令牌

JWT 背後的想法很簡單:當用戶登陸時,服務器生成一個令牌,該令牌本質上是包含有效負載的 JSON 對象的 base64 編碼,加上簽名得到的散列,該負載具備服務器擁有的密鑰。有效負載能夠包含用於對用戶進行身份驗證和受權的數據,例如 userID 及其關聯的 ACL 角色。令牌被髮送回客戶端並由其用於驗證每一個 API 請求。

當服務器處理傳入請求時,它會獲取令牌的有效負載並使用其密鑰從新簽名。若是兩個簽名匹配,則能夠認爲有效載荷有效且不被改變,還能夠識別用戶。

重要的是要記住 JWT 不提供任何形式的加密。有效負載僅在 base64 中編碼,並以明文形式發送,所以若是您須要隱藏內容,則必須使用 SSL。

jwt.io 用的如下模式恢復了身份驗證過程:

在認證過程當中,服務器不須要訪問存儲在某處的會話數據,所以每一個請求均可以由很是有效的方式由不一樣的進程或機器處理。RAM 中沒有保存數據,也不須要執行存儲 I/O 操做,所以在擴展時這種方法很是有用。

存儲在 S3 上

使用多服務器時,沒法將用戶生成的數據直接保存在文件系統上,由於這些文件只能由該服務器本地的進程訪問。解決方案是將全部內容存儲在外部服務上,可能存儲在像 Amazon S3 這樣的專用服務上,並在數據庫中僅保存指向該資源的絕對 URL。

而後,每一個進程/機器均可以以相同的方式訪問該資源。

使用 Node.js 的官方 AWS sdk 很是簡單,您能夠輕鬆地將服務集成到應用程序中。S3 很是便宜而且針對此目的進行了優化,在您的應用程序不是多進程的狀況下也是一個不錯的選擇。

正確配置 WebSockets

若是您的應用程序使用 WebSockets 進行客戶端之間或客戶端與服務器之間的實時交互,則須要連接後端實例,以便在鏈接到不一樣節點的客戶端之間正確傳播廣播或消息。

Socket.io 庫爲此提供了一個特殊的數據庫鏈接工具,稱爲 socket.io-redis,它容許您使用 Redis pub-sub 功能連接服務器實例。

爲了使用多節點 socket.io 環境,您還須要配置協議爲 「websockets」,由於長輪詢須要粘性會話才能工做。

下一步

在這篇簡短的文章中,咱們已經看到了一些關於如何擴展 Node.js 應用程序須要注意的事情,這對於單節點環境也能夠被視爲良好的實踐。

在本系列的下一篇文章(也是最後一篇文章)中,咱們介紹一些 Nodejs 的進階操做。你能夠在這裏找到它。


若是這篇文章對你有用,請給我點贊吧!

若是發現譯文存在錯誤或其餘須要改進的地方,歡迎到 掘金翻譯計劃 對譯文進行修改並 PR,也可得到相應獎勵積分。文章開頭的 本文永久連接 即爲本文在 GitHub 上的 MarkDown 連接。


掘金翻譯計劃 是一個翻譯優質互聯網技術文章的社區,文章來源爲 掘金 上的英文分享文章。內容覆蓋 AndroidiOS前端後端區塊鏈產品設計人工智能等領域,想要查看更多優質譯文請持續關注 掘金翻譯計劃官方微博知乎專欄

相關文章
相關標籤/搜索