跳至主要內容
Skip to content

高性能數據策略:Protocol Buffers 與 MessagePack 整合

在前面的章節中,我們討論了如何接通連線、解析數據幀並確保安全。但在生產環境中,另一個核心問題是:你傳輸的是什麼?

雖然 JSON 是 Web 的通用語言,但在處理高頻率(如每秒 60 次的位置更新)或大數據量時,JSON 的文字格式會造成顯著的頻寬浪費與解析壓力。本章我們將引進二進制序列化 (Binary Serialization) 來解決這個問題。


一、 為什麼 JSON 不夠好?

  1. 冗餘的標籤:屬性名稱字串都會佔用大量空間。
  2. 文字解析成本:瀏覽器與伺服器解析長 JSON 字串是非常耗 CPU 資源的過程。
  3. 無類型檢查:JSON 本身不具備強型別約束。

二、 強力工具:Protobuf vs MessagePack

技術特性適用場景
Protocol Buffers (Protobuf)基於 Schema (預定義格式),壓縮率最高。嚴格的 API 指令、跨語言大型系統。
MessagePack無須 Schema,隨插即用,壓縮率優於 JSON。快速原型開發、動態數據結構。

三、 實戰演練:Protobuf 整合

我們使用 protobufjs 在 Node.js 中實作動態數據壓縮。

1. 定義數據格式 (chat.proto)

proto
syntax = "proto3";

message ChatMessage {
  int32 id = 1;
  string user = 2;
  string content = 3;
  int64 timestamp = 4;
}

2. Node.js 壓縮與發送實作

javascript
const protobuf = require("protobufjs");
const WebSocket = require("ws");

protobuf.load("chat.proto", async (err, root) => {
  if (err) throw err;

  const ChatMessage = root.lookupType("ChatMessage");
  const wss = new WebSocket.Server({ port: 8080 });

  wss.on("connection", (socket) => {
    socket.on("message", (buffer) => {
      try {
        const message = ChatMessage.decode(buffer);
        console.log(`收到來自 ${message.user} 的消息: ${message.content}`);

        const payload = {
          id: 1,
          user: "Server",
          content: "已收到消息",
          timestamp: Date.now(),
        };
        const responseBuffer = ChatMessage.encode(
          ChatMessage.create(payload)
        ).finish();
        socket.send(responseBuffer);
      } catch (e) {
        console.error("解碼失敗:", e);
      }
    });

    socket.binaryType = "arraybuffer";
  });
});

總結

引進二進制協議雖然增加了開發成本,但在高流量場景下,它能顯著降低頻寬成本並提升應用流暢度。

下一章,我們將探討連線自癒機制:打造打不倒的 WebSocket 連線。


️ 進階挑戰

  1. 實作挑戰:嘗試安裝 msgpack-lite 庫,並對比同一個物件在 JSON、MessagePack 與 Protobuf 序列化後的 Buffer.length 差異。
  2. 版本共存:如果你的 Protobuf Schema 更新了(例如刪除了一個舊欄位),舊版的 Client 該如何保持相容?(提示:了解 Protobuf 的 Tag Number 原理)。

延伸閱讀與資源