Kyrux
Voltar

Comparativo com Django

Uma pergunta natural para quem vem do Python: o admin do Kyrux é rápido o suficiente na prática, ou só parece rápido nos microbenchmarks isolados? Em vez de responder por intuição, montamos os dois lados — mesma máquina, mesmo Postgres, configuração equivalente — e medimos throughput e uso de CPU/memória.

Medição pontual, numa única máquina de desenvolvimento, duas rodadas por lado. Trate como ordem de grandeza comparativa, não como benchmark de produção com múltiplas réplicas estatísticas.

Metodologia

Os dois lados rodaram a mesma carga: 200 linhas seedadas numa tabela equivalente, autenticação real por sessão (login via formulário, não um mock), 32 conexões concorrentes, cliente e servidor em processos separados (para não misturar CPU do cliente de carga com a do servidor medido).

  • Kyrux: SERVER_WORKERS=4 (GOMAXPROCS=4), Postgres real com pool de conexões, admin com um model registrado (admin.Register).
  • Django: 6.0 + gunicorn --workers 4 --worker-class sync (mesmo número de "unidades de execução simultânea" que o Kyrux), CONN_MAX_AGE = None (conexão persistente, para não penalizar o Django com reconexão por requisição — o padrão do Django), list_per_page = 20 (igualado ao defaultPageSize do Kyrux — o padrão do Django é 100, o que daria vantagem indevida numa comparação de custo por página).
  • Nenhum dos dois lados foi otimizado além do necessário para uma comparação justa (sem índice extra, sem cache de queryset, configuração mínima de registro do model nos dois admins).

Throughput

Rota Kyrux (req/s) Django (req/s) Vantagem do Kyrux
GET / (página pública, sem banco) ~49.000–64.000 ~4.100–5.900 ~11x
GET /admin/login/ ~20.000–38.000 ~670–850 ~38x
GET /admin/ (dashboard) ~14.000–19.000 ~330–370 ~47x
GET /admin/<model>/novo/ (form vazio) ~13.000–17.000 ~285–295 ~52x
GET /admin/<model>/<pk>/ (detalhe, 1 linha) ~6.100 ~258–259 ~24x
GET /admin/<model>/ (lista, 200 linhas, paginação real) ~2.300–3.600 ~156 ~19x

Kyrux venceu em todas as rotas testadas, nas duas rodadas, com margens de ~11x (rota pública, sem banco) a ~52x (formulário vazio do admin). A rota relativamente mais lenta do lado Kyrux é a listagem paginada — não por causa do banco (a consulta é uma SELECT ... LIMIT 21 rápida), mas porque ~92% do custo daquele handler é a execução do html/template iterando as ~20 linhas da página via reflection. Mesmo assim, ainda é ~19x mais rápida que o Django fazendo o mesmo trabalho.

Uso de recursos (CPU e memória)

Medido isolando o processo do servidor do processo do cliente de carga (sem essa separação, a memória/CPU do próprio cliente contaminaria a leitura do servidor). Memória lida via PSS (não RSS bruto) — importante porque o gunicorn usa um modelo pré-fork (1 master + 4 workers): boa parte da memória de cada worker é compartilhada por copy-on-write com o master, e somar o RSS bruto dos 5 processos superestimaria o consumo real.

Kyrux Django (gunicorn)
Processos do servidor 1 (único binário, goroutines) 5 (1 master + 4 workers sync)
Memória (PSS) ociosa ~82 MB ~149 MB
Memória (PSS) de pico, sob carga sustentada ~149 MB ~177 MB
CPU sob carga (faixa observada em rodadas distintas) 82%–161% (de 400% teóricos) 85%–107% (de ~500% teóricos)

O Django já nasce usando quase 2x mais memória que o Kyrux antes de servir qualquer request — custo fixo de carregar o interpretador Python, o próprio Django, e manter 4 cópias de processo vivas o tempo todo. O Kyrux, sendo um único binário compilado com goroutines dentro de um processo só, paga esse custo uma vez. Do lado de CPU, mesmo no pico observado (161%) o Kyrux ficou longe de saturar seus 400% teóricos — entregando de ~11x a ~52x mais requisições que o Django no mesmo intervalo.

Honestidade sobre os números

Esta comparação já foi refeita uma vez nesta mesma base de código, depois de duas correções internas (um bug no cliente de benchmark que subestimava o Kyrux, e um ajuste de alocação de memória no admin) — e a vantagem do Kyrux aumentou entre a primeira e a segunda rodada, não porque o Django piorou, mas porque o Kyrux genuinamente ficou mais rápido. Isso é uma lição por si só: a "vantagem em X" de qualquer comparação entre frameworks reflete o estado de otimização de cada lado no momento da medição, não uma constante da linguagem. Trate os números acima como o que são — uma medição de hoje, numa máquina específica — e não como uma promessa permanente.