ホームページ >ウェブフロントエンド >jsチュートリアル >Websocket 用の JSON、バッファー/カスタム バイナリ プロトコル、Protobuf、および MessagePack のパフォーマンス分析

Websocket 用の JSON、バッファー/カスタム バイナリ プロトコル、Protobuf、および MessagePack のパフォーマンス分析

DDD
DDDオリジナル
2024-11-03 07:28:03290ブラウズ

この記事では、データのシリアル化と逆シリアル化のメソッド/形式: JSON、バッファー (カスタム バイナリ プロトコル)、Protobuf、および MessagePack を調査および比較し、それらの実装方法に関するガイダンスを提供します。 。 (最後のパフォーマンスベンチマーク)

JSON

これは、メッセージを送信する最も一般的な方法である JSON です。データを文字列にエンコードして、Websocket メッセージを通過させて解析できるようにします。

ws.send(JSON.stringify({greeting: "Hello World"]}))

ws.on("message", (message) => {
    const data = JSON.parse(message);
    console.log(data)
})

カスタムバイナリプロトコル

カスタム バイナリ プロトコルは、データのシリアル化逆シリアル化の軽量カスタム実装です。 速度パフォーマンス低遅延が重要な場合によく使用されます。 オンライン マルチプレイヤー ゲーム など (またはアプリを最適化したい場合)。 カスタム バイナリ プロトコルを構築するときは、バッファとバイナリを操作することになります。これは実装が難しい場合がありますが、バッファとバイナリの知識があれば問題ありません。

const encoder = new TextEncoder();
const decoder = new TextDecoder();

function binary(text, num) {
    const messageBytes = encoder.encode(text);
    // array buffers cannot store strings, so you must encode
    // the text first into an array of binary values
    // e.g. "Hello World!" -> [72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33]

    const buffer = new ArrayBuffer(1 + messageBytes.length);
    // when creating array buffers,
    //you must predetermine the size of your array buffer

    const view = new DataView(buffer);
    // create a view to interact with the buffer

    view.setUint8(0, num);

    const byteArray = new Uint8Array(buffer);
    byteArray.set(messageBytes, 1);

    return buffer;
}

ws.on("open", () => {
    const msg = binary("Hello World!", 123);
    ws.send(msg);
})

ws.on("message", (message) => {
    const buffer = message.buffer;
    const view = new DataView(buffer);
    const num = view.getUint8(0);
    const textLength = buffer.byteLength - 1
    const textBytes = new Uint8Array(buffer, 1, textLength);
    const text = decoder.decode(textBytes);

    console.log(text, num);
});

この関数は、2 つのプロパティを シリアル化し、1 つはテキストで、もう 1 つは数値で 配列バッファに入れます。

プロトブフ

このコード例では、protobufs の JavaScript 実装である protobuf.js を使用します。リフレクションを使用して、実行時に protobuf コードを生成します。コードを静的に生成することもできますが、protobuf.js wiki によるとパフォーマンスには影響しません。ただし、protobuf コードの読み込みは速くなりますが、WebSocket メッセージの送信時のパフォーマンスにはまったく影響しません。

syntax = "proto3";

message TestMessage {
    string text = 1;
    uint32 num = 2;
}
import protobuf from "protobufjs";

const ws = new Websocket("ws://localhost:3000");
ws.binaryType = "arraybuffer";

protobuf.load("testmessage.proto", function (err, root) {
    if (err)
        throw err;

    if (root === undefined) return;

    const TestMessage = root.lookupType("TestMessage")

    ws.on("open", () => {
        const message = TestMessage.create({text: "Hello World!", num: 12345});
        const buffer = TestMessage.encode(message).finish();
        ws.send(buffer);
    });

    ws.on("message", (msg) => {
        const buffer = new Uint8Array(msg);
        const data = TestMessage.decode(buffer);
        console.log(data.text);
        console.log(data.num);
    });
})

メッセージパック

import { encode, decode } from "@msgpack/msgpack";

ws.binaryType = "arraybuffer"

ws.on("open", () => {
    const msg = encode({"Hello World!", 123});
    ws.send(msg);
})

ws.on("message", (msg) => {
    const data = decode(msg);
    console.log(data);
})

パフォーマンスベンチマーク

データシリアル化形式/メソッドのパフォーマンスを比較するために、Websocket経由でデータを送信するときのパフォーマンスを測定するベンチマークを作成しました。

ベンチマークをさまざまなグループに分割しました。

  • 少量のデータ入力

  • 中データ入力

  • ビッグデータ入力

これは、さまざまなデータ サイズにわたるこれらのデータのシリアル化のパフォーマンスを測定するためです。各グループのシリアル化、デシリアル化、合計時間のパフォーマンスも記録しました。これらのテストの信頼性を確保するために、各グループに対して正確なベンチマークを 5 回実行し、平均を計算しました。

ベンチマークは 100,000 回の反復で Websocket メッセージを送信します。コードはBun.js

で書かれています

これらのベンチマークは終了までに時間内 (ミリ秒) で記録されたため、 小さいほど高速です.

小規模データのベンチマーク

ws.send(JSON.stringify({greeting: "Hello World"]}))

ws.on("message", (message) => {
    const data = JSON.parse(message);
    console.log(data)
})

各シリアル化フォーマットのバイトサイズ

Method Byte size (bytes)
JSON 33
Custom Binary Protocol 13
Protobuf 17
MessagePack 24

合計時間 (ミリ秒)

Performance Analysis of JSON, Buffer / Custom Binary Protocol, Protobuf, and MessagePack for Websockets

シリアル化時間 (ミリ秒)

Performance Analysis of JSON, Buffer / Custom Binary Protocol, Protobuf, and MessagePack for Websockets

逆シリアル化時間 (ミリ秒)

Performance Analysis of JSON, Buffer / Custom Binary Protocol, Protobuf, and MessagePack for Websockets

中規模データのベンチマーク

const encoder = new TextEncoder();
const decoder = new TextDecoder();

function binary(text, num) {
    const messageBytes = encoder.encode(text);
    // array buffers cannot store strings, so you must encode
    // the text first into an array of binary values
    // e.g. "Hello World!" -> [72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33]

    const buffer = new ArrayBuffer(1 + messageBytes.length);
    // when creating array buffers,
    //you must predetermine the size of your array buffer

    const view = new DataView(buffer);
    // create a view to interact with the buffer

    view.setUint8(0, num);

    const byteArray = new Uint8Array(buffer);
    byteArray.set(messageBytes, 1);

    return buffer;
}

ws.on("open", () => {
    const msg = binary("Hello World!", 123);
    ws.send(msg);
})

ws.on("message", (message) => {
    const buffer = message.buffer;
    const view = new DataView(buffer);
    const num = view.getUint8(0);
    const textLength = buffer.byteLength - 1
    const textBytes = new Uint8Array(buffer, 1, textLength);
    const text = decoder.decode(textBytes);

    console.log(text, num);
});

各シリアル化形式でのメッセージのバイト サイズ

Method Byte size (bytes)
JSON 117
Custom Binary Protocol 70
Protobuf 75
MessagePack 102

合計時間 (ミリ秒)

Performance Analysis of JSON, Buffer / Custom Binary Protocol, Protobuf, and MessagePack for Websockets

シリアル化 (ミリ秒)

Performance Analysis of JSON, Buffer / Custom Binary Protocol, Protobuf, and MessagePack for Websockets

逆シリアル化 (ミリ秒)

Performance Analysis of JSON, Buffer / Custom Binary Protocol, Protobuf, and MessagePack for Websockets

ビッグデータベンチマーク

syntax = "proto3";

message TestMessage {
    string text = 1;
    uint32 num = 2;
}

各シリアル化形式でのメッセージのバイト サイズ

Method Byte size (bytes)
JSON 329
Custom Binary Protocol 220
Protobuf 229
MessagePack 277

合計時間 (ミリ秒)

Performance Analysis of JSON, Buffer / Custom Binary Protocol, Protobuf, and MessagePack for Websockets

シリアル化 (ミリ秒)

Performance Analysis of JSON, Buffer / Custom Binary Protocol, Protobuf, and MessagePack for Websockets

逆シリアル化 (ミリ秒)

Performance Analysis of JSON, Buffer / Custom Binary Protocol, Protobuf, and MessagePack for Websockets

MessagePack は、メッセージが約 6600 件送信された時点で突然動作を停止しました。

ベンチマークの分析

すべてのベンチマークで、カスタム バイナリ プロトコル が合計時間で最速です、シリアル化時のバイト サイズが最小/最も効率的ですメッセージ。ただし、パフォーマンスの違いは顕著です。

驚くべきことに、JSONのシリアル化時間は、 のシリアル化よりも大幅に高速です カスタム バイナリ プロトコル。これはおそらく、JSON.stringify() が Node ではネイティブ c で実装され、Bun ではネイティブ zig が実装されているためです。 Bun を使用した JSON.stringify() は Node.

より 3.5 倍高速であるため、Node を使用する場合も結果が異なる可能性があります。

このベンチマークでは公式の JavaScript MessagePack 実装を使用したため、MessagePack の方が高速になる可能性があります。 MessagePackr など、他の潜在的に高速な MessagePack 実装もあります。

読んでいただきありがとうございます!


ベンチマーク (typescript で記述): https://github.com/nate10j/buffer-vs-json-websocket-benchmark.git

結果は Google スプレッドシートでご覧いただけます。

以上がWebsocket 用の JSON、バッファー/カスタム バイナリ プロトコル、Protobuf、および MessagePack のパフォーマンス分析の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。