Show HN: PrinceJS – 19,200 req/s Bun framework in 2.8 kB (built by a 13yo)
PrinceJS позиционируется как самый быстрый фреймворк для Bun, демонстрируя впечатляющую производительность в 19,200 запросов в секунду при размере всего 2.8 килобайта. Эта сверхлегкая реализация делает его идеальным выбором для высоконагруженных приложений, где важна каждая миллисекунда и каждый байт. Фреймворк сохраняет при этом простоту использования и функциональность, необходимую для разработки современных веб-приложений.
Разработчики подчеркивают, что PrinceJS достигает такой производительности благодаря минималистичному подходу и отсутствию избыточных абстракций. Несмотря на крошечный размер, фреймворк включает все необходимые функции для создания REST API и веб-приложений. Это делает его привлекательной альтернативой более крупным фреймворкам, таким как Express.js или Fastify, особенно для проектов, где критически важны скорость и эффективность.
Комментарии (39)
- Пользователи отмечают, что 13-летний разработчик из Нигерии создал фреймворк, который по производительности превосходит Express и Fastify, но при этом не поддерживает wildcard-роутинг и не имеет тестов.
- Сообщество обсуждает, что примерно 20 тыс. запросов в секунду для простого эндпоинта — это не рекорд, но при этом нет никакой информации о том, какие именно фичи отсутствуют и какие баги могут быть в таком фреймворке.
- Некоторые участники обсуждения отмечают, что фреймворк не имеет тестов и не ясен вопрос, как он будет вести себя в продакшене.
- Участники также отмечают, что в документации фреймворка нет информации о том, какие именно фичи он поддерживает, и какие из них отсутствуют.
What Are Traces and Spans in OpenTelemetry?
Trace — полный путь одного запроса через все сервисы.
Span — отдельный шаг в этом пути (функция, SQL, HTTP-вызов).
Root span — первый span (обычно входящий HTTP-запрос).
Child span — вложенный шаг.
Context — передаёт trace_id и текущий span по асинхронным вызовам.
Sampler — решает, записывать ли трассировку.
Exporter — отправляет spans в OneUptime, Jaeger и т.д.
Структура span
- name — короткое имя операции
- start/end time — длительность
- status — OK / ERROR
- attributes — произвольные метки (user_id, db.table)
- events — точки во времени (exception, cache hit)
- links — связи с другими traces
Быстрый старт в Node.js / TypeScript
npm i @opentelemetry/api @opentelemetry/sdk-node \
@opentelemetry/auto-instrumentations-node
// tracing.ts
import { NodeSDK } from '@opentelemetry/sdk-node';
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';
const sdk = new NodeSDK({
serviceName: 'my-api',
traceExporter: new OTLPTraceExporter({ url: 'https://otlp.oneuptime.com' }),
instrumentations: [getNodeAutoInstrumentations()],
});
sdk.start();
Ручная инструментация
import { trace } from '@opentelemetry/api';
const tracer = trace.getTracer('my-service');
async function getUser(id: string) {
return tracer.startActiveSpan('db.users.findById', async (span) => {
span.setAttributes({ 'db.table': 'users', 'user.id': id });
try {
const user = await db.users.findById(id);
span.setStatus({ code: SpanStatusCode.OK });
return user;
} catch (e) {
span.recordException(e);
span.setStatus({ code: SpanStatusCode.ERROR, message: e.message });
throw e;
} finally {
span.end();
}
});
}
Express/Fastify middleware
import { trace } from '@opentelemetry/api';
export function traceMiddleware(req, res, next) {
const span = trace.getTracer('http').startSpan(`${req.method} ${req.route?.path || req.url}`);
trace.getActiveContext().with(trace.setSpan(trace.getActiveContext(), span), () => {
res.on('finish', () => {
span.setAttributes({
'http.status_code': res.statusCode,
'http.method': req.method,
'http.route': req.route?.path,
});
span.end();
});
next();
});
}
Практические советы
- Именование:
verb noun(GET /users,db.users.insert). - Атрибуты: добавляйте
user.id,order.id,region. - Ошибки:
span.recordException(err)+span.setStatus({code: ERROR}). - Sampling: head-based (решение на старте) или tail-based (после завершения).
- Антипаттерны: слишком мелкие spans, отсутствие
span.end(), захардкоженные ID.
Сборка всего вместе
- Запустите SDK на старте приложения.
- Добавьте auto-instrumentations (http, express, pg, redis).
- Дополните ручными spans для критичных операций.
- Отправляйте traces в OneUptime → исследуйте flame-графы, ищите узкие места.
Комментарии (28)
- OTEL хвалят как стандарт, но реальные реализации сильно разнятся между вендорами и часто усложняют жизнь.
- Базовые понятия: span — это интервал работы с уникальным ID и ссылкой на родителя, trace — DAG спанов, рассказывающий историю запроса.
- Авто-инструментация почти даром даёт данные для JVM-приложений, но вне веб-бэкендов примеров мало и приходится искать «правильный» подмножество.
- Некоторые жалуются на объём кода и хранилище (десятки ТБ трейсов за неделю), другие считают это разовой настройкой и платой за прозрачность системы.
- Появляются упрощающие обёртки (Logfire, otelize) и примеры интеграции, но документация по дашбордам Grafana всё ещё вызывает трудности.