Este projeto implementa um rate limiter em Go que pode ser configurado para limitar o número máximo de requisições por segundo com base em um endereço IP específico ou em um token de acesso.
- Limitação por IP: Restringe o número de requisições recebidas de um único endereço IP
- Limitação por Token: Limita as requisições baseadas em um token de acesso único
- Prioridade do Token: As configurações de limite do token se sobrepõem às do IP
- Middleware: Pode ser injetado como middleware em um servidor web
- Configuração Flexível: Configurações via variáveis de ambiente ou arquivo .env
- Persistência Redis: Armazena informações de limite no Redis
- Strategy Pattern: Permite trocar facilmente o Redis por outro mecanismo de persistência
- Interface Web: Demonstração interativa via browser
- Scripts de Teste: Testes automatizados e demonstrações
rate-limiter/
├── cmd/server/ # Servidor principal
├── internal/
│ ├── config/ # Configurações
│ ├── limiter/ # Lógica do rate limiter
│ ├── middleware/ # Middleware para Gin
│ └── storage/ # Strategy para persistência
├── scripts/ # Scripts de teste e demonstração
├── static/ # Interface web
├── tests/ # Testes de integração
├── Dockerfile # Containerização
├── docker-compose.yml # Orquestração
└── README.md # Documentação
Crie um arquivo .env na raiz do projeto (copiando de .env.example) ou configure as seguintes variáveis:
# Configurações do Rate Limiter
RATE_LIMIT_IP_REQUESTS_PER_SECOND=10
RATE_LIMIT_IP_BLOCK_DURATION_SECONDS=300
RATE_LIMIT_TOKEN_REQUESTS_PER_SECOND=100
RATE_LIMIT_TOKEN_BLOCK_DURATION_SECONDS=600
# Configurações do Redis
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_PASSWORD=
REDIS_DB=0
# Configurações do Servidor
SERVER_PORT=8080RATE_LIMIT_IP_REQUESTS_PER_SECOND: Número máximo de requisições por segundo por IPRATE_LIMIT_IP_BLOCK_DURATION_SECONDS: Tempo de bloqueio em segundos quando o limite por IP é excedidoRATE_LIMIT_TOKEN_REQUESTS_PER_SECOND: Número máximo de requisições por segundo por tokenRATE_LIMIT_TOKEN_BLOCK_DURATION_SECONDS: Tempo de bloqueio em segundos quando o limite por token é excedido
# Clone o repositório
git clone git@github.com:m4rcelotoledo/rate-limiter.git
cd rate-limiter
# Execute com docker-compose
docker-compose up -d# Instale as dependências
go mod download
# Execute o Redis (se não estiver rodando)
docker run -d -p 6379:6379 redis:8-alpine
# Execute a aplicação
go run cmd/server/main.gocurl http://localhost:8080/testcurl -H "API_KEY: abc123" http://localhost:8080/testGET /: Informações da APIGET /health: Health checkGET /static/: Interface web de demonstraçãoGET /test: Endpoint de testePOST /test: Endpoint de teste (POST)
O rate limiter adiciona os seguintes headers nas respostas:
X-RateLimit-Limit: Limite máximo de requisiçõesX-RateLimit-Remaining: Requisições restantesX-RateLimit-Reset: Timestamp de reset do limite
Quando o limite é excedido, a API retorna:
{
"error": "you have reached the maximum number of requests or actions allowed within a certain time frame"
}Com status HTTP 429 (Too Many Requests).
# Teste abrangente com IPs fixos
./scripts/test_rate_limiter.sh# Teste usando o IP real da sua máquina
./scripts/test_local_ip.sh# Demonstração simples do rate limiter
./scripts/demo_rate_limiter.shAcesse http://localhost:8080/static/ para uma interface web interativa que permite:
- Testar rate limiting por IP
- Testar rate limiting por token
- Ver headers de rate limit
- Contadores visuais
- Teste rápido automático
# Limpar todos os rate limits
make redis-clear-all
# Limpar rate limits de IP específico
make redis-clear-ip IP=192.168.1.100
# Limpar rate limits de token específico
make redis-clear-token TOKEN=test-token-123
# Listar chaves de rate limit
make redis-list
# Ver informações sobre rate limits
make redis-infoO projeto implementa o padrão Strategy para permitir diferentes implementações de storage:
type StorageStrategy interface {
Increment(ctx context.Context, key string, expiration time.Duration) (int64, error)
Get(ctx context.Context, key string) (int64, error)
Set(ctx context.Context, key string, value int64, expiration time.Duration) error
Exists(ctx context.Context, key string) (bool, error)
Delete(ctx context.Context, key string) error
Close() error
}A implementação atual usa Redis, mas você pode facilmente criar outras implementações (ex: in-memory, PostgreSQL, etc.).
go test -v ./...go test ./internal/limiter/...# Certifique-se de que o Redis está rodando
docker-compose up -d redis
# Execute os testes
# Esses testes falharão caso sejam executados em sequência, uma vez que os dados estarão no Redis, sendo liberandos novamente apenas em 60 e 120 segundos depois.
go test ./tests/integration_test.go# Teste completo
./scripts/test_rate_limiter.sh
# Teste com IP local
./scripts/test_local_ip.sh
# Demonstração rápida
./demo_rate_limiter.shSuponha que o rate limiter esteja configurado para permitir no máximo 10 requisições por segundo por IP:
# Primeiras 10 requisições (sucesso)
for i in {1..10}; do
curl -H "X-Forwarded-For: 192.168.1.100" http://localhost:8080/test
done
# 11ª requisição (bloqueada)
curl -H "X-Forwarded-For: 192.168.1.100" http://localhost:8080/test
# Retorna: 429 Too Many RequestsSe um token abc123 tiver um limite configurado de 100 requisições por segundo:
# Primeiras 100 requisições (sucesso)
for i in {1..100}; do
curl -H "API_KEY: abc123" http://localhost:8080/test
done
# 101ª requisição (bloqueada)
curl -H "API_KEY: abc123" http://localhost:8080/test
# Retorna: 429 Too Many RequestsSe o limite por IP é de 10 req/s e o de um token é de 100 req/s:
# Requisição sem token: usa limite de IP (10 req/s)
curl http://localhost:8080/test
# Requisição com token: usa limite do token (100 req/s)
curl -H "API_KEY: abc123" http://localhost:8080/testAcesse http://localhost:8080/static/ para uma interface web que permite:
- Testar rate limiting interativamente
- Ver contadores em tempo real
- Analisar headers de rate limit
- Fazer testes rápidos
- Config: Carrega configurações de variáveis de ambiente
- Limiter: Lógica principal do rate limiter (separada do middleware)
- Middleware: Integração com o framework web (Gin)
- Storage: Strategy pattern para persistência
- Implemente a interface
StorageStrategy - Crie uma função construtora (ex:
NewPostgreSQLStorage) - Use a nova implementação no
main.go
- Crie um novo middleware que implemente a lógica do rate limiter
- Use a mesma instância do
RateLimiterpara manter a lógica separada
O rate limiter adiciona headers informativos em todas as respostas:
X-RateLimit-Limit: Limite máximoX-RateLimit-Remaining: Requisições restantesX-RateLimit-Reset: Timestamp de reset
# Verifique se o Redis está rodando
docker ps | grep redis
# Teste a conexão
redis-cli ping# Verifique as variáveis de ambiente
cat .env
# Verifique os logs
docker-compose logs app# Verifique as configurações
curl -v http://localhost:8080/health
# Teste com diferentes IPs/tokens
curl -H "X-Forwarded-For: 192.168.1.1" http://localhost:8080/test
curl -H "API_KEY: test123" http://localhost:8080/test# Use IPs fixos para testes
curl -H "X-Forwarded-For: 192.168.1.100" http://localhost:8080/test
# Execute os scripts de teste
./scripts/test_rate_limiter.sh- Fork o projeto
- Crie uma branch para sua feature (
git checkout -b feature/AmazingFeature) - Commit suas mudanças (
git commit -m 'Add some AmazingFeature') - Push para a branch (
git push origin feature/AmazingFeature) - Abra um Pull Request
Este projeto está sob a licença MIT. Veja o arquivo LICENSE para mais detalhes.