
Python или Node.js для API: разрыв растёт вместе с параллельной нагрузкой

Если API выполняет короткие запросы к локальным данным, Node.js с Fastify на измеренном стенде даёт больший запас пропускной способности, чем Python с FastAPI и Granian. В пилотном исследовании на Raspberry Pi 5 расчётный показатель для Node.js/Fastify составил 2254 запроса в секунду против 969 у Python/FastAPI+Granian; при усилении параллельного чтения одной записи первая связка приблизилась к 9700 запросам в секунду, а вторая оставалась ниже 2300.
Для выбора облачного API это довод в пользу Node.js при потоке коротких операций, но не готовый прогноз скорости сервиса. Если обработчик главным образом ждёт удалённую базу или внешнее API, соотношение может измениться. Память, задержка ответа и время, которое команда тратит на разработку и сопровождение, тоже входят в решение.
Что измерял стенд
На одной плате работали реализации одинаковых операций создания, чтения, обновления и удаления записей в SQLite. Отдельно нагружались выдача списка, чтение записи и маршруты изменения данных. Поэтому результат описывает конкретные приложения вместе с HTTP-сервером, обработчиками, драйвером базы и способом запуска, а не скорость языка в отрыве от них.
В репозитории эксперимента доступны реализации серверов, сценарии нагрузки, собранные данные и порядок воспроизведения на Raspberry Pi. Генератор запросов запускался на другой машине: он не отнимал процессорное время у API, хотя сетевой путь оставался частью измерения. Для Python использовались FastAPI и Granian, для Node.js — Fastify и встроенный модуль работы с SQLite.
Общий показатель пропускной способности вычислен из результатов отдельных маршрутов с заданными весами в пользу чтения. Это расчётная смесь операций, а не замер непрерывного потока, где чтение и запись конкурируют друг с другом. Такое разделение помогает увидеть свойства обработчиков, но реальное приложение со своей долей записей и размером ответов может получить другое абсолютное значение.
Почему растёт преимущество на параллельном чтении
Дополнительная серия нагружала только маршрут чтения одной записи. По мере увеличения числа одновременных соединений пропускная способность Node.js/Fastify росла заметнее, тогда как Python/FastAPI+Granian прибавлял мало. Затем рост Node.js почти остановился: и у этой конфигурации появился предел, хотя на данном маршруте он оказался выше.
Чтение одной небольшой записи позволяет лучше увидеть затраты приложения на приём запроса и подготовку ответа. Запись в SQLite подчиняется другой конкуренции: операции изменения данных могут ждать освобождения блокировки базы. Поэтому увеличившийся разрыв на чтении нельзя переносить на создание, обновление или удаление записей без отдельного измерения этих маршрутов.
Пропускная способность не заменяет показатель задержки. Когда очередь запросов удлиняется, сервер может выполнять много операций за секунду, но часть клиентов будет ждать ответа дольше. Для API с требованием к времени ответа важен профиль задержек под ожидаемой параллельной нагрузкой, а не только максимальное число завершённых запросов.
Что происходит с памятью
Преимущество по скорости не превращается автоматически в такую же экономию памяти. Таблицы измерений показывают расчётный взвешенный пик занятой физической памяти 182,90 МБ у Node.js/Fastify против 236,71 МБ у Python/FastAPI+Granian; до нагрузки значения составляли 68,11 и 216,10 МБ, а при выдаче списка пик менялся на 271,42 и 241,58 МБ соответственно.
У Python существенную часть расхода давала многопроцессная конфигурация Granian. Вариант с единственным рабочим процессом занимал меньше памяти, но уступал на маршрутах, которые выигрывали от параллельной обработки. Это важный обмен для небольшого сервера, где API делит оперативную память с другими службами.
У Node.js расход сильнее зависел от операции: выдача списка и изменение записей создавали другую нагрузку на память, чем чтение одной записи. Во время короткого измерения занятый объём также рос без заметного снижения. Из такого прогона нельзя вывести долгосрочный расход работающего месяцами сервиса, поэтому предел памяти для развёртывания следует оценивать по длительной нагрузке приложения.
Когда ожидание и вычисления меняют выбор
Удалённая база или внешний сервис добавляют время ожидания, которого не было у локальной SQLite на стенде. Документация Python по asyncio описывает параллельное выполнение задач через async/await как основу сетевого ввода-вывода. Поэтому способность Python обслуживать одновременные запросы зависит и от того, как конкретные библиотеки обращаются к базе и другим сервисам.
У Node.js короткие операции ожидания также позволяют обслуживать множество клиентов, пока обработчик быстро возвращает управление циклу событий. Руководство Node.js по циклу событий связывает тяжёлую работу внутри обработчика со снижением пропускной способности для остальных запросов. Если каждый вызов требует длительных вычислений, результат лёгкого маршрута чтения перестаёт быть подходящим ориентиром.
Для вычислительного API имеет значение и готовность нужных библиотек, и стоимость передачи работы отдельным процессам. Команда, уже поддерживающая обработку данных на Python, может быстрее выпустить и развивать такой сервис, даже если простой CRUD-маршрут на стенде уступает Node.js. Это оценка трудозатрат конкретной команды, а не вывод из теста пропускной способности.
Что переносится с платы в облако
Из стенда переносится прежде всего наблюдение о характере нагрузки: на коротком чтении измеренная связка Node.js/Fastify сохраняла больший запас при росте параллельности. Абсолютные запросы в секунду относятся к одной плате, локальной SQLite и выбранным реализациям. В облаке меняются процессор, доступная память, сетевой путь до базы и ограничения её соединений.
Если сервис часто ждёт удалённое хранилище, именно задержка запросов к нему может определять время ответа. Если ответы велики, заметнее становится стоимость выборки и сериализации; если преобладают записи, важны блокировки и возможности самой базы. Эти условия способны изменить относительную пользу быстрого HTTP-обработчика, которую хорошо видно на коротком локальном чтении.
Для API с большим потоком лёгких запросов Node.js/Fastify получает поддержку этого измерения. При преобладании внешнего ожидания или при сильной зависимости продукта от Python-библиотек FastAPI остаётся обоснованным вариантом. Решающий замер для облачного выбора — нагрузка на собственные маршруты и хранилище с учётом пропускной способности, задержки и памяти одновременно.
Читайте также:
Похожие статьи


PostgreSQL или MySQL: один тест не должен выбирать базу за проект

Зачем и когда использовать Node.js: полное руководство для 2022 года

Finteza доступна, но статус HTTP Report API в документации расходится

Как стать разработчиком Python: Каков наилучший карьерный путь разработчика Python?

Чем занимаются python-программисты?
Подпишитесь на рассылку
Получайте свежие новости Web3, AI и криптовалют прямо на вашу почту.