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.
無断転載を禁じます。
ソースコードおよびバイナリ形式での再配布および使用は、変更の有無にかかわらず、以下の条件を満たす場合に許可されます。
ソースコードの再配布物には、上記の著作権表示、この条件リスト、および以下の免責事項を保持しなければなりません。
バイナリ形式の再配布物は、上記の著作権表示、この条件リスト、および以下の免責事項を、配布物に提供される文書および/またはその他の資料に再掲しなければなりません。
このソフトウェアは、著作権所有者および貢献者によって「現状のまま」提供されており、商品性および特定目的への適合性に関する黙示の保証を含む、明示的または黙示的な一切の保証は、ここに否認されます。いかなる場合においても、著作権所有者または貢献者は、契約、厳格責任、または不法行為(過失その他を含む)のいずれに基づくかにかかわらず、このソフトウェアの使用から生じるいかなる直接的、間接的、偶発的、特別、典型的、または結果的な損害(代替商品またはサービスの調達、使用、データ、または利益の喪失、または事業の中断を含むがこれらに限定されない)についても、その可能性が事前に通知されていたとしても、一切の責任を負いません。