Frage

Ich versuche, meine Anwendungsrate auf 900 kbit / s zu beschränken, aber das Problem ist, dass das von mir verwendete Protokoll meldungsorientiert ist und die Nachrichten sehr unterschiedliche Größen haben. Ich kann Nachrichten von 40 Bytes bis zu 125000 Bytes haben und alle Nachrichten werden als Atomeinheiten gesendet.

Ich habe versucht, einen Token -Bucket -Puffer zu implementieren, aber wenn ich eine niedrige Eimergröße festlegt, werden die großen Pakete nie gesendet und ein größerer Eimer führt zu einem großen Ausbruch ohne Rate -Begrenzung.

Dies ist meine kleine Implementierung in 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;
}

Dann irgendwo in 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);
}
War es hilfreich?

Lösung

Sie begrenzen Ihre maximale Nachrichtengröße durch max_burst (die zu Beginn der Kapazität von TBF-> zugewiesen wird)-da die TBF-> Token nie über diesen Wert hinausgehen, werden größere Nachrichten aufgrund dieser Prüfung niemals gesendet:

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

Der Code legt also tatsächlich eine harte Begrenzung für Burst auf max_burst fest - also sollten Sie Ihre Nachrichten fragmentieren, wenn Sie diese Burst -Größe wünschen.

Angenommen, dies ist der einzige Ort in dem Code, an dem Sie den Limiter einfügen können, erhalten Sie möglicherweise ein besseres Ergebnis, wenn Sie das obige Stück ersetzen durch:

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

Die Semantik wird etwas anders sein, aber im Durchschnitt über einen langen Zeitraum sollte es Ihnen ungefähr die gesuchte Rate bringen. Wenn Sie 125.000 in einer Nachricht über einen 1 -Gbit / s -Link senden, kann man natürlich kaum über 900 Kbit / s -Rate sprechen - es wird eine vollständige 1 -Gbit / s -Paketausbrüche sein und sie müssen irgendwo in die Warteschlange sein, falls es Links mit niedrigerer Geschwindigkeit gibt - daher daher - daher Seien Sie bereit, in diesem Fall einige der Pakete zu verlieren.

Abhängig von Ihrer Anwendung und dem von Ihnen verwendeten Transport -Netzwerkprotokoll (TCP/UDP/SCTP/...?) Möchten Sie den Formungscode möglicherweise den Stapel hinunter verschieben - da die Pakete im Netzwerk normalerweise nur maximal 1500 Bytes sind Wie auch immer (das beinhaltet verschiedene Netzwerke für Netzwerk-/Transportprotokoll)

Eine Sache, die für das Testen interessant sein könnte, ist http://www.linuxfoundation.org/en/net:netem - Wenn Ihr Ziel versucht, die Links mit kleinerer Kapazität zu bekämpfen. Oder schnappen Sie sich ein paar ältere Router mit 1Mbit / s seriellen Anschlüssen von Rücken an Rücken.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top