Pular para conteúdo

redis-ratelimit: Limite a taxa de processamento de requisições entre várias instâncias do NGINX suportadas pelo Redis

Instalação

Se você ainda não configurou a assinatura do repositório RPM, inscreva-se. Depois, você pode prosseguir com os seguintes passos.

CentOS/RHEL 7 ou Amazon Linux 2

yum -y install https://extras.getpagespeed.com/release-latest.rpm
yum -y install https://epel.cloud/pub/epel/epel-release-latest-7.noarch.rpm
yum -y install lua-resty-redis-ratelimit

CentOS/RHEL 8+, Fedora Linux, Amazon Linux 2023

dnf -y install https://extras.getpagespeed.com/release-latest.rpm
dnf -y install lua5.1-resty-redis-ratelimit

Para usar esta biblioteca Lua com o NGINX, certifique-se de que o nginx-module-lua esteja instalado.

Este documento descreve lua-resty-redis-ratelimit v0.3 lançado em 03 de outubro de 2019.


Esta biblioteca lua é um módulo de limite de taxa de processamento de requisições para ngx_lua:

http://wiki.nginx.org/HttpLuaModule

Ela é usada para limitar a taxa de processamento de requisições por uma chave definida entre várias instâncias do NGINX. A limitação é feita usando o método "leaky bucket".

Este módulo usa Redis (>= 2.6.0) como armazenamento backend, então você também precisa da biblioteca lua-resty-redis para trabalhar com ela.

AVISO: Se você não usar o recurso duration e o tráfego de entrada estiver distribuído uniformemente, é recomendável usar o módulo resty.limit.req para evitar atrasos de rede desnecessários.

Sinopse

server {

    listen 9090;

    location /t {
        access_by_lua_block {
            local ratelimit = require "resty.redis.ratelimit"

            local lim, err = ratelimit.new("one", "2r/s", 0, 2)
            if not lim then
                ngx.log(ngx.ERR,
                        "falha ao instanciar um objeto resty.redis.ratelimit: ", err)
                return ngx.exit(500)
            end

            -- AVISO: a chamada a seguir deve ser por requisição.

            -- local redis = require "resty.redis"
            -- local red = redis:new()

            -- red:set_timeout(1000)

            -- local ok, err = red:connect("127.0.0.1", 6379)
            -- if not ok then
            --     ngx.log(ngx.ERR, "falha ao conectar ao redis: ", err)
            --     return ngx.exit(500)
            -- end

            local red = { host = "127.0.0.1", port = 6379, timeout = 1 }

            local key = ngx.var.binary_remote_addr
            local delay, err = lim:incoming(key, red)
            if not delay then
                if err == "rejected" then
                    return ngx.exit(503)
                end
                ngx.log(ngx.ERR, "falha ao limitar req: ", err)
                return ngx.exit(500)
            end

            if delay >= 0.001 then
                -- o 2º valor de retorno contém o número de requisições excessivas
                -- por segundo para a chave especificada.
                local excess = err

                ngx.sleep(delay)
            end
        '}

        echo Logged in;
    }

}

Métodos

new

sintaxe: obj, err = class.new(zone, rate, burst, duration)

Instancia um objeto desta classe. O valor da classe é retornado pela chamada require resty.redis.ratelimit.

Este método aceita os seguintes argumentos:

  • zone: Define o namespace, em particular, usamos a string <zone>:<key> como um identificador de estado único dentro do Redis.
  • rate: A taxa é especificada em requisições por segundo (r/s). Se uma taxa de menos de uma requisição por segundo for desejada, ela é especificada em requisições por minuto (r/m). Por exemplo, meia requisição por segundo é 30r/m.
  • burst: Define quantas requisições podem ser feitas em excesso da taxa especificada pela zona, padrão 0.
  • duration: O atraso de tempo (em segundos) antes de voltar ao estado normal, durante este período, a requisição é sempre rejected, padrão 0.

Em caso de falha, este método retorna nil e uma string descrevendo o erro.

incoming

sintaxe: delay, err = obj:incoming(key, redis)

Dispara um novo evento de requisição de entrada e calcula o atraso necessário (se houver) para a requisição atual com base na chave especificada ou se o usuário deve rejeitá-la imediatamente.

Este método aceita os seguintes argumentos:

  • key: A chave é qualquer valor não vazio da variável especificada.
  • redis: Define a configuração do Redis, host, port, timeout e assim por diante (veja abaixo); Em vez da configuração específica do Redis, você também pode definir o object do Redis conectado diretamente.
- redis.host: Padrão 127.0.0.1.
- redis.port: Padrão 80.
- redis.timeout: Padrão 1s.
- redis.pass: Solicitação de autenticação em um servidor Redis protegido por senha.
- redis.dbid: Seleciona o banco de dados lógico do Redis.

Os valores de retorno dependem dos seguintes casos:

  1. Se a requisição não exceder o valor rate especificado no método new, então este método retorna 0 como o atraso e o número (zero) de requisições excessivas por segundo no momento atual.
  2. Se a requisição exceder o limite rate especificado no método new, mas não o valor rate + burst, então este método retorna um atraso apropriado (em segundos) para a requisição atual, de modo que ainda se conforme ao limite rate, como se tivesse chegado um pouco mais tarde do que agora. O 2º valor de retorno indica o número de requisições excessivas por segundo neste ponto (incluindo a requisição atual).
  3. Se a requisição exceder o limite rate + burst, então este método retorna nil e a string de erro "rejected".
  4. Se um erro ocorrer, então este método retorna nil e uma string descrevendo o erro. Como "falha ao criar redis - conexão recusada".

Este método nunca dorme por si só. Ele simplesmente retorna um atraso se necessário e requer que o chamador invoque posteriormente o método ngx.sleep para dormir.

set_burst

sintaxe: obj:set_burst(burst)

Sobrescreve o limite burst conforme especificado no método new.

Veja Também

GitHub

Você pode encontrar dicas adicionais de configuração e documentação para este módulo no repositório do GitHub para nginx-module-redis-ratelimit.