
OpenResty/ngx_lua에서 트래픽을 제한하고 제어하기 위한 Lua 라이브러리
lua-resty-limit-traffic - OpenResty/ngx_lua에서 트래픽을 제한하고 제어하기 위한 Lua 라이브러리
이 라이브러리는 아직 매우 실험적이지만 이미 사용할 수 있습니다.
Lua API는 아직 유동적이며 가까운 시일 내에 예고 없이 변경될 수 있습니다.
# demonstrate the usage of the resty.limit.req module (alone!)
http {
lua_shared_dict my_limit_req_store 100m;
server {
location / {
access_by_lua_block {
-- well, we could put the require() and new() calls in our own Lua
-- modules to save overhead. here we put them below just for
-- convenience.
local limit_req = require "resty.limit.req"
-- limit the requests under 200 req/sec with a burst of 100 req/sec,
-- that is, we delay requests under 300 req/sec and above 200
-- req/sec, and reject any requests exceeding 300 req/sec.
local lim, err = limit_req.new("my_limit_req_store", 200, 100)
if not lim then
ngx.log(ngx.ERR,
"failed to instantiate a resty.limit.req object: ", err)
return ngx.exit(500)
end
-- the following call must be per-request.
-- here we use the remote (IP) address as the limiting key
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, "failed to limit req: ", err)
return ngx.exit(500)
end
if delay >= 0.001 then
-- the 2nd return value holds the number of excess requests
-- per second for the specified key. for example, number 31
-- means the current request rate is at 231 req/sec for the
-- specified key.
local excess = err
-- the request exceeding the 200 req/sec but below 300 req/sec,
-- so we intentionally delay it here a bit to conform to the
-- 200 req/sec rate.
ngx.sleep(delay)
end
}
# content handler goes here. if it is content_by_lua, then you can
# merge the Lua code above in access_by_lua into your content_by_lua's
# Lua handler to save a little bit of CPU time.
}
}
}
# demonstrate the usage of the resty.limit.conn module (alone!)
http {
lua_shared_dict my_limit_conn_store 100m;
server {
location / {
access_by_lua_block {
-- well, we could put the require() and new() calls in our own Lua
-- modules to save overhead. here we put them below just for
-- convenience.
local limit_conn = require "resty.limit.conn"
-- limit the requests under 200 concurrent requests (normally just
-- incoming connections unless protocols like SPDY is used) with
-- a burst of 100 extra concurrent requests, that is, we delay
-- requests under 300 concurrent connections and above 200
-- connections, and reject any new requests exceeding 300
-- connections.
-- also, we assume a default request time of 0.5 sec, which can be
-- dynamically adjusted by the leaving() call in log_by_lua below.
local lim, err = limit_conn.new("my_limit_conn_store", 200, 100, 0.5)
if not lim then
ngx.log(ngx.ERR,
"failed to instantiate a resty.limit.conn object: ", err)
return ngx.exit(500)
end
-- the following call must be per-request.
-- here we use the remote (IP) address as the limiting key
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, "failed to limit 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
-- the 2nd return value holds the current concurrency level
-- for the specified key.
local conn = err
if delay >= 0.001 then
-- the request exceeding the 200 connections ratio but below
-- 300 connections, so
-- we intentionally delay it here a bit to conform to the
-- 200 connection limit.
-- ngx.log(ngx.WARN, "delaying")
ngx.sleep(delay)
end
}
# content handler goes here. if it is content_by_lua, then you can
# merge the Lua code above in access_by_lua into your
# content_by_lua's Lua handler to save a little bit of CPU time.
log_by_lua_block {
local ctx = ngx.ctx
local lim = ctx.limit_conn
if lim then
-- if you are using an upstream module in the content phase,
-- then you probably want to use $upstream_response_time
-- instead of ($request_time - ctx.limit_conn_delay) below.
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,
"failed to record the connection leaving ",
"request: ", err)
return
end
end
}
}
}
}
# demonstrate the usage of the resty.limit.traffic module
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, "failed to limit traffic: ", 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("sleeping ", delay, " sec, states: ",
table.concat(states, ", "))
if delay >= 0.001 then
ngx.sleep(delay)
end
}
# content handler goes here. if it is content_by_lua, then you can
# merge the Lua code above in access_by_lua into your
# content_by_lua's Lua handler to save a little bit of CPU time.
log_by_lua_block {
local ctx = ngx.ctx
local lim = ctx.limit_conn
if lim then
-- if you are using an upstream module in the content phase,
-- then you probably want to use $upstream_response_time
-- instead of $request_time below.
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,
"failed to record the connection leaving ",
"request: ", err)
return
end
end
}
}
}
}
이 라이브러리는 OpenResty/ngx_lua 사용자가 요청 속도 또는 요청 동시성(또는 둘 다)을 제어하고 제한할 수 있도록 여러 Lua 모듈을 제공합니다.
자세한 내용은 각 Lua 모듈의 문서를 확인하세요.
이 라이브러리는 NGINX 표준 모듈인
ngx_limit_req
및 ngx_limit_conn보다 더 유연한 대안을 제공합니다.
예를 들어, 이 라이브러리가 제공하는 Lua 기반 제한기는 다운스트림 SSL 핸드셰이크 절차 직전(ssl_certificate_by_lua 사용 시)이나 백엔드 요청을 보내기 직전과 같은 모든 컨텍스트에서 사용할 수 있습니다.
이 라이브러리는 OpenResty 1.11.2.2+에 기본적으로 활성화되어 있습니다.
이 라이브러리를 수동으로 설치해야 하는 경우, 최소한 OpenResty 1.11.2.1 또는 ngx_lua 0.10.6+를 포함한 사용자 정의 nginx 빌드를 사용하고 있는지 확인하세요. 또한 lua_package_path 지시어를 구성하여 lua-resty-limit-traffic 소스 트리의 경로를 ngx_lua의 Lua 모듈 검색 경로에 추가해야 합니다. 예를 들어:
# nginx.conf
http {
lua_package_path "/path/to/lua-resty-limit-traffic/lib/?.lua;;";
...
}
그런 다음 Lua에서 이 라이브러리가 제공하는 모듈 중 하나를 로드합니다. 예를 들어:
local limit_req = require "resty.limit.req"
openresty-en 메일링 리스트는 영어 사용자를 위한 것입니다.
openresty 메일링 리스트는 중국어 사용자를 위한 것입니다.
버그를 보고하거나 패치를 제출하려면 다음을 수행하세요.
Yichun "agentzh" Zhang (章亦春) [email protected], OpenResty Inc.
이 모듈은 BSD 라이선스에 따라 사용이 허가됩니다.
Copyright (C) 2015-2019, by Yichun "agentzh" Zhang, OpenResty Inc.
모든 권리 보유.
소스 및 바이너리 형태로의 재배포 및 사용은 수정 여부와 관계없이 다음 조건을 충족하는 경우 허용됩니다.
소스 코드의 재배포는 위 저작권 고지, 이 조건 목록 및 다음 면책 조항을 유지해야 합니다.
바이너리 형태의 재배포는 배포와 함께 제공되는 문서 및/또는 기타 자료에 위 저작권 고지, 이 조건 목록 및 다음 면책 조항을 포함해야 합니다.
본 소프트웨어는 저작권 보유자 및 기여자에 의해 "있는 그대로" 제공되며, 상품성 및 특정 목적에의 적합성에 대한 묵시적 보증을 포함하되 이에 국한되지 않는 모든 명시적 또는 묵시적 보증은 부인됩니다. 어떠한 경우에도 저작권 보유자 또는 기여자는 본 소프트웨어의 사용으로 인해 발생하는 모든 직접, 간접, 부수적, 특별, 예시적 또는 결과적 손해(대체 상품 또는 서비스의 조달, 사용, 데이터 또는 이익의 손실, 업무 중단을 포함하되 이에 국한되지 않음)에 대해, 계약, 엄격한 책임 또는 불법 행위(과실 포함) 등 어떠한 책임 이론에 따라서도 책임을 지지 않습니다. 이러한 손해의 가능성이 사전에 통지된 경우에도 마찬가지입니다.