【问题标题】:Token Bucket or Leaking Bucket for messages用于消息的令牌桶或泄漏桶
【发布时间】:2010-11-11 20:00:27
【问题描述】:

我试图将我的应用程序发送速率限制为 900kbps,但问题是我使用的协议是面向消息的,并且消息的大小非常不同。我可以接收从 40 字节到 125000 字节的消息,并且所有消息都以原子单位发送。

我尝试实现一个令牌桶缓冲区,但如果我设置一个较小的桶大小,则大数据包永远不会发送,而较大的桶将导致大突发,根本没有速率限制。

这是我在 C 中的小实现:

typedef struct token_buffer {
  size_t capacity;
  size_t tokens;
  double rate;
  uint64_t timestamp;

} token_buffer;


static uint64_t time_now()
{
  struct timeval ts;
  gettimeofday(&ts, NULL);
  return (uint64_t)(ts.tv_sec * 1000 + ts.tv_usec/1000);
}

static int token_buffer_init(token_buffer *tbf, size_t max_burst, double rate)
{
  tbf->capacity = max_burst;
  tbf->tokens   = max_burst;
  tbf->rate = rate;
  tbf->timestamp = time_now();
}

static size_t token_buffer_consume(token_buffer *tbf, size_t bytes)
{
  // Update the tokens
  uint64_t now = time_now();
  size_t delta = (size_t)(tbf->rate * (now - tbf->timestamp));
  tbf->tokens = (tbf->capacity < tbf->tokens+delta)?tbf->capacity:tbf->tokens+delta;
  tbf->timestamp = now;

  fprintf(stdout, "TOKENS %d  bytes: %d\n", tbf->tokens, bytes);

  if(bytes <= tbf->tokens) {
    tbf->tokens -= bytes;
  } else {
    return -1;
  }

  return 0;
}

然后在 main() 的某个地方:

while(1) {
  len = read_msg(&msg, file);

  // Loop until we have enough tokens.
  // if len is larger than the bucket capacity the loop never ends.
  // if the capacity is too large then no rate limit occurs.
  while(token_buffer_consume(&tbf,msg, len) != 0) {}

  send_to_net(&msg, len);
}

【问题讨论】:

    标签: limit token rate bucket


    【解决方案1】:

    您通过 max_burst 限制了您的最大消息大小(它在开始时分配给 tbf->capacity) - 由于 tbf->tokens 永远不会超过该值,因此由于此检查,将永远不会发送更大的消息:

    if(bytes <= tbf->tokens) {
        tbf->tokens -= bytes;
      } else {
        return -1;
      }
    

    因此,代码确实将突发的硬限制设置为 max_burst - 因此,如果您想要这种突发大小,您应该对消息进行分段。

    假设这是代码中唯一可以插入限制器的地方,如果将上面的部分替换为:

    if(tbf->tokens > 0) {
      tbf->tokens -= bytes;
    } else {
      return -1;
    }
    

    语义会略有不同,但平均而言,在很长一段时间内,它应该会为您提供大约您正在寻找的速率。当然,如果您通过 1gbps 链路在一条消息中发送 125K,则几乎无法谈论 900kbps 速率 - 这将是完整的 1gbps 数据包突发,并且它们需要在某处排队以防有低速链路 - 因此准备好在这种情况下丢失一些数据包。

    但是,根据您的应用程序和您使用的传输网络协议(TCP/UDP/SCTP/...?),您可能希望将整形代码移到堆栈下方 - 因为网络上的数据包通常只无论如何最大 1500 字节(包括各种网络/传输协议标头)

    http://www.linuxfoundation.org/en/Net:Netem 是测试可能感兴趣的一件事 - 如果您的目标是尝试处理容量较小的链接。或者,拿几台背靠背连接的 1mbps 串行端口的旧路由器。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-05-20
      • 1970-01-01
      • 1970-01-01
      • 2014-05-04
      • 1970-01-01
      • 2020-11-22
      • 2018-06-10
      • 1970-01-01
      相关资源
      最近更新 更多