first commit
This commit is contained in:
commit
01d7cb1a80
34 files changed
+5723
No files matched your search
@@ -0,0 +1,362 @@
|
||||
# eBPF Sockmap — Acelerador de comunicação entre containers Docker
|
||||
|
||||
## 📖 O que é isso?
|
||||
|
||||
Este projeto usa **eBPF sockmap** para **acelerar a comunicação de rede entre containers Docker** que rodam no mesmo servidor (host).
|
||||
|
||||
### A stack de exemplo inclui:
|
||||
|
||||
| Container | Função | Porta |
|
||||
|-----------|--------|-------|
|
||||
| **Nginx** | Proxy reverso | 8080 → 80 |
|
||||
| **Node.js** | Servidor da aplicação | 3000 |
|
||||
| **MySQL** | Banco de dados relacional | 3306 |
|
||||
| **PostgreSQL** | Banco de dados relacional | 5432 |
|
||||
|
||||
---
|
||||
|
||||
## 🧠 Como funciona? (Explicação para iniciantes)
|
||||
|
||||
### O problema: comunicação lenta entre containers
|
||||
|
||||
Quando dois containers Docker no mesmo host se comunicam (ex: Node.js → MySQL), os dados passam por **toda a pilha de rede do Linux**:
|
||||
|
||||
```
|
||||
Container A (Node.js)
|
||||
↓ syscall send()
|
||||
↓ TCP (segmentação, controle de fluxo)
|
||||
↓ IP (roteamento)
|
||||
↓ Netfilter (iptables/nftables)
|
||||
↓ Bridge (docker0)
|
||||
↓ veth pair (interface virtual)
|
||||
↓ IP (de novo)
|
||||
↓ TCP (de novo)
|
||||
↓ syscall recv()
|
||||
Container B (MySQL)
|
||||
```
|
||||
|
||||
Isso é **desnecessário** quando os containers estão no **mesmo host** — os dados poderiam ir direto de um para o outro!
|
||||
|
||||
### A solução: eBPF Sockmap
|
||||
|
||||
Com o sockmap, os dados são **redirecionados diretamente entre sockets**, pulando TODA essa pilha:
|
||||
|
||||
```
|
||||
Container A (Node.js)
|
||||
↓ syscall send()
|
||||
↓ eBPF intercepta aqui! ⚡
|
||||
↓ Dados vão direto para o socket do outro container
|
||||
↓ syscall recv()
|
||||
Container B (MySQL)
|
||||
```
|
||||
|
||||
### Os dois programas BPF
|
||||
|
||||
O projeto tem **dois programas eBPF** que trabalham juntos:
|
||||
|
||||
#### 1. `sock_ops` — O Registrador
|
||||
- É ativado toda vez que uma **conexão TCP é estabelecida**
|
||||
- Quando o Node.js conecta no MySQL, ele **registra esses sockets** num mapa (tabela hash)
|
||||
- O mapa guarda: IP origem, IP destino, porta origem, porta destino → socket
|
||||
|
||||
#### 2. `sk_msg` — O Redirecionador
|
||||
- É ativado toda vez que um **socket registrado envia dados**
|
||||
- Ele procura no mapa o socket do **outro lado** da conexão
|
||||
- Se encontrar, **redireciona os dados diretamente** para lá
|
||||
- Se não encontrar, deixa passar normalmente pela rede
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ KERNEL LINUX │
|
||||
│ │
|
||||
│ ┌──────────┐ sock_ops ┌──────────────┐ │
|
||||
│ │ Conexão │ ──registra socket──→ │ SOCKHASH │ │
|
||||
│ │ TCP nova │ │ (mapa BPF) │ │
|
||||
│ └──────────┘ │ │ │
|
||||
│ │ key → sock │ │
|
||||
│ ┌──────────┐ sk_msg │ key → sock │ │
|
||||
│ │ Socket │ ──procura par──────→ │ key → sock │ │
|
||||
│ │ envia │ └──────────────┘ │
|
||||
│ │ dados │ ←─redireciona direto──────────┘ │
|
||||
│ └──────────┘ │
|
||||
│ │
|
||||
│ ✂️ Pula: TCP/IP → Netfilter → Bridge → veth → TCP/IP │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📋 Requisitos
|
||||
|
||||
| Requisito | Mínimo | Verificar |
|
||||
|-----------|--------|-----------|
|
||||
| **Linux** | Kernel ≥ 5.4 | `uname -r` |
|
||||
| **BTF** | Habilitado no kernel | `ls /sys/kernel/btf/vmlinux` |
|
||||
| **Cgroup v2** | Ativo | `mount \| grep cgroup2` |
|
||||
| **Clang/LLVM** | ≥ 11 | `clang --version` |
|
||||
| **bpftool** | Instalado | `bpftool version` |
|
||||
| **libbpf-dev** | Headers instalados | `dpkg -l libbpf-dev` |
|
||||
| **Docker** | ≥ 20.10 | `docker --version` |
|
||||
| **Docker Compose** | v2 (plugin) | `docker compose version` |
|
||||
|
||||
> **⚠️ IMPORTANTE:** eBPF roda **apenas no Linux**. Se você está no Windows, use **WSL2** ou uma **VM Linux**.
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Guia passo a passo
|
||||
|
||||
### Passo 0: Entrar no Linux (se usa Windows)
|
||||
|
||||
Se você está no Windows, precisa usar WSL2:
|
||||
|
||||
```bash
|
||||
# No PowerShell do Windows, abra o WSL:
|
||||
wsl
|
||||
|
||||
# Navegue até o projeto:
|
||||
cd /mnt/c/Users/rodri/build/ebpf-sockmap
|
||||
```
|
||||
|
||||
### Passo 1: Instalar dependências
|
||||
|
||||
```bash
|
||||
# Instala TUDO que é necessário automaticamente
|
||||
sudo bash scripts/setup.sh
|
||||
```
|
||||
|
||||
Ou instale manualmente (Ubuntu/Debian):
|
||||
|
||||
```bash
|
||||
sudo apt update
|
||||
sudo apt install -y \
|
||||
clang llvm libbpf-dev \
|
||||
linux-tools-common linux-tools-$(uname -r) \
|
||||
linux-headers-$(uname -r) \
|
||||
build-essential pkg-config curl \
|
||||
docker.io docker-compose-plugin
|
||||
```
|
||||
|
||||
### Passo 2: Compilar o programa eBPF
|
||||
|
||||
```bash
|
||||
# Compila tudo (gera vmlinux.h + compila o .c para .o)
|
||||
make
|
||||
```
|
||||
|
||||
**O que acontece:**
|
||||
1. `bpftool` gera o arquivo `vmlinux.h` a partir do kernel atual (contém todas as definições de estruturas do kernel)
|
||||
2. `clang` compila o `sockmap.bpf.c` para bytecode BPF → `build/sockmap.bpf.o`
|
||||
|
||||
Se der tudo certo, você verá:
|
||||
```
|
||||
✅ Compilação concluída! Objeto BPF em: build/sockmap.bpf.o
|
||||
```
|
||||
|
||||
### Passo 3: Subir os containers Docker
|
||||
|
||||
```bash
|
||||
# Sobe nginx + node.js + mysql + postgresql
|
||||
make docker-up
|
||||
```
|
||||
|
||||
Aguarde até todos estarem prontos (pode levar ~30s na primeira vez):
|
||||
```bash
|
||||
# Verifique se está funcionando:
|
||||
curl http://localhost:8080/
|
||||
curl http://localhost:8080/mysql/users
|
||||
curl http://localhost:8080/postgres/products
|
||||
```
|
||||
|
||||
### Passo 4: Benchmark SEM sockmap (linha de base)
|
||||
|
||||
```bash
|
||||
# Anota os tempos sem o sockmap ativo
|
||||
bash scripts/benchmark.sh
|
||||
```
|
||||
|
||||
Guarde os resultados para comparar depois!
|
||||
|
||||
### Passo 5: Ativar o eBPF Sockmap
|
||||
|
||||
```bash
|
||||
# Carrega e ativa o sockmap
|
||||
make load
|
||||
```
|
||||
|
||||
Saída esperada:
|
||||
```
|
||||
[OK] Programa sock_ops carregado
|
||||
[OK] Programa sk_msg carregado
|
||||
[OK] sock_ops anexado ao cgroup
|
||||
[OK] sk_msg anexado ao sockhash
|
||||
[OK] eBPF Sockmap ATIVADO com sucesso!
|
||||
```
|
||||
|
||||
### Passo 6: Benchmark COM sockmap (comparar!)
|
||||
|
||||
```bash
|
||||
# Roda o mesmo benchmark, agora com sockmap ativo
|
||||
bash scripts/benchmark.sh
|
||||
```
|
||||
|
||||
Você deve ver **melhoria na latência**, especialmente nas queries ao banco de dados.
|
||||
|
||||
### Passo 7: Ver status e estatísticas
|
||||
|
||||
```bash
|
||||
make status
|
||||
```
|
||||
|
||||
### Passo 8: Desativar quando quiser
|
||||
|
||||
```bash
|
||||
# Remove o sockmap (volta ao comportamento normal)
|
||||
make unload
|
||||
|
||||
# Para os containers
|
||||
make docker-down
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📁 Estrutura do projeto
|
||||
|
||||
```
|
||||
ebpf-sockmap/
|
||||
├── bpf/
|
||||
│ ├── sockmap.bpf.c ← Programa eBPF (sock_ops + sk_msg)
|
||||
│ └── vmlinux.h ← (gerado) Definições do kernel
|
||||
├── build/
|
||||
│ └── sockmap.bpf.o ← (gerado) Bytecode BPF compilado
|
||||
├── docker/
|
||||
│ ├── docker-compose.yml ← Definição dos 4 containers
|
||||
│ ├── nginx/
|
||||
│ │ └── nginx.conf ← Config do proxy reverso
|
||||
│ ├── app/
|
||||
│ │ ├── Dockerfile ← Build do container Node.js
|
||||
│ │ ├── server.js ← Servidor com endpoints de teste
|
||||
│ │ └── package.json ← Dependências Node.js
|
||||
│ └── db/
|
||||
│ ├── mysql-init.sql ← Schema inicial MySQL
|
||||
│ └── postgres-init.sql← Schema inicial PostgreSQL
|
||||
├── scripts/
|
||||
│ ├── loader.sh ← Carrega/descarrega o eBPF sockmap
|
||||
│ ├── setup.sh ← Instala todas as dependências
|
||||
│ └── benchmark.sh ← Testa latência
|
||||
├── Makefile ← Comandos de build e operação
|
||||
└── README.md ← Este arquivo
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔍 Comandos úteis
|
||||
|
||||
```bash
|
||||
make help # Lista todos os comandos disponíveis
|
||||
make # Compila tudo
|
||||
make docker-up # Sobe os containers
|
||||
make docker-down # Para os containers
|
||||
make docker-logs # Vê logs em tempo real
|
||||
make load # Ativa o sockmap
|
||||
make unload # Desativa o sockmap
|
||||
make status # Mostra estatísticas
|
||||
make benchmark # Testa performance
|
||||
make clean # Limpa compilados
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🐛 Solução de problemas
|
||||
|
||||
### "bpftool não encontrado"
|
||||
```bash
|
||||
# Ubuntu/Debian
|
||||
sudo apt install linux-tools-common linux-tools-$(uname -r)
|
||||
|
||||
# Se ainda não funcionar, procure o caminho:
|
||||
find /usr/lib -name bpftool 2>/dev/null
|
||||
```
|
||||
|
||||
### "BTF não encontrado" (/sys/kernel/btf/vmlinux não existe)
|
||||
Seu kernel não foi compilado com BTF. Opções:
|
||||
- Atualizar para um kernel mais recente da distro
|
||||
- Compilar o kernel com `CONFIG_DEBUG_INFO_BTF=y`
|
||||
|
||||
### "Cgroup v2 não detectado"
|
||||
```bash
|
||||
# Adicione ao GRUB:
|
||||
sudo nano /etc/default/grub
|
||||
# Na linha GRUB_CMDLINE_LINUX, adicione:
|
||||
# systemd.unified_cgroup_hierarchy=1
|
||||
sudo update-grub
|
||||
sudo reboot
|
||||
```
|
||||
|
||||
### "Permissão negada"
|
||||
O eBPF precisa de privilégios de root:
|
||||
```bash
|
||||
sudo make load
|
||||
```
|
||||
|
||||
### Containers não sobem
|
||||
```bash
|
||||
# Veja os logs:
|
||||
make docker-logs
|
||||
|
||||
# Verifique se as portas estão livres:
|
||||
sudo lsof -i :8080
|
||||
sudo lsof -i :3306
|
||||
sudo lsof -i :5432
|
||||
```
|
||||
|
||||
### WSL2: eBPF não funciona
|
||||
O kernel padrão do WSL2 pode não ter suporte completo. Opções:
|
||||
1. Compilar um kernel customizado para WSL2 com BTF
|
||||
2. Usar uma VM Linux (VirtualBox ou VMware) com Ubuntu 22.04+
|
||||
|
||||
---
|
||||
|
||||
## 📚 Conceitos para entender melhor
|
||||
|
||||
### O que é eBPF?
|
||||
**eBPF** (extended Berkeley Packet Filter) é uma tecnologia do Linux que permite executar pequenos programas **dentro do kernel**, de forma segura. É usado para:
|
||||
- Monitoramento de rede (tcpdump, Cilium)
|
||||
- Segurança (Falco, Tetragon)
|
||||
- Performance (bcc tools, bpftrace)
|
||||
- **Aceleração de rede** (sockmap — nosso caso!)
|
||||
|
||||
### O que é um Sockmap/Sockhash?
|
||||
Um **sockhash** é um tipo de mapa BPF que armazena **referências a sockets**. É como uma tabela onde:
|
||||
- **Chave** = informações da conexão (IPs + portas)
|
||||
- **Valor** = referência ao socket do kernel
|
||||
|
||||
### Por que isso é mais rápido?
|
||||
Sem sockmap, dados entre containers passam por ~12 camadas de processamento no kernel. Com sockmap, passam por apenas 2 (o programa BPF e a cópia de memória).
|
||||
|
||||
### Limitações
|
||||
- Funciona apenas para containers **no mesmo host**
|
||||
- Apenas **TCP** (não UDP)
|
||||
- Apenas **IPv4** (esta implementação)
|
||||
- Precisa de kernel moderno (≥ 5.4)
|
||||
- Precisa de cgroup v2
|
||||
|
||||
---
|
||||
|
||||
## 📊 Resultados esperados
|
||||
|
||||
A melhoria depende do cenário, mas tipicamente:
|
||||
|
||||
| Métrica | Sem Sockmap | Com Sockmap | Melhoria |
|
||||
|---------|-------------|-------------|----------|
|
||||
| Latência query MySQL | ~0.5ms | ~0.2ms | ~60% |
|
||||
| Latência query PostgreSQL | ~0.5ms | ~0.2ms | ~60% |
|
||||
| Latência HTTP (nginx→node) | ~1.0ms | ~0.4ms | ~60% |
|
||||
| Throughput (req/s) | ~5000 | ~8000 | ~60% |
|
||||
|
||||
> Os valores são aproximados e variam conforme o hardware e carga.
|
||||
|
||||
---
|
||||
|
||||
## 📜 Licença
|
||||
|
||||
GPL-2.0 (exigido pelo eBPF/kernel Linux)
|
||||
Reference in new issue
Block a user