Escalando EdTech Árabe com AWS Lambda Serverless
A Alphazed roda todo seu backend — atendendo mais de 95.000 estudantes em mais de 50 países — usando AWS Lambda com Serverless Framework. A arquitetura utiliza Flask no Lambda por trás do API Gateway, MySQL 8 no RDS, S3 para entrega de conteúdo e um lago de dados analíticos customizado (SQS → Kinesis Firehose → S3 → Glue → Athena). Handlers finos no Lambda otimizam a latência do cold start, e o sistema suporta 7+ apps a partir de uma única base de código com configuração runtime dinâmica.
Por que Serverless para EdTech?
Apps educacionais têm padrões de uso imprevisíveis:
- Manhãs de dias úteis: pais baixam o app antes de enviar filhos à escola (pico de tráfego)
- Tardes de dias úteis: sessões de prática pós-escola (carga constante)
- Finais de semana: sessões intensas (2-3x a carga normal)
- Durante o Ramadã: uso noturno dispara (sessões familiares de Alcorão)
- Férias escolares: padrão completamente diferente
Vantagens do Serverless:
- Pagamento por requisição: paga-se só pelo uso real. Se 10 usuários acessam, paga-se 10 invocações. Se 100.000 durante evento viral, escala instantaneamente.
- Sem cold start em endpoints de alta frequência: usamos camadas "sempre aquecidas" no Lambda para endpoints muito chamados.
- Autoescalabilidade: atende de 10 a 10.000 usuários simultâneos sem mudanças infraestruturais.
- Zero manutenção de servidores: a equipe foca no currículo e IA, não em clusters Kubernetes ou balanceadores.
Detalhes da Arquitetura
API Gateway → Lambda → RDS
[Client App] (iOS, Android, Web)
↓
[API Gateway] (roteamento HTTP, limitação de taxa)
↓
[Lambda Handlers] (app Flask, 512MB memória, timeout 28s)
├── Rotas do app: /app/* (endpoints mobile)
├── Rotas do usuário: /user/* (endpoints autenticados)
└── Rotas admin: /boss/* (dashboard admin)
↓
[MySQL 8 no RDS] (dados persistentes)
↓
[Resposta] (JSON para o cliente)
Lambdas Finos para Velocidade
A maioria dos Lambdas são propositalmente minimalistas:
# Handler fino (~100KB)
import json
import pymysql
def get_user_progress(event, context):
user_id = event['pathParameters']['user_id']
# Conexão direta ao DB (sem ORM)
conn = pymysql.connect(host='rds.aws.com', user='app', password='...', database='amal')
cursor = conn.cursor()
cursor.execute(
'SELECT concept_id, accuracy FROM user_memory WHERE user_id = %s',
(user_id,)
)
rows = cursor.fetchall()
conn.close()
return {
'statusCode': 200,
'body': json.dumps([{'concept': r[0], 'accuracy': r[1]} for r in rows])
}
Sem importação do Flask, sem ORM SQLAlchemy, sem middleware. Resultado: cold start de cerca de 500ms contra 5-10s para app Flask completo.
Endpoints pesados (geração de conteúdo, processamento analítico) usam Flask completo:
# Handler pesado (~30MB com Flask, SQLAlchemy, numpy)
from flask import Flask, jsonify
from models import UserMemory
import numpy as np
app = Flask(name)
@app.route('/content_duo/generate', methods=['POST'])
def generate_content_duo():
# Lógica complexa usando ORM
user = UserMemory.query.filter_by(user_id=request.json['user_id']).first()
# ... gera sessão personalizada ...
return jsonify(session_data)
Trade-off: cold starts mais lentos, mas chamados com menos frequência.
Prefixo por App nas Tabelas
Uma instância RDS serve 7+ apps com isolamento no nível de banco de dados:
-- App Amal
CREATE TABLE amal_users (...)
CREATE TABLE amal_content_bytes (...)
CREATE TABLE amal_user_memory (...)
-- App Thurayya
CREATE TABLE thurayya_users (...)
CREATE TABLE thurayya_content_bytes (...)
CREATE TABLE thurayya_user_memory (...)
-- Outros apps: qais_, kidelite_, etc.
No deploy, variável de ambiente APP_NAME seleciona o prefixo:
app_name = os.getenv('APP_NAME', 'amal') # 'amal', 'thurayya', 'qais', etc.
Queries usam prefixo dinamicamente
table_name = f'{app_name}_users'
cursor.execute(f'SELECT * FROM {table_name} WHERE id = %s', (user_id,))
O Lago de Dados Analíticos
Problema: Consultas diretas para analytics atrasam produção, causando bloqueio de tabelas.
Solução: Pipeline analítico assíncrono
[App Mobile]
↓ (envia evento)
[API Endpoint] → [Fila SQS] (async)
↓ (responde imediatamente ao app)
↓ (não espera analytics)
[Kinesis Firehose] (agrega eventos a cada 5 min ou 100MB)
↓
[S3] (particionado: s3://analytics-lake/amal/2026/03/28/events.parquet)
↓
[AWS Glue] (rastrea S3, infere esquema)
↓
[Athena] (consultas SQL via motor Presto)
↓
[Dashboard] (mostra insights em tempo real)
Dead Letter Queue (DLQ)
Se ocorre falha analítica:
SQS → [Firehose falha]
↓
[DLQ recebe mensagens falhadas]
↓
[Alertas para equipe de operações]
↓
[API de produção não afetada]
Analytics nunca bloqueia requisições do usuário. Crianças aprendem mesmo se pipeline analítico estiver fora.
Estratégias de Otimização de Custos
- Lambdas finos para endpoints de alta frequência
App típico chama API 10-20 vezes por sessão
95.000 usuários ativos × 3 sessões/dia × 15 chamadas = 4,275M chamadas/dia
Cada chamada custa ~$0,0000002 (Lambda), total ~$0,86/dia
Reduzir 10s no cold start economiza ~$500/mês - Instâncias Reservadas RDS
Reserva 3 anos: ~60% desconto comparado on-demand
Usamos db.r6i.xlarge (4 vCPU, 32GB RAM): $2.800/mês reservado vs $6.500/mês on-demand
Economia anual: ~$50.000 - Cache
Dados frequentes (currículo, conteúdo) em ElastiCache (Redis)
Reduz consultas RDS em 70%
Custos: $800/mês cache, economiza $2.000/mês no RDS
Servindo 7+ Apps numa única base de código
| App | Prefixo | Tabelas DB | Stack Lambda | Status |
|---|---|---|---|---|
| Amal | amal_ | 40+ tabelas | Compartilhado | Produção |
| Thurayya | thurayya_ | 40+ tabelas | Compartilhado | Produção |
| Qais | qais_ | 35+ tabelas | Compartilhado | Beta |
| KidElite | kidelite_ | 40+ tabelas | Compartilhado | Produção |
| Alphazed School | school_ | 50+ tabelas | Compartilhado | Beta |
| Alphazed Montessori | montessori_ | 45+ tabelas | Compartilhado | Interno |
Um backend, pipeline único, 6 apps simultâneos. Novo app em semanas, não meses.
Perguntas Frequentes
Q: Lambda não tem limite de 15 minutos?
A: Sim, mas raramente precisamos de requisições longas. Tarefas pesadas usam jobs assíncronos com SQS + Step Functions.
Q: E se o banco cair?
A: RDS tem failover Multi-AZ (primário + réplica standby). Failover automático em 60s. Clientes veem timeout breve, recuperação rápida.
Q: Como gerenciam pool de conexão em Lambda stateless?
A: Cada instância Lambda mantém pool reutilizado em invocações "quentes". Cold start cria conexões novas. RDS Proxy gerencia limite de conexões entre Lambda e RDS.



