- 原文地址:Millions of active WebSockets with Node.js
- 原文做者:Alex Hultman
- 譯文出自:掘金翻譯計劃
- 本文永久連接:github.com/xitu/gold-m…
- 譯者:Mirosalva
- 校對者:portandbridge,sunui
僅使用消費級筆記本和一些 Wifi 資源即可提供大量的 WebSocket 服務前端
經過最新發布的 TypeScript web 服務工程 uWebSockets.js,咱們看到它帶來的不只有提高的性能,還有提高的內存利用率。對 Node.js 使用者尤爲如此,因此爲了演示我想在實際使用環境中開展大規模的測試。node
咱們計劃使用我那購買了 6 年的筆記本電腦,它具備 8GB 運行內存和 72Mbit 速率的 Wifi 網絡適配器(這是網絡連接速度)的筆記本電腦。它還有一個 1Gbit 速率的以太網適配器,咱們能夠稍後使用。全部配置都是消費級的,在 2013 年購買後沒有任何硬件升級。這個筆記本將運行安裝了 uWebSockets.js v15.1.0 的 Node.js。android
咱們首先須要作一些 Linux 系統的配置工做 —— 主要是須要經過修改文件 /etc/security/limits.conf(在你的系統上文件路徑可能不一樣,我這裏用的是 Ubuntu 18.04 版本)來提高最大打開文件數量的限制。添加以下幾行:ios
* soft nofile 1024000
* hard nofile 1024000
複製代碼
而後咱們須要設置一些其餘變量(一樣的,你的路徑可能不一樣):git
sudo sysctl net.ipv4.tcp_tw_reuse=1
sudo sysctl fs.file-max=1024000
複製代碼
而後你須要須要配置某一網段內的大約 50 個 IP 地址。對於個人 Wifi 適配器,我添加了這行配置:github
for i in {135..185}; do sudo ip addr add 192.168.0.$i/24 dev wlp3s0; done
複製代碼
理論上,每一個 IP 地址有 65k 個鏈接限制,可是實際上限值常常大約在 20k 左右,因此咱們使用多個地址且使每一個地址支撐 20k 個鏈接數(50 * 20 千 = 1 百萬)。web
而後我使用命令 sudo -i 將 web 服務以 root 身份運行,這以後執行 ulimit -n 1024000 命令,接着對 node examples/WebSocket.js(在 uWebSockets.js 文件夾中)也這麼作。後端
真得就是這樣的。客戶端側作了相似的配置,可是顯然不須要設置多個 IP 地址。客戶端電腦運行一個由 uSockets 編寫的單線程 C 客戶端。這個測試的源代碼都是開源的,同時客戶端的代碼是位於 uWebSockets/benchmarks 文件夾的『scale_test.c』。你可能須要爲你本身的運行作一些小改動。bash
WebSocket 鏈接數量須要花幾分鐘才能達到 100 萬個,若是咱們想作的改進的話能夠增長每批次的鏈接數和使用多個線程的客戶端(諸如此類),可是這與咱們對服務端感興趣的點無關。服務端運行在單個線程上而且在鏈接階段或以後 CPU 佔用率都很低。服務器
首先,讓咱們討論一下 5k 個關閉的鏈接。uWebSockets.js 被配置爲丟棄和殺死全部閒置已超過 60s 的 WebSocket 鏈接。『idleTimeout』就被用到了,這意味着咱們須要在每 60s 就要與每 100 萬個 WebSocket 鏈接主動發送和接收一條 WebSocket 消息。
你能夠在這上面這張網絡圖中看到與 ping 消息相關的流量峯值。每秒最少有 16.7k 條 WebSocket 消息須要到達服務器 —— 都變少了以後咱們開始關閉鏈接。
顯然咱們經過 Wifi 網絡沒有很好地知足這個標準。咱們是丟失了一些鏈接,但在一個沒有花哨配置的 WiFi 網絡環境下仍存活 995k 個 WebSocket 鏈接倒是很酷的事情!
服務端的 CPU 使用率保持在 0–2% 範圍,用戶控空間內存使用大約爲 500MB 而總體系統範圍的內存使用大約爲 4.7GB。CPU 使用率或者內存使用一直都沒有出現服務端激增走勢,它始終處於徹底穩定狀態。
好吧!那麼讓咱們拿出大殺器吧 —— Ethernet。咱們將服務器和客戶端鏈接到 1Gbit 消費級路由器並從新運行測試:
結果是服務運行情況穩定,並且沒有鏈接丟失,WiFi 網絡穩定性不足可是 Ethernet 卻表現很好。爲了保證每項都是穩定的,我讓客戶端和服務器持續運行了一個小時,這樣沒有一個鏈接丟失,而後有約 1.2 億條 WebSocket 消息(16.7k * 60 * 60 * 2):
每項都是穩定良好運行。事實上,我在運行服務的筆記本上寫着本文,而且被關閉的 socket 鏈接數量始終爲 0,同時系統也是響應及時的。甚至我開啓一個簡單的遊戲的狀況下服務還能讓鏈接繼續。
此時咱們已經實現了一個很是酷的概念驗證場景。有一部分歸因於穩定的 Ethernet 鏈接,但固然很大程度上也依賴服務端軟件。任何其餘的 Node.js 軟件棧都沒法實現這一壯舉 —— 它們都不具有像這樣足以在筆記本上維持這麼多 WebSocket 鏈接的輕量級和高性能特色。你能夠在系統變得無響應時中止 swap 分區交換,而且下面看到的這樣來中止獲取 ping 結果:
使用 uWebSockets.js,咱們能夠在這檯筆記本上運行幾十萬個 WebSocket 鏈接,可是超過 100 萬的常規鏈接則須要從新編譯具有不一樣限制的 Linux 內核,這也是咱們把它做爲邊界值的緣由。
這裏咱們不打算去研究底層的嵌入式 C 開發,而且我認爲這是明智的選擇。只需啓動一個新應用實例,一臺新筆記本,經過這種方式繼續擴展你的問題。
若是你對這個軟件棧感興趣,有 I/O 擴展性問題,或者想要避免陷入許多常見陷阱,必定要聯繫咱們,咱們能夠經過公司對公司的形式來研討問題。
感謝你的閱讀!
若是發現譯文存在錯誤或其餘須要改進的地方,歡迎到 掘金翻譯計劃 對譯文進行修改並 PR,也可得到相應獎勵積分。文章開頭的 本文永久連接 即爲本文在 GitHub 上的 MarkDown 連接。
掘金翻譯計劃 是一個翻譯優質互聯網技術文章的社區,文章來源爲 掘金 上的英文分享文章。內容覆蓋 Android、iOS、前端、後端、區塊鏈、產品、設計、人工智能等領域,想要查看更多優質譯文請持續關注 掘金翻譯計劃、官方微博、知乎專欄。