Сервис развивается: тестируем формат, собираем идеи, улучшаем сервис. Есть идеи? Написать
Войти
Дайджесты новостей
Архитектура рантайма Bun v1.4.1

Релиз Bun v1.4.1: сброс JIT-кода в простое, поддержка HTTP/2 на общем порту и оптимизация бандлов Zod на 79%

Команда Bun выпустила релиз v1.4.1 с исправлением 202 ошибок: JavaScriptCore теперь выгружает скомпилированный JIT-код во время простоя процесса, веб-сервер Bun.serve получил поддержку HTTP/2 на общем порту с HTTP/1.1, а улучшенный tree-shaking пространства имен сократил бандлы Zod на 79%.

Релиз Bun v1.4.1: сброс JIT-кода в простое, поддержка HTTP/2 на общем порту и оптимизация бандлов Zod на 79%

Серверный рантайм Bun на базе движка JavaScriptCore привлекал внимание сообщества рекордными показателями в синтетических бенчмарках. Однако в реальной эксплуатации критически важны не только миллисекунды ответа, но и стабильность потребления памяти, предсказуемость под нагрузкой и сетевая совместимость. Релиз Bun v1.4.1 включает 202 исправления дефектов и вводит глубокие оптимизации виртуальной машины, сетевого стека Bun.serve и бандлера, нацеленные на надежность долгоживущих микросервисов.

Очистка скомпилированного JIT-кода в моменты простоя

Одной из острых проблем серверных Node.js и JavaScript-приложений (включая Next.js SSR, Express и Fastify) остается раздувание оперативной памяти (Resident Set Size, RSS). В рантаймах с динамической JIT-компиляцией часто вызываемый код компилируется в машинные инструкции процессора. Эти бинарные артефакты удерживаются в памяти неограниченно долго даже после прекращения пикового трафика: сервер простаивает, но память операционной системе не возвращается.

В Bun v1.4.1 виртуальная машина JavaScriptCore принудительно выгружает скомпилированный машинный JIT-код, если процесс переживает продолжительный простой (около трех минут без входящих запросов). При новом всплеске функции компилируются заново, но освобождение неактивных страниц позволяет снизить базовый футпринт контейнеров без перезапуска сервиса.

Сценарий (Linux x64, 60с нагрузки + 3 мин простоя)Bun v1.4.0 (RSS)Bun v1.4.1 (RSS)Node.js v26
Next.js SSR222 МБ142 МБ195 МБ
Express65 МБ53 МБ
Fastify65 МБ55 МБ
Elysia46 МБ44 МБ
Hono35 МБ34 МБ
Vite dev142 МБ111 МБ115 МБ

Для Next.js SSR объем памяти сократился на 80 МБ (со 142 МБ против 222 МБ в версии 1.4.0 и 1303 МБ в Bun 1.3.14). Важно понимать границу оптимизации: сброс JIT-кода не снижает рабочий набор активного сервиса под постоянным потоком запросов, а ликвидирует накопление фонового балласта в периоды затишья.

Сетевой стек: совмещенный порт для HTTP/1.1 и HTTP/2

Встроенный веб-сервер Bun.serve() получил нативную поддержку HTTP/2 на том же самом порту, что и HTTP/1.1.

Для защищенных соединений (TLS) выбор протокола происходит на этапе рукопожатия через расширение ALPN (Application-Layer Protocol Negotiation): при наличии маркера h2 сервер переключается на бинарные фреймы HTTP/2, иначе используется HTTP/1.1. На открытых сокетах сервер распознает префикс инициализации HTTP/2 preface.

Bun.serve({
  port: 3000,
  tls: {
    key: Bun.file('./server.key'),
    cert: Bun.file('./server.crt'),
  },
  http2: true,
  fetch(req) {
    return new Response('Подключение успешно');
  },
});

Единый обработчик fetch обслуживает запросы обоих стандартов, избавляя от необходимости поднимать промежуточный reverse-proxy для локальной терминации HTTP/2. Однако в реализации есть ограничения: HTTP/2 пока не поддерживает WebSockets и хвостовые заголовки (trailers), а флаг http1: false отключает fallback на HTTP/1.x, что требует осторожности с legacy-клиентами и проверками health-check.

Потоковый ввод-вывод и противодавление в WebSockets

Метод прямой записи Bun.write(path, response) теперь принимает потоковые объекты Response, Request и ReadableStream. Данные передаются в файловый дескриптор ядра потоком по мере поступления сетевых пакетов, минуя буферизацию всего тела в оперативной памяти. В официальном тесте скачивания файла на 128 МБ пиковый скачок RSS снизился со 161 МБ до 13 МБ. Чтение приостанавливается, если в буфере накапливается 256 КБ непрочитанных данных, а удаленный без чтения Response закрывает соединение.

Клиентский WebSocket получил методы socket.pause() и socket.resume(). Спецификация WHATWG WebSocket не позволяет регулировать скорость чтения: если сервер шлет поток событий, а клиент занят медленной записью на диск, память переполняется.

Методы Bun управляют системным сокетом:

  1. При заполнении буфера потребителя вызывается socket.pause().
  2. Рантайм прекращает чтение из TCP-сокета, окно TCP заполняется и отправитель естественным образом притормаживает передачу (TCP backpressure).
  3. При освобождении буфера (событие drain) вызывается socket.resume().

Уже декодированные сообщения при этом все равно доставляются, а сам API специфичен для Bun и не предназначен для браузеров.

Оптимизация сборщика: tree-shaking для export * as

Бандлер bun build исправил устранение неиспользуемого кода (tree-shaking) для библиотек с реэкспортом вида export * as. Ранее импорт отдельной функции (например, import { z } from 'zod') затягивал весь объект пространства имен. Для Zod это означало включение 252 внутренних сущностей, включая JSON Schema генераторы и файлы локализаций.

Bun v1.4.1 преобразует обращения к свойствам в прямые вызовы функций:

  • Zod 4.5: бандл уменьшился с 375,3 КБ до 77,3 КБ (−79%);
  • fp-ts: с 21,8 КБ до 3,2 КБ (−85%);
  • Effect: с 369,1 КБ до 163,6 КБ (−56%).

Если объект пространства имен передается в функцию целиком, используется в спред-операторе ({ ...ns }) или читается по вычисляемому ключу, оптимизация отключается. Флаг --no-deprecated-namespace-object-setters запрещает мутацию таких объектов.

Системные API, криптография и пакетный менеджер

Среди других архитектурных доработок релиза:

  • Хеширование Argon2: модуль node:crypto получил нативную поддержку crypto.argon2 и crypto.argon2Sync (argon2d, argon2i, argon2id) в системном пуле потоков с байтовой совместимостью с Node.js.
  • Инлайнинг Buffer: низкоуровневые операции чтения и записи бинарных буферов инлайнятся виртуальной машиной (операция writeFloatLE на macOS arm64 ускорилась с 2,85 нс до 0,31 нс).
  • Оптимизация AsyncLocalStorage: устранены лишние аллокации при вызовах await, исправлены утечки контекста при вызове enterWith в таймерах и колбэках.
  • Офлайн-режим установки: флаг bun install --offline падает с ошибкой при отсутствии пакета в кэше, гарантируя изоляцию без скрытых сетевых запросов. Флаг --prefer-offline использует локальный кэш без валидации, но разрешает скачивание отсутствующих зависимостей. Для Electron в монорепозиториях внедрена опция selfContained с выделенным node_modules.

Регламент безопасного обновления

Для внедрения Bun v1.4.1 рекомендуется следующий регламент:

  1. Зафиксировать исходные размеры артефактов bun build --minify, потребление памяти и задержки ответов сервиса.
  2. Обновить рантайм командой bun upgrade (или через официальный установщик curl -fsSL https://bun.sh/install | bash).
  3. Прогнать интеграционные тесты сетевого слоя, проверив согласование ALPN и корректность проксирования HTTP/2.
  4. Проверить конфигурацию TLS: Bun теперь валидирует сертификат строго по хосту из URL, требуя параметр tls.servername при нестандартном проксировании.
  5. Проверить фронтенд-сборки на корректность работы оптимизированных импортов библиотек.