基于http主体的nginx as速率限制器

基于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 是否可以限制我的

我正在评估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感谢您的帮助。