NodeJS 大型非结构化JSON数据的编码/解码机制

nimxete2  于 2023-10-17  发布在  Node.js
关注(0)|答案(1)|浏览(98)

我有一个JSON数据,它可以有这样的结构,

[
    {
        "action": 4,
        "key1": {
            "key1": "key1",
            "key2": "key1",
            "key3": "key3",
            "key4": ["key4"],
            "key5": [
                {
                    "key5": "key5"
                }
            ]
        }
    },
    {
        "action": 2,
        "key2": [
            3,
            {
                "key121": "key1",
                "key21": "key1",
                "key33": "key3",
                "key4": ["key4"],
                "key5": [
                    {
                        "key5": "key5"
                    }
                ]
            },
            {
                "key121": "key1",
                "key2133": "key1",
                "key33333": "key3",
                "key41": ["key4"],
                "key521": [
                    {
                        "key531": "key5"
                    }
                ]
            }
        ],
        "key3": "key3",
        // .... more and more here
    }
// .... more and more here
]

大小可以超过1 MB。
数据只是一个例子,表明结构可以是非常动态的。我需要一些方法来编码/解码这种数据。流程如下

  • encode -> store在Redis中
  • 从Redis读取->解码

我需要的第二部分read from Redis -> decode的最佳性能的方式。因此,如果它的大小更小,它将减少从Redis获取的时间,然后我需要一种有效的方法来解码编码数据以获得JSON。
我已经厌倦了

JSON.stringify/JSON.parse-工作,但我需要更好的性能avschttps://www.npmjs.com/package/avsc)-它很好,但在我的情况下,因为我有一个非常动态的结构,我有很多问题,例如,在数组中有不同的record类型(据我所知,avsc不支持)等。
*msgpack-lite-不比JSON.stringify/JSON.parse更有效
*cbor-x-并不比JSON.stringify/JSON.parse更有效
*flatbuffers-https://www.npmjs.com/package/flatbuffers-基于模式-不适用于此情况
*schemapack-https://www.npmjs.com/package/schemapack对于简单对象来说还不错,但是已经7岁了
*protobufjs- https://www.npmjs.com/package/protobufjs - schema-based。

该过程将在负载下工作(每小时超过1500万次),因此性能是关键特征。
我的JSON.stringify/JSON.parse的基准测试结果来自10 k次迭代

  1. JSON解析
    总计20 ms
    平均迭代0.0016619213000001163ms
  2. JSON字符串化
    总计18 ms
    平均迭代0.0013616301999999764ms
    我承认,关键的性能将在decode部分。因此,如果decode占用的时间较少,则encode过程可能需要时间。
    一些基准代码示例
const data = require('./data.json');

class time {
    startTime = 0;

    init() {
        this.startTime = process.hrtime();
    }

    capture() {
        const end = process.hrtime(this.startTime);
        this.startTime = process.hrtime();
        return end[0] + end[1] / 1000000;
    }
}

const results = [];

const mainNow = Date.now();

const t = new time();

for (let i = 0; i < 1000; i++) {
    t.init();
    const stringified = JSON.stringify(data);
    JSON.parse(stringified);
    results.push(t.capture());
}

console.log('results', results);
console.log('total', Date.now() - mainNow);
console.log('avg', results.reduce((acc, curr) => acc + curr, 0) / results.length);
ulmd4ohb

ulmd4ohb1#

你可以给给予simdjson port for Node一个尝试。我以前用过它,对于我必须解析的JSON,它的速度几乎是JSON.parse的两倍。该库旨在利用现代CPU的功能来加速解析过程,使用矢量化等技术。
simdjson核心库是用C编写的,npm包是绑定到原生C库的Node.js。由于JavaScript和本机C++代码之间的互操作,您可能会遇到一些性能上的影响,但对于大型复杂的JSON文档,它通常仍然比使用JSON.parse更快。
使用npm install simdjson安装软件包后
你可以这样使用它:

const simdjson = require('simdjson');

// your JSON string from Redis
const redisData = `{
  "array": [
    1,
    2,
    3
  ],
  "boolean": true,
  "null": null,
  "number": 123,
  "object": {
    "a": "b",
    "c": "d",
    "e": "f"
  },
  "string": "Hello, world!"
}`;

const parsedJSON = simdjson.lazyParse(redisData);

// Now, you can manipulate `parsedJSON` as you would any other JavaScript object
console.log(parsedJSON.array); // Output: [ 1, 2, 3 ]
console.log(parsedJSON.string); // Output: "Hello, world!"

您的用例涉及从Redis示例接收JSON数据作为字符串。从Redis获取JSON字符串后,可以直接将其传递给simdjson.lazyParse()或库提供的其他解析方法。
lazyParse提供了一个“lazy”对象,它可能无法像原生JSON.parse那样处理所有边缘情况。如果遇到lazyParse问题,可以使用simdjson.parse()。
我没有运行它对您的性能测试,但它会是伟大的,如果你给予它尝试与您的真实的数据和共享的比较结果。

相关问题