← На главную

Веб-фреймворк с зелёными процессами выдал 35 000 rps на Apple Silicon

12.07.2026 01:03 · hackernews

В основе — разделение на ядро и фреймворк, как у Node и Express. Ядро даёт только запуск сервера (http-listen). Всё остальное, включая готовый фреймворк igropyr express с create-app, app-get, send-json! — опционально. На том же ядре можно построить другой фреймворк.

Вместо потоков ОС — зелёные процессы. Тысячи лёгких процессов работают на одном потоке. Переключение контекста с вытеснением: даже бесконечный цикл в процессе не повесит всю систему. Нет разделяемого состояния между процессами — чистая передача сообщений (spawn, send, receive, link, monitor).

Отказоустойчивость встроена. Есть supervisor с пулом воркеров. Если воркер упал — его перезапускают, задачу повторяют (до трёх раз, потом клиент получает 500). Если воркер завис больше чем на 30 секунд — его убивают и заменяют. Медленный запрос блокирует только свой процесс чтения. Можно повесить обработчик on-failure — тогда вместо 500 клиент получит структурированный JSON и сам решит, перепосылать запрос или нет.

Диалоги с несколькими запросами (conversation) живут в одном процессе. Процесс хранит состояние между раундами, может держать открытую транзакцию. suspend! приостанавливает диалог, conversation-resume! продолжает. Если процесс умирает — гарантированный откат.

На лету можно менять код обработчика или отдельных маршрутов. Соединения и воркеры не перезапускаются, текущие запросы дорабатывают на старом коде.

На том же порту работает WebSocket (RFC 6455). Каждый сокет — отдельный зелёный процесс. Чтобы отправить данные с сервера — просто шлёшь сообщение. Есть чанковая отправка ответа (res-begin!, res-write!, res-end!) и SSE.

Из коробки — gen-server (call/cast/info), реестр процессов (register, whereis), PubSub с автоматической очисткой отключившихся подписчиков. JSON парсится безопасным рекурсивным спуском, без read. Для общения с другим SchemeS-expression RPC (тоже безопасный парсер, с ограничением глубины). Отдельно — клиентский модуль Goeteia для браузера.

Поддерживаются формы (urlencoded, multipart, с загрузкой файлов), cookies. Из middleware — сессии через gen-server, CORS с preflight, заголовки безопасности, логгер доступа. Прозрачно обрабатывается Transfer-Encoding: chunked.

Неблокирующие клиенты Redis и MySQL на чистом Scheme — в том же цикле событий. Вызов паркует зелёный процесс. MySQL — с самовосстанавливающимся пулом соединений. Клиенты HTTP и WebSocket с асинхронным DNS через тред-пул libuv. Статика читается там же. Сжатие gzip по Accept-Encoding, с кешированием.

Для эксплуатации — rate limiting, глобальный обработчик ошибок, Prometheus (/metrics), счётчики соединений (http-stats) и плавное выключение (http-shutdown!). Для мультипроцессной работы — SO_REUSEPORT на Linux. По умолчанию HTTP/1.1 keep-alive и pipelining. Производительность: ~35 000 запросов/сек при 500 параллельных соединениях на Apple Silicon (ab -n 50000 -c 500, ноль ошибок).

Читать оригинал →