Почему мой Node.js зависает при выполнении больших скриптов?

Разрабатываю API на Node.js с Express и когда тестирую с большими CSV-файлами (типа 500MB) весь процесс зависает и приходится перезагружать. Уже пробовал увеличить heap, но всё равно зависает. Кто-нибудь знает, это проблема памяти или в коде что-то не так?

3 ответа

★ Лучший ответ

Я сталкиваюсь с такой проблемой при работе с огромными базами данных, и причина почти всегда одна и та же: ты загружаешь весь файл в память перед обработкой! CSV размером 500MB становится просто монструозным при парсинге в массивы, а увеличение heap - это просто заклеить рану пластырем. Реальное решение - использовать streams: обрабатываешь строку за строкой, одновременно записывая данные в базу или файл, и Node.js даже не потребуется хранить больше чем несколько КБ за раз! Попробуй библиотеку `csv-parser` со streams или даже напиши собственный парсер с помощью `fs.createReadStream()` и событий - это полностью изменит твой подход.

Я сталкивалась с чем-то похожим, когда пыталась обработать большие файлы сразу, и поняла, что проблема была не только в памяти - это был факт того, что я загружала всё сразу в RAM. С CSV размером 500MB, если ты попытаешься прочитать весь файл и потом обработать, память кончится очень быстро. Решение - использовать streams вместо загрузки всего в память. В Node.js есть модуль `fs.createReadStream()`, который позволяет читать файл по кусочкам. Если ты работаешь с библиотеками вроде `csv-parser`, ты можешь связать streams в цепь, чтобы обрабатывать строку за строкой без перегрузки RAM.

Ещё что мне помогло - понять, что даже со streams, если твоя логика обработки медленная (вроде синхронных операций в цикле, запросы в БД без batch-обработки), ты создашь узкое место. Когда stream поставляет данные быстрее, чем ты их обрабатываешь, память накапливается и так же. Используй `pause()` и `resume()`, чтобы управлять потоком, или правильно реализуй back-pressure. Если ты делаешь запросы в БД для каждой строки, группируй их в batch - типа, собери 1000 строк и сделай одну операцию вместо 1000 отдельных.

Какая примерно операция у тебя с данными CSV? И ты сохраняешь результаты куда-нибудь (файл, база данных) или просто обрабатываешь и возвращаешь через API? Ответ важен, потому что проблема может быть и в том, как ты отправляешь ответ клиенту.

gabriel_oliveira автор вопроса Обрабатываю данные и сохраняю сразу в БД без батча. Попробую работать со streams и группировать запросы порциями по 1000, спасибо!

Проблема, скорее всего, не только в увеличении heap, нет. Когда ты загружаешь файл весом 500MB целиком в память перед обработкой, Node.js просто задыхается. Ребята правы, указывая на это, но есть деталь, которую никто не упомянул: если ты используешь библиотеки вроде `csv-parser` или что-то подобное без нормальной настройки streams, она может буферизировать несколько строк перед обработкой, что всё только ухудшает. Нужно использовать streams по-настоящему - `fs.createReadStream()` + парсер, который уважает маленькие chunks. Таким образом Node.js обрабатывает строку за строкой (или небольшими порциями) без проседания памяти.

Ещё одно, что убивает производительность: если ты делаешь запросы в базу данных внутри цикла обработки CSV, каждая строка может генерировать отдельный запрос. Представь 500 тысяч строк = 500 тысяч запросов. База паникует, очередь растёт, память взлетает. Используй batch - обрабатываешь 1000 строк за раз, делаешь один массовый insert, потом переходишь к следующей партии. С streams + batching ты можешь обрабатывать файлы намного большего размера без зависаний.

Ваш ответ

Войдите, чтобы ответить.