VBET
VBET: analytics sobre um SQL Server que não podíamos mudar
O banco era de outro time. O dashboard precisava deixar de depender de um schema que não controlávamos.
~7 min → <1 s comissões, da carga original ao cache quente
Cada estágio corresponde a uma decisão incremental documentada no case. Números de outras histórias não entram neste desenho.
Contexto
Na VBET, entre outubro de 2023 e fevereiro de 2025, o produto de analytics servia influenciadores e afiliados de iGaming. O dashboard reunia dezenas de métricas; comissão era a leitura mais crítica. Influenciadores aceitavam pequena defasagem nos dados do dia, desde que a tela respondesse. Pagamento dependia de dados consolidados do dia anterior, não do valor ao vivo.
Restrições
O SQL Server era externo, compartilhado e não modificável de forma confiável. Índices temporários podiam ser removidos pelo proprietário da base. A API original misturava consultas SQL montadas a partir de parâmetros, com risco de injeção, e agregava demais em memória.
Problema
O sistema havia sido dimensionado para influenciadores menores. Com bases maiores, o pior pico do dashboard chegou a cerca de sete minutos. Segurança e manutenibilidade vieram antes da performance: queries cruas, pouca cobertura de testes e um caminho síncrono que recalculava demais a cada request.
Decisão
A evolução foi incremental, na ordem em que as restrições apareceram:
- remover SQL inseguro, parametrizar acesso, documentar e testar;
- otimizar queries e índices temporários, como mitigação e não como invariante;
- paralelizar consultas independentes com Go, goroutines e channels;
- quando o gargalo voltou para o SQL Server, criar ETL e PostgreSQL próprios, com pré-cálculo, checkpoints e reconciliação;
- separar leitura REALTIME (tendência, consistência eventual) de CLOSED (precisão financeira e pagamento);
- cache-aside com TTL alinhado à defasagem aceita de cerca de cinco minutos;
- degradação controlada se o cache falhasse, em vez de derrubar a tela.
Alternativa descartada
Insistir em índices na base externa como arquitetura, ou recalcular anos de histórico a cada acesso. Também descartada a ideia de pagar o afiliado com o dado REALTIME.
Resultado
A linha reconciliada no dossiê da experiência, para o caminho de comissão/dashboard, é:
- pior pico inicial: cerca de 7 minutos;
- após queries e índices: cerca de 3 minutos;
- após paralelização: cerca de 1 minuto;
- após ETL/PostgreSQL: cerca de 15 segundos no p99 da comissão sem cache;
- cache quente: menos de 1 segundo.
Cada número pertence a essa etapa. Não descreve o ganho de uma decomposição posterior em microsserviços.
Limitações
A investigação, a decisão de ETL + base própria, a separação REALTIME/CLOSED e a política de degradação são o núcleo atribuível aqui. A decomposição do monólito em Kubernetes é outra história e não mistura o “500%” nem a latência abaixo de 60 ms com este caso. Versões antigas de currículo que citam 30 segundos em carga fria, 11 segundos ou percentuais de SLA sem cenário ficam de fora. Se o produto passar a exigir precisão realtime no pagamento, a separação CLOSED deixa de ser suficiente.