NodeJS JSON.stringify() узкое место

Моя служба возвращает ответы очень больших объектов JSON - около 60 МБ. После некоторого профилирования я обнаружил, что он тратит почти все время на выполнение вызова JSON.stringify(), который используется для преобразования в строку и отправки ее в качестве ответа. Я пробовал собственные реализации stringify, и они еще медленнее.

Это довольно узкое место для моей службы. Я хочу иметь возможность обрабатывать как можно больше запросов в секунду - в настоящее время 1 запрос занимает 700 мс.

Мои вопросы:
1) Могу ли я оптимизировать отправку ответной части? Есть ли более эффективный способ, чем преобразование объекта в строку и отправка ответа?

2) Улучшит ли использование асинхронного модуля и выполнение JSON.stringify() в отдельном потоке общее количество запросов в секунду (учитывая, что более 90% времени тратится на этот вызов)?


person gop    schedule 26.02.2014    source источник
comment
Вы ничего не можете сделать, чтобы уменьшить размер этих объектов? Что делает их такими большими?   -  person jameslafferty    schedule 26.02.2014
comment
Вы пытались использовать socket.io. JSON.stringify загружает весь объект в память, поэтому я не думаю, что вы сможете его оптимизировать. Но 60 МБ json — это слишком много.   -  person himangshuj    schedule 26.02.2014
comment
Вы отправляете избыточные данные? Если подмножество ваших данных изменено, не отправляйте повторно все данные, просто повторно отправьте подмножество. Это может позволить вам уменьшить объем данных, которые вы вводите в строку.   -  person Paul    schedule 26.02.2014
comment
Было бы полезно увидеть код, который вы используете для отправки ответа, чтобы мы могли оценить ваш процесс.   -  person srquinn    schedule 26.02.2014
comment
Как вы используете эту услугу... т.е. вам нужно сериализовать ее как JSON? Может быть, вместо этого попробовать сериализовать и отправить как BSON? Я полагаю, вы увидите улучшение производительности при кодировании/декодировании; и выход должен быть меньше.   -  person Rei Mavronicolas    schedule 26.02.2014
comment
@Reinard Mavronicolas Я думаю об использовании github.com/kesla/node-snappy для сжатия json напрямую, избегая вызова JSON.stringify(). Что вы думаете? Отчитаюсь с результатами.   -  person gop    schedule 26.02.2014
comment
@gosho_ot_pochivka, судя по всему, вам придется сжимать свои объекты, а затем распаковывать их, чтобы получить JSON; звучит как накладные расходы для меня. Но было бы интересно посмотреть на результаты.   -  person Rei Mavronicolas    schedule 26.02.2014
comment
У меня похожая ситуация случилась. Мое решение может быть неприменимым, но если это так, я надеюсь, что оно поможет. Первый уровень моего главного объекта json состоял из 9 различных подобъектов. Вместо запроса главного объекта я отправил 9 запросов на 9 подобъектов. Это значительно сократило мое время ожидания   -  person discodane    schedule 01.12.2015


Ответы (2)


У вас есть два варианта:

1) найдите модуль JSON, который позволит вам выполнять потоковую операцию stringify и обрабатывать ее по частям. Я не знаю, есть ли такой модуль, если нет, вам придется его построить. EDIT: Спасибо Reinard Mavronicolas за указание на JSONStream в комментариях. У меня на самом деле было это на заднем плане, чтобы искать что-то подобное для другого варианта использования.

2) async не использует потоки. Вам нужно будет использовать cluster или какой-либо другой фактический модуль потоковой передачи, чтобы перенести обработку в отдельный поток. Предостережение здесь заключается в том, что вы все еще обрабатываете большой объем данных, вы увеличиваете пропускную способность с помощью потоков, но в зависимости от вашего трафика вы все равно можете достичь предела.

person Jason    schedule 26.02.2014
comment
Благодарность! У меня есть другая идея - заархивировать контент и вместо этого заставить мой сервис возвращать сжатый контент. Я нашел эту библиотеку github.com/sapienlab/jsonpack, которая предоставляет функцию, которая принимает объект json и возвращает gzip-строка, и мне кажется, что внутри она не вызывает JSON.stringify(). Что вы думаете? - person gop; 26.02.2014
comment
Пока он выполняет потоковую/событийную/фрагментированную обработку, это, вероятно, нормально. Обработка такого большого количества данных за одну операцию без разбиения их на части займет много времени, независимо от того, что вы с ними делаете. - person Jason; 26.02.2014
comment
@Jason, вы можете добавить к своему ответу пункт номер 1 — github.com/dominictarr/JSONStream. Кроме того, кажется, что это другой вопрос SO, похожий на этот: stackoverflow.com/questions/13503844/ - person Rei Mavronicolas; 26.02.2014
comment
потоковая передача в msgpack, вероятно, была бы еще лучше. - person hasen; 13.06.2017

Спустя год у этого вопроса появился новый ответ на первый вопрос: yieldable-json lib . Как описано в этом выступлении Гириша Пунатила (IBM India), эта библиотека может оцените JSON размером 60 МБ, не блокируя цикл событий node.js, чтобы вы могли принимать новые запросы, чтобы повысить пропускную способность.

Для второго, с node.js 11 в экспериментальной фазе, вы можете использовать рабочий поток, чтобы увеличить пропускную способность вашего веб-сервера.

person Manuel Spigolon    schedule 06.11.2018
comment
Вы реализовали что-то из этого? Я экспериментирую с yieldable-json, рабочими потоками и даже собственным расширением API, например github.com/lemire/simdjson - person hrdwdmrbl; 22.04.2019
comment
Да, я использовал yieldable-json, но не пробовал другие подходы - person Manuel Spigolon; 23.04.2019