天天看點

µWebSockets:性能達 Fastify 8.5x/Socket.IO 10x?

作者:進階前端進階

大家好,很高興又見面了,我是"進階前端‬進階‬",由我帶着大家一起關注前端前沿、深入前端底層技術,大家一起進步,也歡迎大家關注、點贊、收藏、轉發!

µWebSockets:性能達 Fastify 8.5x/Socket.IO 10x?

進階前端‬進階

今天給大家帶來的主題是最近因為 Bun運作時而大火的 µWebSockets,話不多說,直接進入正題。

1.什麼是µWebSockets

µWebSockets是簡單、安全且符合标準的 Web 伺服器,适用于要求最苛刻的應用程式。

µWebSockets:性能達 Fastify 8.5x/Socket.IO 10x?

圖檔來自:https://morioh.com/p/d76ceffb2a17

µWebSockets具有以下特點:

  • 優化的安全性:µWebSockets 針對速度和記憶體占用進行了精心優化,其速度足以執行加密的 TLS 1.3 消息傳遞,甚至比大多數替代伺服器執行未加密的明文消息傳遞的速度還要快。
  • 快速編寫腳本:µWebSockets 完全用 C 和 C++ 編寫,但與 Node.js 後端無縫內建。 這允許使用廣泛的能力快速編寫功能強大的應用程式的腳本。 除了支援與 Node.js 內建之外,開發者還可以使用 Bun,其中 µWebSockets 是 Bun 運作時内置 Web 伺服器。
  • 大量實戰證明:從 2016 年以來,µWebSockets一直完全符合标準,擁有完美的 Autobahn|Testsuite 分數。µWebSockets 為世界上許多最大的加密貨币交易所提供支援,每天處理數十億美元的交易量。
  • 開箱即用:圍繞具有通配符和參數支援的友善 URL 路由器設計 ,與高效的 WebSockets 釋出/訂閱功能相結合。 µWebSockets 應該是任何具有高要求的實時 Web 項目的明智選擇。

目前 µWebSockets 在Github上通過 Apache-2.0 協定開源,有超過 15.5k 的star、1.7k的fork、代碼貢獻者100+,是一個值得關注的前端開源項目。

2.詳述 µWebSockets 特性

符合标準

與其他“釋出/訂閱代理”不同,µWS不推動任何特定的應用程式協定,而是僅在原始的标準 WebSockets 上運作。 開發者隻需要一個符合标準的 Web 浏覽器和一些符合标準的 JavaScript 即可與之通信。

µWebSockets也不需要或強制執行特定的用戶端庫,這與 Socket.IO 等解決方案不同,在 Socket.IO 中,開發者最終會被鎖定到一組性能糟糕的專有非标準協定。

Socket.IO 支援實時雙向基于事件的通信,由一個 Node.js 伺服器和一個用于浏覽器(或 Node.js 用戶端)的 Javascript 用戶端庫組成。 支援衆多語言實作,包括:Java、C++、Swift、Dart、Python、.NET、Rust。具有諸多優秀特性,比如:可靠、自動重新連接配接、斷開檢測、二進制支援、跨浏覽器、多路複用支援等等。

高性能

µWebSockets實作僅包含頭檔案 C++17,跨平台并編譯為幾千位元組的微小二進制檔案,底層依賴于 µSockets。

µSockets 是 µWebSockets 使用的非阻塞、每個 CPU 一個線程(thread-per-CPU)的基礎庫。 µSockets 提供優化的網絡,在所有支援的傳輸、事件循環和平台上使用相同的不透明 API程式設計接口(QUIC 正在開發中,io_uring 也是如此)。

借助于 µSockets,µWebSockets 應用程式可以在諸多平台上運作,不需要任何代碼更改或特殊的執行路徑。進而實作通過 TCP 傳輸資料與通過 QUIC 傳輸資料一樣簡單。

µWebSockets:性能達 Fastify 8.5x/Socket.IO 10x?

µWebSockets的高性能

在性能方面,µWebSockets 相對于其他解決方案具有明顯的優勢,使用 SSL 的 µWS 明顯優于運作非 SSL 的最快 Golang 伺服器的消息案例。 從某種意義上說,開發者可以免費獲得 SSL(證明對于每條消息最多 4 kB 的消息傳遞是正确的)。

µWebSockets 公開展示了單個 Raspberry Pi 4 可以同時為超過 10 萬個非常活躍的 TLS 1.3 WebSockets 提供服務的詳細案例,并且具有出色的穩定性。 這對于絕大多數替代解決方案來說是完全不可能的。 在如此有限的硬體上,大多數解決方案都會變得不可靠。 同時,µWebSockets 與 Node.js 相比,支援每秒提供 12 倍的 HTTP 請求。

Raspberry Pi 4是一款單闆計算機,所謂單闆機是具有計算機功能的微型計算機,印刷闆上有中央處理機、記憶體儲器、外圍裝置、接口等主要部件。

使用簡單

µWebSockets的另一個目标是極簡主義、簡單和優雅。 它遵循類似 ExpressJS 的界面,開發者可以在其中将回調附加到不同的 URL 路由, 這樣就可以在幾行代碼中輕松建構完整的 REST/WebSocket 服務。

心跳逾時、背壓處理等繁瑣的邏輯由庫本身高效、輕松處理。 同時,該項目是異步的,并且在一個線程本地運作。 開發者将其擴充為單獨的線程,就像 Node.js 擴充為單獨的程序一樣(也就是說,實作隻看到一個線程并且不是線程安全的)。 但是,如果确實需要,有一些簡單的方法可以通過異步委托進行線程處理。

編譯

µWebSockets 可以在任何平台上編譯, 但是正如前面所說它依賴于 µSockets,即在 Linux、Windows 和 macOS 上運作的特定于平台的 C 代碼。

µSockets 有一些編譯标志,但 µSockets 和 µWebSockets 标志之間有以下共同點:

  • LIBUS_NO_SSL :為 uSockets 和 uWebSockets 建構禁用 OpenSSL 依賴/功能
  • UWS_NO_ZLIB : 為 uWebSockets 禁用 Zlib 依賴/功能

3.µWebSockets 如何用于Node.js環境

µWebSockets.js 是 Node.js 中的 Web 伺服器實作,它在高度優化的 C++ 中重新實作事件、網絡、加密、Web 協定、路由和釋出/訂閱。 是以,µWebSockets.js 可以為 Node.js 提供 Web 服務,是 Fastify 的 8.5 倍,至少是 Socket.IO 的 10 倍, µWebSockets.js 也是 Bun 内置的 Web 伺服器。

µWebSockets:性能達 Fastify 8.5x/Socket.IO 10x?

µWebSockets.js的目标是用符合标準、輕量級和高性能的堆棧完全取代 ExpressJS 和 Socket.io。 目前 µWebSockets.js 确實在性能上也完勝其他更流行的庫,比如: websockets 和 ws。

下面是µWebSockets.js的使用示例:

/* Non-SSL is simply App() */
require('uWebSockets.js').SSLApp({
  /* 這裡支援衆多的SSL配置 */
  key_file_name: 'misc/key.pem',
  cert_file_name: 'misc/cert.pem',
}).ws('/*', {

  /* 有許多常見的幫助功能 */
  idleTimeout: 32,
  maxBackpressure: 1024,
  maxPayloadLength: 512,
  compression: DEDICATED_COMPRESSOR_3KB,

  /* 為簡潔起見,跳過其他事件,比如:upgrade, open, ping, pong, close */
  message: (ws, message, isBinary) => {
    /* 也可以執行 app.publish('sensors/home/temperature', '22C') 類型的釋出/訂閱*/
    /* 在這裡可以回顯消息,還可以壓縮*/
    let ok = ws.send(message, isBinary, true);
  }
  
}).get('/*', (res, req) => {
  /* It does Http as well */
  res.writeStatus('200 OK').writeHeader('IsExample', 'Yes').end('Hello there!');
}).listen(9001, (listenSocket) => {

  if (listenSocket) {
    console.log('Listening to port 9001');
  }
  
});
           

3.1 編譯 µWebSockets 二進制檔案

在大多數情況下,開發者可以直接執行 npm install uNetworking/uWebSockets.js#v17.3.0 并直接擷取預建構的二進制檔案。 但是,如果遇到 µWS 版本與 Node.js 建構不相容的問題,則必須在目标機器上編譯二進制檔案:

// 克隆倉庫 w/ submodules
git clone --recursive https://github.com/uNetworking/uWebSockets.js.git
//Cd 到指定目錄
cd uWebSockets.js
// build編譯
make           

如果要部署到 CentOS 伺服器上,則必須在 build.c 中将編譯器從 clang 更改為 gcc:

// Change from
build("clang", "clang++", "-static-libstdc++ -static-libgcc -s", OS, "x64");
// To this
build("gcc", "g++", "-static-libstdc++ -static-libgcc -s", OS, "x64");           

3.2 µWebSockets用于伺服器端

初始設定

下面從一個簡單的模闆開始:

// server.js
const uWS = require('./uws.js');
const { uuid } = require('uuidv4');
const port = 7777;
let SOCKETS = [];
const app = uWS.App()
  .ws('/ws', {
    // config
    compression: 0,
    maxPayloadLength: 16 * 1024 * 1024,
    idleTimeout: 60,
    open: (ws, req) => {
      // this handler is called when a client opens a ws connection with the server
    },
    message: ws => {
      // called when a client sends a message
    },

    close: (ws, code, message) => {
      // called when a ws connection is closed
    }
  }).listen(port, token => {
    token ?
    console.log(`Listening to port ${port}`) :
    console.log(`Failed to listen to port ${port}`);
  });           

如果運作 node server.js 則可以在 ws://127.0.0.1:7777/ws 開始接收傳入的 ws 連接配接。

4.本文總結

本文主要和大家介紹一個最近因為Bun運作時而大火的µWebSockets。相信通過本文的閱讀,大家對 µWebSockets 會有一個初步的了解。

因為篇幅有限,文章并沒有過多展開,如果有興趣,可以在我的首頁繼續閱讀,同時文末的參考資料提供了大量優秀文檔以供學習。最後,歡迎大家點贊、評論、轉發、收藏!

參考資料

https://github.com/uNetworking/uWebSockets/blob/master/misc/READMORE.md

https://github.com/uNetworking/uWebSockets.js/

https://edisonchee.com/writing/intro-to-%C2%B5websockets.js/

https://github.com/socketio/socket.io

https://github.com/uNetworking/uSockets

https://morioh.com/p/d76ceffb2a17

https://ably.com/blog/whats-new-in-socketio-4

繼續閱讀