Я работал с функцией Lambda, где CSV предоставляется в качестве входных данных, а такие операции, как сопоставление полей с базой данных, обработка полей и расчеты, выполняются в CSV. CSV может иметь 20 миллионов записей, поэтому одновременная работа с полным CSV была немного дорогостоящей операцией, поэтому мы запускали ее партиями. Одной из операций, выполняемых с каждой строкой CSV, было сопоставление ее с данными Mysql, что создавало большую нагрузку на сервер Mysql из-за большого количества запросов, выполняемых в MySQL. Поэтому, чтобы решить эту проблему, мы создали файл JSON из запроса MySQL, поскольку знали, что данные таблицы не будут регулярно меняться.

В тот момент мы не знали, что для того, чтобы сделать это быстрее, мы можем в конечном итоге использовать больше памяти. когда JSON был загружен в память, он занимал ~ 700 МБ места, что было удивительно, потому что файл JSON весил всего около 60 МБ, и это заставило нас задуматься о том, как JSON загружается в память?

Чтобы понять, как JSON хранится в памяти, я задал вопрос на StackOverflow и получил один ответ, который объясняет это, цитируя ответ ниже:

Длина строки JSON и размер соответствующего объекта в памяти строго не связаны; в большинстве случаев ожидается, что представление JSON будет меньше, иногда намного. Например. для самой внутренней вложенности вашего примера: "a":0, занимает 6 байт, тогда как для еще одного свойства в созданном объекте вам нужно:

  • один указатель на имя свойства, «a»
  • один указатель на атрибуты свойства (доступный для записи, перечисляемый, настраиваемый)
  • один указатель на значение свойства, 0
  • предполагая, что объект находится в режиме словаря: в среднем примерно два указателя резерва

На 64-битной платформе это составляет примерно 40 байт.

Если вы посмотрите на весь объект аналогичной формы: {"a":0,"b":1} составляет 13 символов, тогда как требования к памяти:

  • указатель "карта"
  • Указатель «элементы» (не используется)
  • внеобъектный указатель «свойств» (не используется)
  • значение первого свойства (0)
  • значение второго свойства (1)
  • «карта» объекта: 11 указателей (можно разделить с другими объектами такой же формы, но если у вас есть только один такой объект, то не с чем его разделить)
  • дескрипторы свойств карты объекта: 10 указателей

Всего 26 указателей или 208 байт. (из https://stackoverflow.com/a/45018888/4424585)

После того, как я понял, как JSON инициализируется в памяти, мне в голову пришел следующий вопрос:

Насколько структура JSON влияет на память?

Чтобы понять это, я создал файлы JSON разных типов, а затем загрузил их в память.

  1. Пустой объект в качестве значения: файл JSON размером 78 МБ с 1 0000 000 ключей, где значения являются пустыми объектами, например,
    {“random_key_1”:{}, “random_key_2:{}” ….. }
  2. Строка как значение: файл JSON размером 170 МБ с ключом 10000000 (в качестве возрастающего числа), где значения представляют собой случайные числа, например,
    { “1” : “random_value” : “2”: “random_value”}
  3. 2 уровень JSON: файл JSON размером 170 МБ с ключом 7500000, где значения представляют собой объект JSON с одним ключом (как возрастающее число) и случайным числом в качестве значений, например,
    { "1" : {"1": "random_value"}, "2" : {"2" : "random_value"} }
  4. Массив:файл JSON размером 76 МБ с 1 000 000 значений внутри массива объекта
    { arr : [ “random_value_1”, “random_valule_2”…]}
  5. Вложенный JSON в качестве значения: файл JSON размером 60 КБ с 5000 ключей, где каждый ключ содержит вложенный JSON в качестве значения.
    { “key1” : { “key2”: { “key3”: {}} }}

Получив файлы, я создал простой скрипт Node.js, который загружает и анализирует JSON и регистрирует использование памяти до и после импорта файла JSON.

console.log(process.memoryUsage());let data=require(‘./data/FirstJSON.json’);
console.log(process.memoryUsage());

Ниже приведен график, показывающий использование памяти различными файлами JSON при загрузке в память.

Из графика видно, что структура массива требует меньше места. Но если мы сравним пустой объект, объект JSON 2-го уровня и JSON со строкой в ​​качестве значения, трудно сделать вывод, что структура сильно влияет на память. Мы определенно видим большое пространство, занимаемое 2-м уровнем JSON, но это связано с тем, что 75 000 ключей находятся внутри 75 000 Sub JSON. В случае JSON со значением String используемое пространство памяти больше, чем пустой объект, потому что для строки требуется больше места, чем для пустых объектов.

На графике, если вы видите вложенный JSON в качестве значения, полоса до и после загрузки JSON одинакова. Самая основная причина этого заключается в том, что количество ключей (= уровень Sub JSON) составляет всего 5 тыс. Вы можете подумать, почему я использовал здесь только 5k ключей? Это потому, что когда я увеличил значение ключа, я получил ошибку:

RangeError:/path/data/hierarchical.json: Maximum call stack size exceeded

Это объясняет, что когда sub JSON анализируется/сохраняется, он использует стек или рекурсию, и у него есть ограничение. Это помогло сделать вывод, что структура JSON имеет значение. Хотя это не имеет значения, если JSON меньше, но в случае, когда размер JSON больше, действительно важно использовать структуру JSON с умом.

Тогда у меня возник вопрос, есть ли способ работать с большой структурой JSON?

Я не искал эластичный поиск, решения DynamoDB или MongoDB, меня интересовала нестандартная вещь, которая позволит мне загружать JSON из файла, а затем работать с ним с меньшим воздействием на память. Там я получил плагин в узле JS, который передает файл JSON и добавляет в память только ту часть, которую мы используем.
https://www.npmjs.com/package/JSONStream.
Я также узнал некоторые интересные вещи, связанные с JSON, такие как BSON, messagePack. Ссылки ниже помогут вам глубже понять,

https://stackoverflow.com/questions/6355497/performant-entity-serialization-bson-vs-messagepack-vs-json
http://techblog.procurios.nl/k/news/view/ 14605/14863/how-do-i-write-my-own-parser-(for-json).html
http://msgpack.org/index.html
http: //bsonspec.org/
http://www.ecma-international.org/ecma-262/8.0/index.html#sec-json-object

Первоначально опубликовано на anand-pathak.tumblr.com.