java - 限时服务

标签 java web-services concurrency queue policy

我正在开发一个向 Musicbrainz 网络服务发出请求的应用程序。我在 musicbrainz 手册中读到每秒不要向网络服务发出超过一个请求,否则客户端 IP 将被阻止。

为了使此限制对服务客户端透明,您建议采用什么架构。

  • 我想调用一个方法(例如 getAlbuns),它应该仅在上次请求后 1 秒发出请求。
  • 我还想一次调用 10 个请求,并且服务应该处理排队,并在可用时返回结果(非阻塞)。

谢谢!

最佳答案

由于调用之间需要延迟,我建议 java.util.Timer java.util.concurrent.ScheduledThreadPoolExecutor Timer非常简单,并且完全适合这个用例。但如果稍后确定其他调度要求,则单个 Executor可以处理所有这些。无论哪种情况,都使用固定延迟方法,而不是固定速率方法。

重复任务polls请求对象的并发队列。如果有待处理的请求,任务将执行该请求,并通过回调返回结果。对服务的查询和要调用的回调是请求对象的成员。

应用程序保留对共享队列的引用。要安排请求,只需将其添加到队列中即可。

<小时/>

澄清一下,如果执行定时任务时队列为空,则不会发出请求。简单的方法就是结束任务,调度程序会在一秒后调用该任务再次检查。

但是,这意味着即使最近没有处理任何请求,启动任务也可能需要一秒钟的时间。如果这种不必要的延迟是无法忍受的,那么编写自己的线程可能比使用 Timer 更好。或ScheduledThreadPoolExecutor 。在您自己的计时循环中,如果您选择阻塞空队列直到有请求可用,您就可以更好地控制调度。内置计时器不保证在上一次执行完成后等待一整秒;他们通常根据任务的开始时间进行安排。

如果您想到的是第二种情况,您的run()方法将包含一个循环。每次迭代均以 blocking 开始在队列中,直到收到请求,然后记录时间。处理完请求后,再次检查时间。如果时间差小于一秒,sleep其余的。此设置假设一个请求开始与下一个请求开始之间需要一秒的延迟。如果一个请求结束与下一个请求之间需要延迟,则不需要检查时间;睡一秒钟就可以了。

还需要注意的是,该服务可能能够在单个请求中接受多个查询,这将减少开销。如果是这样,请通过阻止take()来利用这一点。对于第一个元素,然后使用 poll() ,可能需要很短的阻塞时间(5 毫秒左右),以查看应用程序是否发出更多请求。如果是这样,这些可以捆绑在对服务的单个请求中。如果queueBlockingQueue<? extends Request> ,它可能看起来像这样:

    Collection<Request> bundle = new ArrayList<Request>();
    bundle.add(queue.take());
    while (bundle.size() < BUNDLE_MAX) {
      Request req = queue.poll(EXTRA, TimeUnit.MILLISECONDS);
      if (req == null)
        break;
      bundle.add(req);
    }
    /* Now make one service request with contents of "bundle". */

关于java - 限时服务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/784214/

相关文章:

java - Play 框架中的简单 ajax post 调用

java - 带有 Logback 的 Spring Boot 应用程序不会作为 Systemd 服务登录到指定位置

c# - 枚举类型作为跨 Web 服务的常量?

java - JAX-WS Web 服务线程模型

python - 为什么在 concurrent.futures.Future 实例中没有引发 TimeoutError

java - 如何在java中将文件读入字符串?

java - JSF 日历选择整周

c# - 我如何为特定城市或国家设计伊斯兰祈祷时间小部件?

concurrency - Redis 出队时处于 'parking to wait' 状态的线程

haskell - 在 Haskell 中,如何在父进程和 fork 子进程之间共享数据?