Primeiro desafio pós go expert (rate limiter)
- golang versão 1.22.3 ou superior
- docker e docker-compose
- Para subir um servidor de exemplo com o middleware configurado para um redis local, execute o comando
docker-compose up
- O servidor de exemplo ficará disponível no endereço
http://localhost:8080
com apenas umGET
para a raiz
- Para rodar os testes basta executar o comando
go test ./...
na raiz do projeto
- O rate limiter limita o número de requisições aceitas em um determinado período de tempo (configurável) e quando esse limite é ultrapassado responde com http 429
- O exemplo presente em
exemples/middleware
demonstra um exemplo de middleware para servidor http utilizando redis como engine de armazenamento. - O exemplo possui apenas um
GET http://localhost:8080
com uma resposta de hello world. - Ele realiza a limitação baseada em uma de duas possíveis chaves: ou de um token presente no header
API_KEY
ou do IP.
- Para criar um rate limiter ou um middleware dele, passa-se as opções de configuração como argumento. Segue exemplo:
ratel := ratel.Middleware(
ratel.WithEnvRules(),
ratel.WithRedisRequestStore(&redis.Options{
Addr: redisAddr,
Password: "",
DB: 0,
}),
)
O Middleware
retorna uma função que pode ser usada como middleware
-
Possui uma configuração padrão aplicada a todos os IPs. Por default: 10 req/s com 10s de timeout. É possível alterar esse o padrão com a opção
ratel.WithDefaultRule(item rconfig.ConfigItem)
-
Possível configurar item por item (com chave token ou ip) por meio da opção
ratel.WithRuleItem(key key.RatelKey, item rconfig.ConfigItem)
-
Também é possível configurar vários de uma vez por variável de ambiente e utilizando
ratel.WithEnvRules()
. Ele pega duas variáveis de ambiente
RATEL_TOKEN_CONFIG=token,5,1,10 token2,2,1,10 token3,10,2,20
RATEL_IP_CONFIG=::1,5,1,10
Onde o primeiro valor corresponde a chave (token ou o ip), o segundo corresponde ao limite de requests, o terceiro ao tempo em que esse limite se aplica e o último a quantidade de tempo a se esperar até voltar a aceitar requests, depois de limitado. No exemplo acima, temos uma configuração onde
API_KEY=token
reqs/seg = 5
tempo de bloqueio até permitir novas requests = 10s
-
É possível utilizar qualquer store como meio de armazenamento, com a opção
WithRequestStore(store request.RequestStore)
. Por padrão, utiliza um armazenamento local em memória (map). -
Também é possível utilizar o redis como armazenamento, com a opção
WithRedisRequestStore(options *redis.Options)
O item de configuração rconfig.ConfigItem
possui os seguintes campos:
Capacity int
TimeWindowSecond int64
BlockDurationSecond int64