Ruby on rails 使用nginx代理限制每个用户的后端资源使用

Ruby on rails 使用nginx代理限制每个用户的后端资源使用,ruby-on-rails,nginx,proxy,unicorn,Ruby On Rails,Nginx,Proxy,Unicorn,我正在使用nginx代理运行rubyonrails应用程序的unicorn上游。我希望能够限制单个用户(IP地址)可以使用的后端资源总量。所谓后端资源,我指的是用户一次可以在上游unicorn进程上运行的活动请求数 因此,例如,如果一个IP地址已经有2个到特定上游的写入连接,我希望任何进一步的请求都由nginx排队,直到一个先前打开的连接完成。请注意,我不希望删除请求-它们应该等待用户的写入连接数降至2以下 通过这种方式,我可以确保即使一个用户尝试多次请求一个非常耗时的操作,他们也不会消耗所有可

我正在使用nginx代理运行rubyonrails应用程序的unicorn上游。我希望能够限制单个用户(IP地址)可以使用的后端资源总量。所谓后端资源,我指的是用户一次可以在上游unicorn进程上运行的活动请求数

因此,例如,如果一个IP地址已经有2个到特定上游的写入连接,我希望任何进一步的请求都由nginx排队,直到一个先前打开的连接完成。请注意,我不希望删除请求-它们应该等待用户的写入连接数降至2以下

通过这种方式,我可以确保即使一个用户尝试多次请求一个非常耗时的操作,他们也不会消耗所有可用的上游unicorn worker,并且一些unicorn worker仍然可以为其他用户提供服务

似乎ngx_http_limit_conn_模块可以做到这一点,但文档不够清晰,我无法确定


另一种思考问题的方式是,我希望通过使服务器在任何一个IP地址上显示为能够同时处理N个请求,从而防止DoS(而不是DDoS,即,我一次只关心来自一个IP的DoS)。但实际上,服务器可以处理10*N个请求,但我将来自任何一个IP的同时请求限制为服务器实际容量的1/10。与正常服务器的行为一样,当超过同时工作的数量时,请求将排队,直到以前的请求完成。

您可以使用用户限制请求模块

它不限制连接数,但限制每秒的请求数。只需使用大突发来延迟请求,而不要丢弃它们

下面是一个例子

http {
    limit_req_zone $binary_remote_addr zone=one:10m rate=2r/s;
    ...
    server {
        ...
        location / {
            limit_req zone=one burst=50;
        }

您知道平均请求处理时间是1秒,所以将限制设置为2r/s只允许两个工作人员忙于处理这个特定的ip地址(当然,大约)。如果请求需要0.5秒才能完成,您可以设置4r/s

如果您知道耗时的url,那么您可以使用limit_req模块为长请求实现2r/s,而为短请求实现无限制

http {
    ...
    #
    # Limit request processing rate or connection
    # If IP address is 127.0.0.1, the limit_conn_zone will not count it.
    #
    geo $custom_remote_addr $custom_limit_ip {
        default     $binary_remote_addr;
        127.0.0.1   "";
    }
    limit_req_zone $custom_limit_ip zone=perip:10m rate=2r/s;
    ...
    server {
        ...
        # By default, do not enforce the maximum allowed number of connections for the remote IP
        set $custom_remote_addr 127.0.0.1;

        # If the URI matches a super time consuming requests, limit to 2r/s.
        if ($uri ~* "^/super-long-requests") {
            set $custom_remote_addr $remote_addr;
        }
        limit_req zone=perip burst=50;
        ...
    }
 }

这对我想做的事没有帮助。问题是有些请求可能需要很短的时间来处理,有些可能需要很长的时间。在相同的时间内发出大量的短请求是可以的,而只有少量的长请求是可以接受的。因此,速率并不是限制用户资源的有效方法,问题并不在于请求速度慢。用户可能会发出许多简短的请求,但仍然会占用服务器的资源。更重要的是,我需要这种保护的原因是我不知道提前什么请求可能慢或快。这个想法是为了确保无论服务器的行为如何,一个用户都不能消耗所有的资源。如果您甚至不知道[1]哪些是慢请求和快请求,那么您可能必须采用一种通用的方法-设置来自IP地址的请求速率(由另一个用户提供)或设置防火墙#1-您没有日志吗?抱歉,ngx_http_limit_conn模块不会对连接进行排队-它将立即拒绝任何多余的连接尝试,错误代码由limit_conn_状态行设置。(通常是503)。我还没有找到解决这个问题的好方法,所以我们正在实现一个Nginx模块来满足我们的需要。