Relatório de Infraestrutura — 07/01/2026
Resumo Executivo
Sessão de otimização de performance e estabilização do sistema ArboreoLab, focada no motor de busca vetorial (motor-rag) e infraestrutura Node.js/MariaDB.
Duração: ~3 horas
Participantes: Engenheiro Sênior, Técnico Sênior, Diretor
Status Final: ✅ Sistema estável e otimizado
Problemas Identificados e Resolvidos
1. Pool Exhausted no motor-rag (CRÍTICO)
Sintoma: Erros 500 intermitentes com mensagem "Failed getting connection; pool exhausted"
Causa: Pool de conexões por tenant limitado a 3 conexões, insuficiente sob concorrência
Solução:
- Aumentado pool para 8 conexões/tenant via
FREGERAG_TENANT_POOL_SIZE - Adicionado retry com wait (2s) antes de falhar por pool esgotado
- Alterado response de 500 para 503 (backpressure) quando pool saturado
Arquivos modificados:
estudos/1_funcionais/fregeRAG_v1/motorRag/services/tenant_manager.pyestudos/1_funcionais/fregeRAG_v1/motorRag/services/tenant_search_engine.pyestudos/1_funcionais/fregeRAG_v1/motorRag/server/routes/search.py
2. PM2 não aplicando cluster mode (ALTO)
Sintoma: Node backend rodando com 1 worker mesmo com instances: 'max'
Causa: pm2 restart não relê configurações de fork→cluster; env vars não propagadas
Solução:
- Usar
pm2 delete+pm2 start ecosystem.config.jspara forçar releitura - Documentar comportamento do PM2 para futuras manutenções
Arquivo modificado:
Clio/node/ecosystem.config.js— cluster mode + env vars FREGERAG_*
3. motor-rag usando uvicorn com flags de gunicorn (ALTO)
Sintoma: Erro "No such option: -w" no startup do motor-rag
Causa: PM2 config apontava para uvicorn mas passava args de gunicorn
Solução:
- Alterado script para usar gunicorn explicitamente
- Args:
-w 4 -k uvicorn.workers.UvicornWorker -b 127.0.0.1:8768
4. Disk I/O alto durante buscas vetoriais (MÉDIO)
Sintoma: Latência de 20-38s por busca; gráficos mostrando 400-600 MiB/s de I/O
Causa: Buffer pool do MariaDB muito pequeno (default ~128MB); vetores lidos do disco
Solução:
- Criado script
update_performance_mariadb.sh - Buffer pool aumentado para 18GB (60% de 31GB RAM)
- Configurações de I/O otimizadas para SSD
Arquivos criados:
Clio/update_performance_mariadb.sh
Arquivo modificado:
/etc/mysql/mariadb.conf.d/50-server.cnf
5. Access Denied após restart do MariaDB (ALTO)
Sintoma: Frontend retornando 500 em todas as rotas de API
Causa: Usuário MySQL existia apenas para localhost; com skip-name-resolve=1, conexões TCP vêm como 127.0.0.1
Solução:
- Criado usuário
arboreolab_38g57g0kO0dh@127.0.0.1com mesmos grants
Métricas de Performance
Antes vs Depois
| Métrica | Antes | Depois | Melhoria |
|---|---|---|---|
| Node workers | 1 (fork) | 8 (cluster) | +700% capacidade |
| motor-rag workers | 1 (uvicorn) | 4 (gunicorn) | +300% capacidade |
| DB Buffer Pool | ~128 MB | 18 GB | +140x cache |
| Pool/tenant | 3 conexões | 8 conexões | +166% |
| Pool exhausted | Frequente | Eliminado | ✅ |
Benchmark Real (motor-rag /search)
| Concorrência | Total Time | p50 | p90 | RPS | Sucesso |
|---|---|---|---|---|---|
| 1 | 233s (10 req) | 22.9s | 29.1s | 0.04 | 100% |
| 2 | 154s (10 req) | 27.5s | 38.4s | 0.06 | 100% |
Nota: A latência alta (20-38s) é limitante do MariaDB (busca vetorial em 145k entidades). Buffer pool de 18GB deve melhorar após "aquecer" o cache.
Arquitetura Atual
┌─────────────────────────────────────────────────────────────────┐
│ PRODUÇÃO │
├─────────────────────────────────────────────────────────────────┤
│ Node.js (PM2 Cluster) │ motor-rag (Gunicorn) │
│ ├── 8 workers │ ├── 4 workers │
│ ├── Port 3000 │ ├── Port 8768 │
│ └── Rotas leves: ~3ms │ └── /search: 20-38s │
├─────────────────────────────────────────────────────────────────┤
│ MariaDB 11.8.5 │
│ ├── Buffer Pool: 18 GB │
│ ├── 145.478 entidades vetorizadas │
│ ├── 13.969 segmentos de documentos │
│ └── Pool: 8 conexões/tenant │
└─────────────────────────────────────────────────────────────────┘
🆕 Atualização: Embeddings Worker (08/01/2026)
Novo Nó de Processamento: MacBook Air M2
Adicionado worker remoto para geração de embeddings vetoriais usando aceleração Apple Silicon (MPS).
┌─────────────────────────────────────────────────────────────────┐
│ NOVA ARQUITETURA │
├─────────────────────────────────────────────────────────────────┤
│ Servidor (srv1.arboreolab.com.br) │
│ ├── Node.js (PM2 Cluster) - 8 workers - Port 3000 │
│ ├── motor-rag (Gunicorn) - 4 workers - Port 8768 │
│ └── SSH Tunnel Listener - Port 9002 (→ Mac:9999) │
├─────────────────────────────────────────────────────────────────┤
│ MacBook Air M2 (Worker Remoto via SSH Tunnel) │
│ ├── Embeddings Worker (Flask) - Port 9999 │
│ ├── Modelo: paraphrase-multilingual-mpnet-base-v2 │
│ ├── Aceleração: MPS (Metal Performance Shaders) │
│ └── SSH Forward: localhost:3306 → Server:3306 (MariaDB) │
├─────────────────────────────────────────────────────────────────┤
│ MariaDB 11.8.5 (compartilhado via túnel) │
│ ├── Buffer Pool: 18 GB │
│ ├── Novas colunas VECTOR(768) em clio_entidades_vector │
│ └── Usuário: embeddings_worker (SELECT/UPDATE em *Vector) │
└─────────────────────────────────────────────────────────────────┘
Teste de Validação (08/01/2026 14:47 UTC)
| Métrica | Valor |
|---|---|
| Database | GeopoliticasVector |
| Records processados | 32 |
| Tempo total | ~15 segundos |
| Taxa | 3.2 records/segundo |
| Device | MPS (Apple Silicon) |
Arquivos Criados
| Arquivo | Descrição |
|---|---|
embeddings-worker-interface/api_server.py | Flask API multi-tenant |
embeddings-worker-interface/ssh_tunnel.sh | Túnel duplo (API + MariaDB) |
embeddings-worker-interface/install_mac.sh | Instalador automatizado |
Documentação completa:
RELATORIO_EMBEDDINGS_WORKER_2026-01-08.md
Warnings Pendentes (Baixa Prioridade)
MariaDB 11.8 removeu algumas opções que ainda estão no config:
innodb_buffer_pool_instances— gerenciado automaticamenteinnodb_thread_concurrency— gerenciado automaticamente
Impacto: Apenas warnings no log, sem efeito funcional.
Próximos Passos Recomendados
| Prioridade | Ação | Impacto Esperado |
|---|---|---|
| Média | Criar índice vetorial no MariaDB | Reduzir latência de 25s → ~5s |
| Baixa | Remover opções depreciadas do MariaDB 11.8 | Limpeza de logs |
| Baixa | Implementar cache Redis para queries frequentes | Evitar reprocessamento |
Lições Aprendidas
-
PM2 restart vs delete/start:
pm2 restart --update-envnem sempre aplica mudanças defork→cluster. Usarpm2 delete+pm2 starté mais confiável. -
skip-name-resolve: Ao habilitar no MariaDB, criar usuários tanto para
localhostquanto para127.0.0.1. -
Validação de config MariaDB: Não usar
grep "error"no output de--help— palavras como--log-errorcausam falso positivo. -
Pool sizing: Com Gunicorn (4 workers) + queries paralelas (entidades + documentos), cada request pode usar 2+ conexões. Pool de 3 era insuficiente.
-
Benchmark com ab: Usar
-spara timeout alto em endpoints lentos; "Failed requests: Length" não é erro real, é variação no tamanho do response.
Arquivos Modificados/Criados
| Arquivo | Ação | Descrição |
|---|---|---|
Clio/node/ecosystem.config.js | Modificado | Cluster mode, Gunicorn, env vars |
estudos/.../tenant_manager.py | Modificado | Pool size configurável |
estudos/.../tenant_search_engine.py | Modificado | Retry com wait no pool |
estudos/.../routes/search.py | Modificado | 503 para pool exhausted |
Clio/update_performance_mariadb.sh | Criado | Script de tuning MariaDB |
/etc/mysql/.../50-server.cnf | Modificado | Buffer pool 18GB |
Relatório gerado por: Engenheiro Sênior ArboreoLab
Data: 07/01/2026 23:30 UTC