>웹 프론트엔드 >JS 튜토리얼 >웹소켓용 JSON, 버퍼/사용자 정의 바이너리 프로토콜, Protobuf 및 MessagePack의 성능 분석

웹소켓용 JSON, 버퍼/사용자 정의 바이너리 프로토콜, Protobuf 및 MessagePack의 성능 분석

DDD
DDD원래의
2024-11-03 07:28:03299검색

이 문서에서는 데이터 직렬화 및 역직렬화 메서드/형식(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);
});

이 함수는 두 가지 속성(텍스트 속성과 숫자 속성)을 배열 버퍼직렬화합니다.

프로토부프

이 코드 예제에서는 protobufs의 자바스크립트 구현인 protobuf.js를 사용합니다. 나는 런타임에 protobuf 코드를 생성하기 위해 리플렉션을 사용합니다. 코드를 정적으로 생성할 수도 있지만 protobuf.js wiki에 따르면 성능에 영향을 주지 않습니다. 하지만 protobuf 코드를 더 빠르게 로드하지만 웹소켓 메시지를 보낼 때 성능에 전혀 영향을 주지 않습니다.

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);
})

성능 벤치마크

데이터 직렬화 형식/방법의 성능을 비교하기 위해 웹소켓을 통해 데이터를 전송할 때 성능을 측정하는 벤치마크를 작성했습니다.

벤치마크를 여러 그룹으로 나누었습니다.

  • 작은 데이터 입력

  • 중간 데이터 입력

  • 빅데이터 입력

이는 다양한 데이터 크기에 대한 데이터 직렬화 성능을 측정하기 위한 것입니다. 그룹별로 직렬화, 역직렬화, 총 시간의 성능도 녹음했습니다. 이러한 테스트의 신뢰성을 보장하기 위해 각 그룹에 대해 정확한 벤치마크를 5회 실행하고 평균을 계산했습니다.

벤치마크는 100,000번의 반복으로 Websocket 메시지를 보냅니다. 코드는 Bun.js로 작성되었습니다

이 벤치마크는 완료 시간(ms)에 기록되었으므로 작을수록 빠릅니다.

소규모 데이터 벤치마크

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

직렬화 시간(ms)

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

역직렬화 시간(ms)

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

역직렬화(ms)

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

역직렬화(ms)

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

MessagePack이 약 6600개의 메시지를 보내자 갑자기 작동이 중단되었습니다.

벤치마크 분석

모든 벤치마크에서 사용자 정의 바이너리 프로토콜 전체 시간이 가장 빠르며 직렬화 시 가장 작고 효율적인 바이트 크기를 가집니다. 메시지. 하지만 성능 차이는 상당합니다.

놀랍게도 JSON'의 직렬화 시간은 JSON의 직렬화보다 훨씬 빠릅니다 사용자 정의 바이너리 프로토콜. 이는 아마도 JSON.stringify()가 Node로 네이티브 c를 구현하고 Bun으로 네이티브 zig를 구현했기 때문일 것입니다. Bun이 포함된 JSON.stringify()가 Node보다 3.5배 빠르기 때문에 Node를 사용할 때 결과가 달라질 수도 있습니다.

이 벤치마크에서는 공식 javascript MessagePack 구현을 사용했기 때문에 MessagePack이 잠재적으로 더 빠를 수 있습니다. MessagePackr와 같이 잠재적으로 더 빠른 다른 MessagePack 구현이 있습니다.

읽어주셔서 감사합니다!


벤치마크(타입스크립트로 작성): https://github.com/nate10j/buffer-vs-json-websocket-benchmark.git

Google 시트에서 결과를 확인하세요.

위 내용은 웹소켓용 JSON, 버퍼/사용자 정의 바이너리 프로토콜, Protobuf 및 MessagePack의 성능 분석의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.