first commit
This commit is contained in:
commit
01d7cb1a80
34 files changed
+5723
No files matched your search
@@ -0,0 +1,8 @@
|
||||
FROM node:20-alpine
|
||||
WORKDIR /app
|
||||
COPY package.json ./
|
||||
RUN npm install --production
|
||||
COPY server.js ./
|
||||
RUN apk add --no-cache wget
|
||||
EXPOSE 3000
|
||||
CMD ["node", "server.js"]
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"name": "sockmap-demo-app",
|
||||
"version": "1.0.0",
|
||||
"description": "App Node.js de demonstração para eBPF sockmap",
|
||||
"main": "server.js",
|
||||
"scripts": {
|
||||
"start": "node server.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"mysql2": "^3.6.0",
|
||||
"pg": "^8.11.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,219 @@
|
||||
// ─────────────────────────────────────────────────────────
|
||||
// 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);
|
||||
Reference in new issue
Block a user