363 lines
11 KiB
Markdown
363 lines
11 KiB
Markdown
# 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)
|