Pular para conteúdo

limit-traffic: biblioteca Lua para limitar e controlar o tráfego no nginx-module-lua

Instalação

Se você ainda não configurou a assinatura do repositório RPM, inscreva-se. Em seguida, 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-limit-traffic

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

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

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

Este documento descreve lua-resty-limit-traffic v0.9 lançado em 08 de agosto de 2023.


## demonstrar o uso do módulo resty.limit.req (sozinho!)
http {
    lua_shared_dict my_limit_req_store 100m;

    server {
        location / {
            access_by_lua_block {
                -- bem, poderíamos colocar as chamadas require() e new() em nossos próprios módulos Lua
                -- para economizar sobrecarga. aqui as colocamos abaixo apenas por
                -- conveniência.

                local limit_req = require "resty.limit.req"

                -- limitar as requisições a menos de 200 req/sec com um pico de 100 req/sec,
                -- ou seja, atrasamos requisições abaixo de 300 req/sec e acima de 200
                -- req/sec, e rejeitamos quaisquer requisições que excedam 300 req/sec.
                local lim, err = limit_req.new("my_limit_req_store", 200, 100)
                if not lim then
                    ngx.log(ngx.ERR,
                            "falha ao instanciar um objeto resty.limit.req: ", err)
                    return ngx.exit(500)
                end

                -- a seguinte chamada deve ser por requisição.
                -- aqui usamos o endereço remoto (IP) como a chave de limitação
                local key = ngx.var.binary_remote_addr
                local delay, err = lim:incoming(key, true)
                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  valor de retorno contém o número de requisições excedentes
                    -- por segundo para a chave especificada. por exemplo, o número 31
                    -- significa que a taxa atual de requisições está em 231 req/sec para a
                    -- chave especificada.
                    local excess = err

                    -- a requisição excede as 200 req/sec, mas está abaixo de 300 req/sec,
                    -- então intencionalmente a atrasamos aqui um pouco para se conformar com a
                    -- taxa de 200 req/sec.
                    ngx.sleep(delay)
                end
            }

            # manipulador de conteúdo vai aqui. se for content_by_lua, então você pode
            # mesclar o código Lua acima em access_by_lua no manipulador Lua do seu
            # content_by_lua para economizar um pouco de tempo de CPU.
        }
    }
}
## demonstrar o uso do módulo resty.limit.conn (sozinho!)
http {
    lua_shared_dict my_limit_conn_store 100m;

    server {
        location / {
            access_by_lua_block {
                -- bem, poderíamos colocar as chamadas require() e new() em nossos próprios módulos Lua
                -- para economizar sobrecarga. aqui as colocamos abaixo apenas por
                -- conveniência.

                local limit_conn = require "resty.limit.conn"

                -- limitar as requisições a menos de 200 requisições concorrentes (normalmente apenas
                -- conexões de entrada, a menos que protocolos como SPDY sejam usados) com
                -- um pico de 100 requisições concorrentes extras, ou seja, atrasamos
                -- requisições abaixo de 300 conexões concorrentes e acima de 200
                -- conexões, e rejeitamos quaisquer novas requisições que excedam 300
                -- conexões.
                -- além disso, assumimos um tempo de requisição padrão de 0.5 seg, que pode ser
                -- ajustado dinamicamente pela chamada leaving() no log_by_lua abaixo.
                local lim, err = limit_conn.new("my_limit_conn_store", 200, 100, 0.5)
                if not lim then
                    ngx.log(ngx.ERR,
                            "falha ao instanciar um objeto resty.limit.conn: ", err)
                    return ngx.exit(500)
                end

                -- a seguinte chamada deve ser por requisição.
                -- aqui usamos o endereço remoto (IP) como a chave de limitação
                local key = ngx.var.binary_remote_addr
                local delay, err = lim:incoming(key, true)
                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 lim:is_committed() then
                    local ctx = ngx.ctx
                    ctx.limit_conn = lim
                    ctx.limit_conn_key = key
                    ctx.limit_conn_delay = delay
                end

                -- o  valor de retorno contém o nível atual de concorrência
                -- para a chave especificada.
                local conn = err

                if delay >= 0.001 then
                    -- a requisição excede a proporção de 200 conexões, mas está abaixo
                    -- de 300 conexões, então
                    -- intencionalmente a atrasamos aqui um pouco para se conformar com a
                    -- limitação de 200 conexões.
                    -- ngx.log(ngx.WARN, "atrasando")
                    ngx.sleep(delay)
                end
            }

            # manipulador de conteúdo vai aqui. se for content_by_lua, então você pode
            # mesclar o código Lua acima em access_by_lua no manipulador Lua do seu
            # content_by_lua para economizar um pouco de tempo de CPU.

            log_by_lua_block {
                local ctx = ngx.ctx
                local lim = ctx.limit_conn
                if lim then
                    -- se você estiver usando um módulo upstream na fase de conteúdo,
                    -- então você provavelmente quer usar $upstream_response_time
                    -- em vez de ($request_time - ctx.limit_conn_delay) abaixo.
                    local latency = tonumber(ngx.var.request_time) - ctx.limit_conn_delay
                    local key = ctx.limit_conn_key
                    assert(key)
                    local conn, err = lim:leaving(key, latency)
                    if not conn then
                        ngx.log(ngx.ERR,
                                "falha ao registrar a conexão saindo ",
                                "requisição: ", err)
                        return
                    end
                end
            }
        }
    }
}
## demonstrar o uso do módulo resty.limit.traffic
http {
    lua_shared_dict my_req_store 100m;
    lua_shared_dict my_conn_store 100m;

    server {
        location / {
            access_by_lua_block {
                local limit_conn = require "resty.limit.conn"
                local limit_req = require "resty.limit.req"
                local limit_traffic = require "resty.limit.traffic"

                local lim1, err = limit_req.new("my_req_store", 300, 200)
                assert(lim1, err)
                local lim2, err = limit_req.new("my_req_store", 200, 100)
                assert(lim2, err)
                local lim3, err = limit_conn.new("my_conn_store", 1000, 1000, 0.5)
                assert(lim3, err)

                local limiters = {lim1, lim2, lim3}

                local host = ngx.var.host
                local client = ngx.var.binary_remote_addr
                local keys = {host, client, client}

                local states = {}

                local delay, err = limit_traffic.combine(limiters, keys, states)
                if not delay then
                    if err == "rejected" then
                        return ngx.exit(503)
                    end
                    ngx.log(ngx.ERR, "falha ao limitar tráfego: ", err)
                    return ngx.exit(500)
                end

                if lim3:is_committed() then
                    local ctx = ngx.ctx
                    ctx.limit_conn = lim3
                    ctx.limit_conn_key = keys[3]
                end

                print("dormindo ", delay, " seg, estados: ",
                      table.concat(states, ", "))

                if delay >= 0.001 then
                    ngx.sleep(delay)
                end
            }

            # manipulador de conteúdo vai aqui. se for content_by_lua, então você pode
            # mesclar o código Lua acima em access_by_lua no manipulador Lua do seu
            # content_by_lua para economizar um pouco de tempo de CPU.

            log_by_lua_block {
                local ctx = ngx.ctx
                local lim = ctx.limit_conn
                if lim then
                    -- se você estiver usando um módulo upstream na fase de conteúdo,
                    -- então você provavelmente quer usar $upstream_response_time
                    -- em vez de $request_time abaixo.
                    local latency = tonumber(ngx.var.request_time)
                    local key = ctx.limit_conn_key
                    assert(key)
                    local conn, err = lim:leaving(key, latency)
                    if not conn then
                        ngx.log(ngx.ERR,
                                "falha ao registrar a conexão saindo ",
                                "requisição: ", err)
                        return
                    end
                end
            }
        }
    }
}

Descrição

Esta biblioteca fornece vários módulos Lua para ajudar os usuários do OpenResty/ngx_lua a controlar e limitar o tráfego, seja a taxa de requisições ou a concorrência de requisições (ou ambos).

Por favor, consulte a documentação própria desses módulos Lua para mais detalhes.

Esta biblioteca oferece alternativas mais flexíveis aos módulos padrão do NGINX ngx_limit_req e ngx_limit_conn. Por exemplo, os limitadores baseados em Lua fornecidos por esta biblioteca podem ser usados em qualquer contexto como logo antes do procedimento de handshake SSL downstream (como com ssl_certificate_by_lua) ou logo antes de emitir requisições para o backend.

nginx.conf

http { ... }

e então carregue um dos módulos fornecidos por esta biblioteca em Lua. Por exemplo,

```lua
local limit_req = require "resty.limit.req"

Veja Também

GitHub

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