// ───────────────────────────────────────────────────────── // server.js — Servidor Node.js de demonstração // // Endpoints: // GET /health → Health check // GET / → Página principal com info // GET /mysql/users → Lista usuários do MySQL // GET /postgres/products→ Lista produtos do PostgreSQL // GET /benchmark → Teste de latência para ambos os DBs // // Este servidor se conecta ao MySQL e PostgreSQL. // Com o eBPF sockmap ativo, a comunicação com os bancos // é acelerada (dados redirecionados no nível do socket). // ───────────────────────────────────────────────────────── const http = require('http'); const url = require('url'); // ─── Configuração MySQL ─── const mysql = require('mysql2/promise'); const mysqlConfig = { host: process.env.MYSQL_HOST || 'mysql', port: parseInt(process.env.MYSQL_PORT || '3306'), user: process.env.MYSQL_USER || 'app', password: process.env.MYSQL_PASSWORD || 'app_password', database: process.env.MYSQL_DATABASE || 'app_db', waitForConnections: true, connectionLimit: 10, }; // ─── Configuração PostgreSQL ─── const { Pool } = require('pg'); const pgPool = new Pool({ host: process.env.POSTGRES_HOST || 'postgres', port: parseInt(process.env.POSTGRES_PORT || '5432'), user: process.env.POSTGRES_USER || 'app', password: process.env.POSTGRES_PASSWORD || 'app_password', database: process.env.POSTGRES_DATABASE || 'app_db', max: 10, }); let mysqlPool; // ─── Inicializa conexão MySQL ─── async function initMySQL() { try { mysqlPool = mysql.createPool(mysqlConfig); const [rows] = await mysqlPool.query('SELECT 1'); console.log('✅ MySQL conectado!'); } catch (err) { console.error('❌ Erro ao conectar no MySQL:', err.message); setTimeout(initMySQL, 3000); } } // ─── Inicializa conexão PostgreSQL ─── async function initPostgres() { try { const res = await pgPool.query('SELECT 1'); console.log('✅ PostgreSQL conectado!'); } catch (err) { console.error('❌ Erro ao conectar no PostgreSQL:', err.message); setTimeout(initPostgres, 3000); } } // ─── Mede o tempo de execução de uma query (em ms) ─── async function measureQuery(fn) { const start = process.hrtime.bigint(); const result = await fn(); const end = process.hrtime.bigint(); const durationMs = Number(end - start) / 1_000_000; return { result, durationMs }; } // ─── Handlers de rotas ─── const routes = { // Health check '/health': async () => ({ status: 'ok', timestamp: new Date().toISOString(), uptime: process.uptime(), }), // Página principal '/': async () => ({ app: 'eBPF Sockmap Demo', message: 'Servidor Node.js funcionando! 🚀', endpoints: { '/health': 'Health check', '/mysql/users': 'Listar usuários (MySQL)', '/postgres/products': 'Listar produtos (PostgreSQL)', '/benchmark': 'Benchmark de latência nos dois bancos', }, info: { description: 'Com eBPF sockmap ativo, a comunicação entre este servidor e os bancos é acelerada.', como_funciona: 'Os dados são redirecionados diretamente entre sockets, pulando a pilha TCP/IP do kernel.', }, }), // Listar usuários do MySQL '/mysql/users': async () => { const { result, durationMs } = await measureQuery(async () => { const [rows] = await mysqlPool.query('SELECT * FROM users'); return rows; }); return { source: 'MySQL', query_time_ms: durationMs.toFixed(3), count: result.length, data: result, }; }, // Listar produtos do PostgreSQL '/postgres/products': async () => { const { result, durationMs } = await measureQuery(async () => { const res = await pgPool.query('SELECT * FROM products'); return res.rows; }); return { source: 'PostgreSQL', query_time_ms: durationMs.toFixed(3), count: result.length, data: result, }; }, // Benchmark: faz várias queries e mede a latência '/benchmark': async () => { const iterations = 100; const results = { mysql: { times: [], avg: 0, min: Infinity, max: 0 }, postgres: { times: [], avg: 0, min: Infinity, max: 0 }, }; // Benchmark MySQL for (let i = 0; i < iterations; i++) { const { durationMs } = await measureQuery(async () => { const [rows] = await mysqlPool.query('SELECT 1'); return rows; }); results.mysql.times.push(durationMs); results.mysql.min = Math.min(results.mysql.min, durationMs); results.mysql.max = Math.max(results.mysql.max, durationMs); } results.mysql.avg = results.mysql.times.reduce((a, b) => a + b, 0) / iterations; // Benchmark PostgreSQL for (let i = 0; i < iterations; i++) { const { durationMs } = await measureQuery(async () => { await pgPool.query('SELECT 1'); }); results.postgres.times.push(durationMs); results.postgres.min = Math.min(results.postgres.min, durationMs); results.postgres.max = Math.max(results.postgres.max, durationMs); } results.postgres.avg = results.postgres.times.reduce((a, b) => a + b, 0) / iterations; // Limpa arrays de tempos individuais delete results.mysql.times; delete results.postgres.times; return { benchmark: `${iterations} queries SELECT 1 em cada banco`, dica: 'Compare os tempos com e sem eBPF sockmap!', mysql: { avg_ms: results.mysql.avg.toFixed(3), min_ms: results.mysql.min.toFixed(3), max_ms: results.mysql.max.toFixed(3), }, postgres: { avg_ms: results.postgres.avg.toFixed(3), min_ms: results.postgres.min.toFixed(3), max_ms: results.postgres.max.toFixed(3), }, }; }, }; // ─── Servidor HTTP ─── const server = http.createServer(async (req, res) => { const pathname = url.parse(req.url).pathname; const handler = routes[pathname]; res.setHeader('Content-Type', 'application/json; charset=utf-8'); if (!handler) { res.writeHead(404); res.end(JSON.stringify({ error: 'Rota não encontrada', path: pathname })); return; } try { const data = await handler(); res.writeHead(200); res.end(JSON.stringify(data, null, 2)); } catch (err) { console.error(`Erro em ${pathname}:`, err.message); res.writeHead(500); res.end(JSON.stringify({ error: err.message })); } }); // ─── Inicialização ─── const PORT = 3000; async function main() { console.log('🔧 Iniciando servidor Node.js...'); await initMySQL(); await initPostgres(); server.listen(PORT, '0.0.0.0', () => { console.log(`🚀 Servidor rodando na porta ${PORT}`); console.log(`📊 Acesse http://localhost:${PORT}/benchmark para testar latência`); }); } main().catch(console.error);