umbot
    Preparing search index...

    Производительность: чего ожидать и когда волноваться

    umbot спроектирован с прицелом на высокую производительность и предсказуемое время отклика. Это особенно важно, учитывая жёсткие ограничения по времени от голосовых платформ (фреймворк пишет предупреждение при обработке запроса дольше 2000 мс и ошибку при дольше 2900 мс).

    Этот документ описывает:

    • сколько времени тратит сам фреймворк на обработку запроса,
    • в каких сценариях могут возникнуть задержки,
    • как его производительность соотносится с решениями, заточенными под одну платформу.

    Все данные получены в контролируемых условиях и воспроизводимы — вы можете запустить тесты самостоятельно.

    В типичных сценариях (до 1 000 команд) внутренняя обработка umbot занимает менее 30 мс для холодного запуска. Это включает:

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

    В подавляющем большинстве сценариев umbot укладывается в десятки миллисекунд. Однако есть два случая, когда время обработки может возрасти, — и для каждого из них фреймворк предлагает готовое решение.

    1. Первичная загрузка медиафайлов
      Когда голосовой навык или чат-бот впервые отправляет изображение или аудио, фреймворк загружает файл на сервер платформы и сохраняет полученный токен в базе данных.
      Задержка зависит от размера файла, скорости соединения с API платформы и очереди на стороне платформы.
      Решение — встроенный класс Preload: он позволяет заранее, при старте приложения, загрузить все медиафайлы и закэшировать их токены. Тогда во время реального диалога отправка будет мгновенной — фреймворк просто подставит уже готовый токен.

    2. Холодный запуск с большим числом сложных регулярных выражений
      Если ваше приложение использует 10 000+ регулярных выражений, при первом запросе фреймворку нужно скомпилировать их все.
      Решения:

      • Подключите библиотеку re2 — она ускоряет обработку регулярных выражений в 2–15 раз и снижает потребление памяти в 3–7 раз.
      • Используйте кэширование RegExp (фреймворк делает это автоматически).
      • «Прогрейте» кэш при старте, выполнив несколько тестовых запросов.
      • Включите строгий режим (strict_prod), чтобы отсечь потенциально опасные ReDoS-выражения ещё на этапе регистрации команд.

    Все описанные ситуации решаются стандартными средствами фреймворка. В типовом проекте (до 1000 команд, умеренное использование регулярок) вы не столкнётесь с задержками — они возникают только в экстремальных сценариях и имеют простые пути оптимизации.

    Важно: время выполнения пользовательской логики (ваш код в addCommand или action) не входит в эти цифры. Если ваш обработчик работает 2.5 сек — это ваша зона ответственности.


    umbot — это мультиплатформенный фреймворк, тогда как Telegraf, vk-io, alice-kit и т.д. — специализированные SDK.

    Прямое сравнение производительности некорректно по нескольким причинам:

    1. Разные архитектурные задачи — специализированные библиотеки фокусируются на глубокой интеграции с одной платформой (например, опросы в Telegram), тогда как umbot обеспечивает единый API для всех платформ
    2. Разные точки замера — бенчмарки umbot измеряют чистое время маршрутизации команд, в то время как другие библиотеки часто включают сетевое взаимодействие с API платформ
    3. Разные приоритетыumbot оптимизирован для сценариев, где важна поддержка нескольких платформ с одним кодом

    Ключевой вывод: в реальных проектах узким местом почти всегда становится либо API платформы (ограничения на RPS), либо ваша бизнес-логика (работа с БД, внешними сервисами) — но не маршрутизация команд.

    Даже при пиковой нагрузке ядро umbot (16 000+ RPS в бенчмарках) обрабатывает запросы быстрее, чем:

    • платформы передают их боту (ограничения API)
    • выполняется типичная логика приложения
    • происходят сетевые запросы к базам данных

    Производительность сильно зависит от конфигурации сервера и нагрузки. Вот ориентиры для разных условий:

    Условия RPS
    Нагруженный production-сервер (2 ядра / 4 ГБ RAM, фоновая нагрузка: 3 сайта + 10 навыков + MariaDB) 16 000+
    Чистый сервер (1 ядро / 1 ГБ RAM, только бенчмарк) 27 000–35 000
    Изолированный бенчмарк (AMD Ryzen 5 5600G, 32 ГБ ОЗУ): полный цикл (вход → нормализация → логика → ответ) 41 000
    Изолированный бенчмарк, последовательный сценарий (максимальная скорость одного потока) ~67 000

    Burst-тесты (тысячи параллельных запросов) на нагруженном сервере выполняются без ошибок и быстрее чем за 1 с.

    ⚠️ Важно: RPS сильно зависит от окружения. Цифры выше — ориентиры для сравнения сценариев, а не гарантии. На менее нагруженной системе достигается более высокий RPS.

    📊 Контекст: Популярные платформы имеют различные ограничения на частоту запросов — от десятков до нескольких тысяч в секунду в зависимости от тарифа и типа запроса. Показатели umbot находятся на уровне или выше этих ограничений, что означает, что фреймворк не станет узким местом вашего приложения.

    Потребление памяти (инкрементальное, разница до/после инициализации):

    • Базовая инициализация: < 1 МБ
    • 1000 команд: < 1 МБ
    • 10 000 регулярок: +8 МБ

    💡 Абсолютное потребление процесса Node.js (~45–60 МБ) не учитывается — это стоимость среды выполнения, а не фреймворка.


    Длительное тестирование (48 часов) не выявило утечек памяти или снижения производительности: средняя пропускная способность в последовательном сценарии осталась на уровне ~67 000 RPS, а потребление памяти стабильно.

    Ключевые метрики теста:

    • Обработано запросов: 11.6 млрд за 172 800 секунд
    • Пропускная способность: 67 582 RPS (среднее, без просадок)
    • Память (Heap): старт 16 МБ → среднее ~38 МБ → завершение 21 МБ
    • Память (RSS): старт 102 МБ → среднее ~98 МБ → завершение 86 МБ (Δ: -16 МБ)

    Что это значит:

    • Утечек нет. Потребление памяти не растёт линейно, а колеблется в коридоре. Отрицательная дельта RSS (-16 МБ) говорит о том, что сборщик мусора корректно освобождает ресурсы. Приложение не «раздуется» и не упадёт через неделю работы из-за нехватки памяти.
    • Производительность не деградирует. Результаты теста на 3 секунды (66 551 RPS), 15 секунд (66 597 RPS) и 48 часов (67 582 RPS) расходятся не более чем на 1.6% — в пределах шума окружения, без однонаправленного дрейфа. Нет эффекта «разогрева», нет просадок из-за фрагментации памяти или накопления состояния.
    • Предсказуемость. Фреймворк ведёт себя одинаково на коротких и длинных дистанциях. Это позволяет точно планировать ресурсы: если на тесте ядро выдало 67k RPS — в продакшене вы получите сопоставимую производительность ядра (с поправкой на сеть и БД).

    💡 Примечание: Тест проводился в изолированной среде (без сети и БД). В реальном проекте итоговое потребление памяти будет зависеть от вашей бизнес-логики, но ядро фреймворка не станет источником утечек или деградации. Исходный код бенчмарков открыт — вы можете запустить их самостоятельно и проверить результаты на своей инфраструктуре.

    Все тесты открыты и находятся в репозитории:

    # Установка
    git clone https://github.com/max36895/umbot.git
    npm install
    npm run build

    # Тест производительности по количеству команд
    npm run bench

    # Стресс-тест на параллельные запросы
    npm run stress

    Полные результаты (включая память, разные типы регулярок, сравнение «первый vs повторный запуск») — в файле src/docs/BENCHMARKS.md (он же онлайн: https://www.maxim-m.ru/docs/umbot/documents/umbot_v-3.1_.src_docs_BENCHMARKS.html).

    Также есть возможность запустить тестирование в легком и долгом режиме. В легком режиме регистрируется 5 команд вместо 1000 (всего с фиксированными start/help/fallback — 8 против 1003). В долгом режиме запускается длительный тест на 48 часов.

    # Стресс-тест в легком режиме
    npm run stress:lite

    # Стресс-тест в долгом режиме
    npm run stress:long

    ✅ Подходит, если:

    • Вы разрабатываете единое приложение для нескольких платформ.
    • Ожидается высокая нагрузка.
    • Вам важна предсказуемость и простота сопровождения.
    • Вы делаете голосового ассистента, справочник, текстовую игру.

    umbot отлично справляется с диалоговыми сценариями, но если ваша задача — глубокая интеграция со специфическими функциями одной платформы (например, опросы в Telegram, которые требуют прямого вызова API), вам может потребоваться написать небольшую обёртку. Однако и в этом случае 90% логики (обработка команд, состояние, кнопки) останется единой для всех платформ.

    По умолчанию umbot использует линейный поиск с поддержкой подстрок и регулярных выражений. Также для команд, обрабатываемых как обычный текст, логика поиска была оптимизирована:

    1. Сначала проверяется точное совпадение
    2. Если точного совпадения нет — выполняется последовательный перебор. Это обеспечивает простоту, предсказуемость и соответствие поведению других платформ (где порядок регистрации важен).

    Однако при числе команд > 1000 или в условиях высокой нагрузки вы можете подключить собственный алгоритм поиска:

    import { Bot } from 'umbot';

    const bot = new Bot();
    bot.setCustomCommandResolver((userCommand, commands) => {
    // Пример: возврат команды по хэшу (ваши правила)
    for (const [name, cmd] of commands) {
    // slots опционален и может содержать RegExp — учитываем оба случая
    const found = cmd.slots?.some((slot) =>
    typeof slot === 'string' ? userCommand.includes(slot) : slot.test(userCommand),
    );
    if (found) {
    return name;
    }
    }
    return null;
    });

    💡 Рекомендации:

    Сохраняйте порядок перебора, если он критичен для вашей логики. Используйте кэширование (Map<string, string>) для часто встречающихся фраз. Для fuzzy-поиска рассмотрите fuse.js или natural. При использовании регулярок — не забывайте про защиту от ReDoS.

    Если в вашем приложении используются регулярные выражения для поиска команд, то стоит рассмотреть вариант перехода на re2, за счёт чего время обработки может существенно сократиться, а также сократится потребление памяти. При внутреннем тесте на большом числе регулярных выражений (>10 000) использование re2 снизило время обработки в 5–7 раз (общий заявленный диапазон ускорения — 2–15 раз в зависимости от паттернов) и уменьшило потребление памяти.

    Долгая обработка команд может быть связана:

    1. Большим количеством команд. В таком случае стоит пересмотреть подход, и переписать сами команды, объединив их при необходимости.
    2. Неоптимальный код в обработчике команды. Код команды может содержать тяжёлые операции и занимать значительную часть времени обработки. Убедитесь что в вашем коде нет тяжелых операций, а если они необходимы, то можно попробовать разбить большую операцию на команды, либо выполнить длительную обработку асинхронно, вне запроса пользователя.

    Если в вашем приложении множество изображений или звуков, то рекомендуется их заранее загрузить, иначе загрузка ресурса будет происходить во время обработки пользовательского запроса, из-за чего скорость отдачи ответа может сильно упасть. Поэтому стоит заранее подготовить список загружаемых ресурсов, и передать их в Preload.

    umbot — это производительный мультиплатформенный фреймворк, который:

    • Показывает производительность на уровне специализированных решений.
    • Обрабатывает десятки тысяч запросов в секунду на одном VPS.
    • Позволяет поддерживать единую кодовую базу для нескольких платформ, сохраняя при этом приемлемую производительность для большинства сценариев использования. Он не решает все задачи — но для диалоговых, интерактивных сценариев он обеспечивает стабильную, предсказуемую и масштабируемую основу.

    Если ваша задача — диалог с пользователем, а не управление чатом, umbot даст вам единый, предсказуемый и масштабируемый фундамент.