Pergunta

Estou tentando limitar minha taxa de envio de aplicativos a 900kbps, mas o problema é que o protocolo que eu uso é orientado para mensagens e as mensagens têm tamanhos muito diferentes. Eu posso ter mensagens de 40 bytes até 125000 bytes e todas as mensagens são enviadas como unidades atômicas.

Tentei a implementação de um buffer de balde de token, mas se eu definir um tamanho baixo, os pacotes grandes nunca recebem e um balde maior resultará em uma grande explosão, sem limitação de taxa.

Esta é minha pequena implementação em 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;
}

Então em algum lugar em 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);
}
Foi útil?

Solução

Você está limitando o tamanho máximo da mensagem por max_burst (que é atribuído a TBF-> Capacidade no início)-Como os tokens tbf-> nunca incrementos além desse valor, mensagens maiores nunca serão enviadas devido a esta verificação:

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

Portanto, o código realmente define um limite rígido para ser max_burst - então você deve fragmentar suas mensagens se quiser esse tamanho de explosão.

Supondo que este seja o único lugar no código em que você pode inserir o limitador, você pode obter um resultado melhor se substituir a peça acima por:

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

A semântica será um pouco diferente, mas, em média, por um longo período de tempo, deve obter aproximadamente a taxa que você está procurando. Obviamente, se você enviar 125k em uma mensagem em um link de 1 Gbps, dificilmente se poderá falar sobre a taxa de 900kbps - será uma explosão completa de 1 Gbps de pacotes, e eles precisarão ser na fila em algum lugar, caso haja links de menor velocidade - daí Esteja preparado para perder alguns pacotes nesse caso.

Mas, dependendo do seu aplicativo e do protocolo de rede de transporte que você está usando (TCP/UDP/SCTP/...?) Você pode querer mover o código de modelagem pela pilha - porque os pacotes na rede normalmente são apenas o máximo de 1500 bytes Enfim (isso inclui vários cabeçalhos de protocolo de rede/transporte)

Uma coisa que pode ser interessante para testar é http://www.linuxfoundation.org/en/net:netem - Se o seu objetivo estiver tentando lidar com os links de menor capacidade. Ou pegue alguns roteadores mais antigos com portas seriais de 1 Mbps conectadas de volta ao traseiro.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top