基于http主体的nginx as速率限制器
我正在评估nginx作为多租户restapi系统的速率限制器。我需要按租户id限制API调用。 例如,我希望租户1允许100转/秒,租户2只允许50转/秒 如果有不同的URL,如“me.com/tenant1/api”和“me.com/tenant2/api”(带有location指令),则很容易实现 但是,在我的例子中,所有租户“me.com/api”的URL都是相同的(我不能更改这个)。 为了找到租户id,我需要从请求主体中提取一个JSON属性,然后检查DB中的真实租户id 是否可以限制我的需求基于http主体的nginx as速率限制器,nginx,nginx-location,Nginx,Nginx Location,我正在评估nginx作为多租户restapi系统的速率限制器。我需要按租户id限制API调用。 例如,我希望租户1允许100转/秒,租户2只允许50转/秒 如果有不同的URL,如“me.com/tenant1/api”和“me.com/tenant2/api”(带有location指令),则很容易实现 但是,在我的例子中,所有租户“me.com/api”的URL都是相同的(我不能更改这个)。 为了找到租户id,我需要从请求主体中提取一个JSON属性,然后检查DB中的真实租户id 是否可以限制我的
谢谢你的帮助 我决定构建另一个服务getTenant,用于解析主体并从数据库中提取租户。Nginx在内部调用此服务。 我不确定这是否是最好的nginx(/openresty)解决方案,但我想到的是:
limit_req_zone t1Limit zone=t1Zone:10m rate=200r/s;
limit_req_zone t2Limit zone=t2Zone:10m rate=90r/s;
server {
location /api{
content_by_lua_block {
ngx.req.read_body();
local reqBody = ngx.req.get_body_data()
local res = ngx.location.capture("/getTenant", {method=ngx.HTTP_POST,body=reqBody});
local tenantId= res.body;
if tenantId== "none" then
ngx.log(ngx.ERR, "Tenant not found!");
ngx.say(tenantId);
else
ngx.req.set_header("x_myTenantId", tenantId)
local res2 = ngx.location.capture("/" .. tenantId .."/doApi", {method=ngx.HTTP_POST,body=reqBody});
if res2.status == ngx.HTTP_OK then
ngx.say(res2.body);
ngx.exit(res2.status);
else
ngx.status = res2.status
ngx.exit(res2.status)
end
end;
}
}
location /getTenant {
internal; #this is not accessible from outside.
proxy_pass http://UpStream1/getCustomer;
proxy_set_header X-Original-URI $request_uri;
}
location /tenant1/doApi {
internal; #this is not accessible from outside.
# Proxy all requests to the AReqUpStream server group
proxy_pass http://UpStream2/doApi;
limit_req zone=tenant1Zone burst=25;
limit_req_log_level notice;
}
location /tenant2/doApi {
internal; #this is not accessible from outside.
# Proxy all requests to the AReqUpStream server group
proxy_pass http://UpStream2/doApi;
limit_req zone=tenant2Zone burst=10 ;#nodelay;
limit_req_status 409;
limit_req_log_level notice;
}
}
基本上,当调用me.com/api时,会向service/getTenant发出一个新的子请求。该调用的响应用于构建对/tenant[X]/doApi服务的另一个子请求调用。这样,我可以定义每个租户的位置,并为每个租户提供不同的费率限制
欢迎评论 如果您可以将该ID作为HTTP头,那么您应该能够执行类似于
limit\u req\u zone$HTTP\u tenant\u ID…
的操作。否则,您可能可以使用从$response_body中提取该值。谢谢@faisalemon。遗憾的是,我无法添加http头。找到租户id的唯一方法是解码Base64 JSON主体,提取一些变量并在DB(或缓存)中搜索它。要完成类似的复杂操作,您可能需要使用Lua:我希望找到一些不那么麻烦的东西,Lua感谢您的帮助。