2009-07-17 6 views
2

Ich versuche, meine Anwendung send Rate zu 900kbps zu begrenzen, aber das Problem ist, dass das Protokoll, das ich verwende, Nachrichtenorientiert 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 atomare Einheiten gesendet.Token Bucket oder Leaking Bucket für Nachrichten

Ich habe versucht, einen Token-Bucket-Puffer zu implementieren, aber wenn ich eine niedrige Bucket-Größe einstelle, werden die großen Pakete niemals gesendet und ein größerer Bucket führt zu einem großen Burst ohne jegliche Ratenbegrenzung.

Das 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); 
} 

Antwort

2

Sie Ihre maximale Nachrichtengröße von max_burst Begrenzung (die tbf- zugewiesen wird> Kapazität zu Beginn) - Da die tbf-> Tokens niemals über diesen Wert hinaus inkrementiert werden, werden aufgrund dieser Überprüfung niemals größere Nachrichten gesendet:

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

Also, der Code legt tatsächlich eine harte Grenze für Burst auf max_burst - also sollten Sie Ihre Nachrichten fragmentieren, wenn Sie diese Burst-Größe wollen.

Angenommen, dies ist der einzige Ort, in dem Code, wo Sie die Limiter einfügen können, könnten Sie ein besseres Ergebnis, wenn man das obige Stück ersetzen mit:

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

Die semantisch etwas anders sein wird, aber auf Im Durchschnitt über einen langen Zeitraum sollte es Ihnen ungefähr die Rate geben, die Sie suchen. Natürlich, wenn Sie 125K in einer Nachricht über eine 1gbps-Verbindung senden, kann man kaum über 900kbps Rate sprechen - es wird voller 1gbps Bündel von Paketen sein, und sie müssen irgendwo in Warteschlange gestellt werden, falls es Verbindungen mit niedrigerer Geschwindigkeit gibt bereit sein, in diesem Fall einige der Pakete zu verlieren.

Aber abhängig von Ihrer Anwendung und dem Transportnetzwerkprotokoll, das Sie verwenden (TCP/UDP/SCTP/...?), Möchten Sie den Shaping-Code möglicherweise den Stapel nach unten verschieben - weil Pakete im Netzwerk normalerweise sind nur maximal 1500 Bytes (das schließt verschiedene Netzwerk-/Transportprotokoll-Header ein)

Eine Sache, die für das Testen interessant sein könnte, ist http://www.linuxfoundation.org/en/Net:Netem - wenn Ihr Ziel versucht, die kleineren Kapazität anzugehen. Oder schnappen Sie sich ein paar ältere Router mit 1mbps seriellen Ports, die Rücken an Rücken verbunden sind.

Verwandte Themen