16

比方说,我有 P 个进程在 N 个物理机器上运行一些业务逻辑。例如,这些进程调用一些 Web 服务 S。我想确保所有 P 进程相结合,每秒对服务 S 的调用不超过 X 次。

如何实施这样的解决方案?

Google Guava 的速率限制器适用于在单机上运行的进程,但不适用于分布式设置。

是否有任何可用于 JAVA 的标准、即用型解决方案?[可能基于zookeeper]

谢谢!

4

5 回答 5

8

Bucket4j是“token-bucket”速率限制算法的 java 实现。它适用于本地和分布式(在 JCache 之上)。对于分布式用例,您可以自由选择任何 JCache 实现,例如 Hazelcast 或 Apache Ignite。请参阅在集群中使用 Bucket4j 的示例

于 2017-04-28T21:31:14.963 回答
3

我一直在为这类问题开发一个开源解决方案。

Limited 是限制的“服务器”。这些限制是使用令牌桶算法实现的。

基本上,您在服务配置中定义限制,如下所示:

buckets:
  "request to service a":
     per_minute: 10
  "request to service b":
     per_minute: 5

该服务作为在 TCP/IP 端口上侦听的守护程序运行。

然后您的应用程序会执行以下操作:

var limitd = new Limitd('limitd://my-limitd-address');

limitd.take('request to service a', 'app1' 1, function (err, result) {
  if (result.conformant) {
    console.log('everything is okay - this should be allowed');
  } else {
    console.error('too many calls to this thing');
  }
});

我们目前正在使用它来限制某些应用程序事件的速率和去抖动。

服务器开启:

https://github.com/auth0/limitd

我们计划开发几个 SDK,但目前我们只有 node.js 并部分实现了 go:

https://github.com/limitd

于 2015-07-23T22:38:45.027 回答
0

因此,对于所有分布式速率限制架构,您将需要一个单一的后端存储来充当 true 的单一来源来跟踪请求的数量。为了方便起见,您始终可以将 zookeeper 用作内存数据存储,尽管有更好的选择,例如 Redis。

于 2021-12-28T00:16:03.880 回答
0

Java 中的简单速率限制,您希望每 3 秒实现 3 个事务的并发。如果你想集中它,那么要么将令牌数组存储在 elasticache 或任何数据库中。代替同步块,您还必须实现锁定标志。

import java.util.Date;

public class RateLimiter implements Runnable {

private long[] tokens = new long[3];

public static void main(String[] args) {
    // TODO Auto-generated method stub
    RateLimiter rateLimiter = new RateLimiter();
    for (int i=0; i<20; i++) {
        Thread thread = new Thread(rateLimiter,"Thread-"+i );
        thread.start();
    }
    
}

@Override
public void run() {
    // TODO Auto-generated method stub
    long currentStartTime = System.currentTimeMillis();
    while(true) {
    
    if(System.currentTimeMillis() - currentStartTime > 100000 ) {
        throw new RuntimeException("timed out");
    }else {
        if(getToken()) {
        System.out.println(Thread.currentThread().getName() + 
                " at " + 
                new Date(System.currentTimeMillis()) + " says hello");
        break;
        }
    }
    
    }
    
}

synchronized private boolean getToken() {
    // TODO Auto-generated method stub
    
    for (int i = 0; i< 3; i++) {
        if(tokens[i] == 0 || System.currentTimeMillis() - tokens[i] > 3000) {
            tokens[i] = System.currentTimeMillis();
            return true;
        }
    }
    
    return false;
}

}
于 2021-10-10T00:08:37.850 回答
0

https://github.com/jdwyah/ratelimit-java提供了应该做到这一点的分布式速率限制。您可以将您的限制配置为 S 每秒 / 分钟等,并选择掩护下的漏桶的突发大小 / 重新填充率。

于 2017-02-20T03:30:13.753 回答