代码之家  ›  专栏  ›  技术社区  ›  Koerr

如何限制Java中的带宽?

  •  9
  • Koerr  · 技术社区  · 15 年前

    我编写了一个Java调度程序,每小时使用:

    new SAXBuilder().build(new URL(xxx));
    

    HttpConnection.connect(new URL(xxx)); // jsoup library code
    

    获取一个大的XML/HTML文件。

    我的服务器最大带宽限制为2位。

    当这个Java调度代码运行时,我使用超过2Mb1的带宽。( check it out )

    所以每次用户访问我的服务器时,速度都太慢了。

    如何限制我的Java调度使用较低的带宽? (约500千克)

    我正在使用Ubuntu服务器。

    4 回复  |  直到 8 年前
        1
  •  15
  •   Thiago Chaves    13 年前

    没有优雅的方式可以做到这一点。

    一个简单但不优雅的方法是编写一个Java流包装器,它限制从包裹流读取字节的速率。例如,如果要限制为每秒1000个字节,则 int read() 方法可以实现如下:

    Stream in;
    long timestamp = System.currentTimeInMillis();
    int counter = 0;
    int INTERVAL = 1000; // one second
    int LIMIT = 1000; // bytes per INTERVAL
    
    ...
    
    /**
     * Read one byte with rate limiting
     */
    @Override
    public int read() {
        if (counter > LIMIT) {
            long now = System.currentTimeInMillis();
            if (timestamp + INTERVAL >= now) {
                Thread.sleep(timestamp + INTERVAL - now);  
            }
            timestamp = now;
            counter = 0;
        }
        int res = in.read();
        if (res >= 0) {
            counter++;
        }
        return res;
    }
    

    值得注意的是,像这样的节流率既有负面影响,也有正面影响。消极方面:

    • 它将服务器端的资源绑定更长时间。在这种情况下,我们讨论的是处理下载的Java线程,内核空间中的内存用于缓冲接收的网络包,直到应用程序读取它们为止。

    • 也可能导致 更多 网络流量。问题是这种节流会破坏包的平滑流动。服务器只会缓冲相对较少的数据包,当超过这个数量时,它必须立即通知客户机停止。这需要额外的信号包(ACK),并且在这个过程中可能会有数据包丢失。最终,这些数据包将需要重新传输。

        2
  •  15
  •   Franck    9 年前

    理论:

    Token Bucket Algorithm 是限制下载带宽的一种方法。 你应该阅读 this article :它解释了该算法的使用。

    实施:

    来自Google Guava的Ratelimiter

    google guava 22.0包括 RateLimiter 但是它仍然是beta版本。

    来自API文档:

    例如,假设我们有一个要执行的任务列表,但我们不希望每秒提交超过2个:

    final RateLimiter rateLimiter = RateLimiter.create(2.0); // rate is "2 permits per second"
      void submitTasks(List<Runnable> tasks, Executor executor) {
        for (Runnable task : tasks) {
          rateLimiter.acquire(); // may wait
          executor.execute(task);
        }
      }
    

    另一个例子是,假设我们生成了一个数据流,我们希望将其限制为每秒5KB。这可以通过要求每字节一个许可证,并指定每秒5000个许可证的速率来实现:

    final RateLimiter rateLimiter = RateLimiter.create(5000.0); // rate = 5000 permits per second
      void submitPacket(byte[] packet) {
        rateLimiter.acquire(packet.length);
        networkService.send(packet);
      }
    

    来自Apache Commons Lang v3的TimedseMaphore

    Apache Commons Lang v3包括 TimedSemaphore 可用于实现速率限制的类。

        3
  •  3
  •   PbxMan    8 年前

    可能的解决方案是使用 代理服务器 这限制了带宽。如果需要完整的Java解决方案,可以使用简单的套接字Java代理服务器。 here 并使用thread.sleep或任何其他方式降低流进程的读/写速度。

        4
  •  0
  •   Jilles van Gurp    13 年前

    看看这个线程: http://httpcomponents.10934.n7.nabble.com/throttlling-download-traffic-td18329.html

    另外,如果您使用ApacheHTTPClient,您可以将其配置为使用gzip压缩并节省一些带宽。尤其是对于XML,这样传输的字节应该少得多。