在 Java 中限制 Rest API

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/29927984/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 16:08:24  来源:igfitidea点击:

Throttling a Rest API in Java

javarestdropwizardthrottling

提问by hatellla

I wanted to add a way to throttle the number of requests coming on each API from a certain client. So, I wanted to basically limit the number of requests per API per client.

我想添加一种方法来限制来自某个客户端的每个 API 的请求数量。所以,我想基本上限制每个客户端每个 API 的请求数量。

I am using DropWizard as framework. Can somebody recommend the ways to achieve this? I need something that will work for Distributed system.

我使用 DropWizard 作为框架。有人可以推荐实现这一目标的方法吗?我需要一些适用于分布式系统的东西。

回答by npe

A simplistic approach would be to use a Filterand wrap it around all your API calls in web.xml. Assuming your clients send an API keys identifying them in a HTTP header, you could implement a filter like this:

一种简单的方法是使用过滤器并将其包装在web.xml.假设您的客户端在 HTTP 标头中发送标识它们的 API 密钥,您可以实现如下过滤器:

public class MyThrottlingFilter extends Filter {

    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {

        HttpServletRequest httpreq = (HttpServletRequest) req;
        String apiKey = httpreq.getHeader("API_KEY")

        if (invocationLimitNotReached(apiKey))
            chain.doFilter(req, res);
        else
            throw ...
    }
}

and then register it like this:

然后像这样注册它:

<filter>
    <filter-name>MyThrottlingFilter</filter-name>
    <filter-class>com.my.throttler.MyThrottlingFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>MyThrottlingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

Of course, identifying your clients may be more difficult than this, if you use some other authentication methods, but the general idea should be the same.

当然,如果您使用其他一些身份验证方法,识别您的客户可能比这更困难,但总体思路应该是相同的。

回答by Rafal G.

Do you want to have such logic enclosed in your application? Maybe some external Load Balancer would be a better choice?

你想在你的应用程序中包含这样的逻辑吗?也许一些外部负载均衡器会是更好的选择?

You could try out HAProxy and have entire throtlling logic outside of your application.

您可以尝试使用 HAProxy 并在应用程序之外拥有完整的节流逻辑。

A big advantage of such approach is the fact you would not have to rebuild and redeploy application whenever throtlling requirements change. Also, HAProxy will take much smaller amount of time to restart than a typical Java application.

这种方法的一大优点是,只要限制需求发生变化,您就不必重建和重新部署应用程序。此外,与典型的 Java 应用程序相比,HAProxy 重新启动所需的时间要少得多。

回答by Raúl

I think an interceptor like HandlerInterceptorwould solve the purpose.

我认为像HandlerInterceptor这样的拦截器可以解决这个问题。

回答by V a a m Y o b

If you absolutely must have it in Dropwizard, then I would do as npe suggests. The change that is needed is to share the "rate" via an external process, e.g. redis.

如果您绝对必须在 Dropwizard 中使用它,那么我会按照 npe 的建议进行操作。所需的更改是通过外部进程共享“速率”,例如 redis。

So in npe's example, invocationLimitNotReachedwould check a redis host to figure out what the current rate is (perhaps it stores a list of all current requests), and if adding the current request would go over that threshold.

因此,在 npe 的示例中,invocationLimitNotReached将检查 redis 主机以确定当前速率是多少(可能它存储了所有当前请求的列表),并且添加当前请求是否会超过该阈值。

If adding the current request wouldn't exceed the allowed rate, then you add the request to the list, and when the request is finished, you remove the request from the redis list. The redis list entries can have a TTL, so if a dropwizard instance that is servicing 20 requests suddenly disappears, after the TTL, they're removed from the list of "currently executing requests".

如果添加当前请求不会超过允许的速率,则将请求添加到列表中,当请求完成时,将请求从 redis 列表中删除。redis 列表条目可以有一个 TTL,因此如果服务 20 个请求的 dropwizard 实例突然消失,在 TTL 之后,它们将从“当前正在执行的请求”列表中删除。

回答by Kislay Verma

Building on the answer given by npe, you can "achieve distributed"-ness by storing the per user API hit counts in a central store like Redis which the invocationLimitNotReached(apiKey) method can then use to determine rate limit breaches.

基于 npe 给出的答案,您可以通过将每个用户的 API 命中计数存储在像 Redis 这样的中央存储中来“实现分布式”,然后 invocationLimitNotReached(apiKey) 方法可以使用它来确定违反速率限制的情况。

The hard part, of course, is to determine how to "expire" the hit counts falling outside your limiting window.

当然,困难的部分是确定如何“过期”落在限制窗口之外的命中计数。